From 35584c2a494595c090530deb6bda0fdc7f50c3d5 Mon Sep 17 00:00:00 2001 From: tofulm Date: Thu, 30 Mar 2023 22:44:37 +0200 Subject: [PATCH 01/16] =?UTF-8?q?feat:=20on=20peut=20passer=20dans=20le=20?= =?UTF-8?q?param=20options=20:=20envoi=5Fsepare=20=3D>=20oui,=20cela=20ajo?= =?UTF-8?q?ute=20un=20radio=20(coch=C3=A9=20oui=20par=20defaut)=20pour=20j?= =?UTF-8?q?ouer=20l'envoi=20pour=20chaque=20destinataire=20du=20pour=20et?= =?UTF-8?q?=20non=20pas=201=20seul=20message=20pour=20tous=20les=20destina?= =?UTF-8?q?taires?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/gamumail.css | 49 ++++++++++++++++++++++--- formulaires/gamumail.html | 19 ++++++++++ formulaires/gamumail.php | 76 +++++++++++++++++++++++++++------------ 3 files changed, 116 insertions(+), 28 deletions(-) diff --git a/css/gamumail.css b/css/gamumail.css index 83b76dd..2d72a1d 100644 --- a/css/gamumail.css +++ b/css/gamumail.css @@ -20,14 +20,17 @@ overflow: hidden; margin: 3px 0; } + .tag-editor div { float: left; padding: 0 4px; } + .tag-editor .placeholder { padding: 0 8px; color: #bbb; } + .tag-editor .tag-editor-spacer { padding: 0; width: 8px; @@ -35,6 +38,7 @@ color: transparent; background: none; } + .tag-editor input { vertical-align: inherit; border: 0; @@ -50,15 +54,18 @@ background: none; color: #444; } + /* hide original input field or textarea visually to allow tab navigation */ .tag-editor-hidden-src { position: absolute !important; left: -99999px; } + /* hide IE10 "clear field" X */ .tag-editor ::-ms-clear { display: none; } + /* tag style */ .tag-editor .tag-editor-tag { /*padding-left: 5px; color: #46799b; background: #e0eaf1; white-space: nowrap;*/ @@ -71,6 +78,7 @@ cursor: pointer; border-radius: 4px 0 0 4px; } + /* delete icon */ /*.tag-editor .tag-editor-delete { background: #e0eaf1; cursor: pointer; border-radius: 0 2px 2px 0; padding-left: 3px; padding-right: 4px; }*/ .tag-editor .tag-editor-delete { @@ -80,10 +88,12 @@ padding-left: 3px; padding-right: 4px; } + .tag-editor .tag-editor-delete i { line-height: 18px; display: inline-block; } + /*.tag-editor .tag-editor-delete i:before { font-size: 16px; color: #8ba7ba; content: "×"; font-style: normal; }*/ .tag-editor .tag-editor-delete i:before { font-size: 16px; @@ -91,14 +101,17 @@ content: '×'; font-style: normal; } + .tag-editor .tag-editor-delete:hover i:before { color: #d65454; } -.tag-editor .tag-editor-tag.active + .tag-editor-delete, -.tag-editor .tag-editor-tag.active + .tag-editor-delete i { + +.tag-editor .tag-editor-tag.active+.tag-editor-delete, +.tag-editor .tag-editor-tag.active+.tag-editor-delete i { visibility: hidden; cursor: text; } + .tag-editor .tag-editor-tag.active { background: none !important; } @@ -111,9 +124,11 @@ cursor: default; font-size: 14px; } + .ui-front { z-index: 9999; } + .ui-menu { list-style: none; padding: 1px; @@ -121,21 +136,26 @@ display: block; outline: none; } + .ui-menu .ui-menu-item a { text-decoration: none; display: block; padding: 2px 0.4em; line-height: 1.4; - min-height: 0; /* support: IE7 */ + min-height: 0; + /* support: IE7 */ } + .ui-widget-content { border: 1px solid #bbb; background: #fff; color: #555; } + .ui-widget-content a { color: #46799b; } + .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, @@ -143,6 +163,7 @@ .ui-widget-header .ui-state-focus { background: #e0eaf1; } + .ui-helper-hidden-accessible { display: none; } @@ -151,47 +172,65 @@ .formulaire_gamumail { padding-top: 0; } + .formulaire_gamumail .editer { padding-top: 0; } + .editer_pour { display: flex; } + .editer_pour label { width: 50px; } + +.editer_envoi_separe { + display: flex; +} + .editer_cc { display: flex; } + .editer_cc label { width: 50px; } + .editer_cci { display: flex; } + .editer_cci label { width: 50px; } + .reponse_formulaire { padding: 1rem; margin-bottom: 2rem; font-weight: bold; } -.reponse_formulaire_erreur, .editer .erreur_message { + +.reponse_formulaire_erreur, +.editer .erreur_message { background-color: #f7d1d1; border: solid 2px #f00; display: block; } + .reponse_formulaire_ok { background-color: #c4ecd6; - border: solid 2px #080; + border: solid 2px #080; } + .remplacements_slugs { margin-top: 3rem; } + .formulaire_gamumail .boutons { margin-top: 3rem; } + .formulaire_gamumail .btn { font-size: 3rem; } diff --git a/formulaires/gamumail.html b/formulaires/gamumail.html index 5309bcd..d4262d7 100644 --- a/formulaires/gamumail.html +++ b/formulaires/gamumail.html @@ -29,6 +29,25 @@ + +
+ #SET{name,envoi_separe} + #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}} + #SET{obli,"obligatoire"} +
+ +
+ + +
+
+ + +
+
+
+ +
#SET{name,cc} diff --git a/formulaires/gamumail.php b/formulaires/gamumail.php index c000e19..84d9312 100644 --- a/formulaires/gamumail.php +++ b/formulaires/gamumail.php @@ -69,12 +69,10 @@ function formulaires_gamumail_charger_dist($slug, $destinataires = 0, $Tclient = $Tpdf = [$Tpdf]; } foreach ($Tpdf as $id => $pdf) { - //$TFichierPdf[] = $pdf['fichier']; $TFichierPdf[$id] = $pdf; - //$options[$id] = $pdf; } } -//var_dump($Tcc); + $gamuMail = sql_fetsel('sujet, texte, id_docs', 'spip_gamumails', 'slug='.sql_quote($slug)); $valeurs = array( "slug" => $slug, @@ -87,7 +85,8 @@ function formulaires_gamumail_charger_dist($slug, $destinataires = 0, $Tclient = 'Tpdfs_ok' => [], 'docs_spip' => $gamuMail['id_docs'] ?? '', 'Tid_fichiers' => [], - 'options' => $options + 'options' => $options, + 'envoi_separe' => $options['envoi_separe'] ?? '' ); // surcharges charger : d'abord les surcharges pour tous les slugs (tous_charge.php) puis les spécifiques par slug (nom_slug_charger.php) @@ -201,21 +200,12 @@ function formulaires_gamumail_traiter_dist($slug, $destinataires = 0, $Tclient = include_spip('inc/texte'); include_spip('classes/facteur'); - $retour = array(); + $retour = []; - $pour = _request('pour'); - $cc = _request('cc'); - $cci = _request('cci'); - $sujet = _request('sujet'); - $html = propre(_request('texte')); - $docs_spip = _request('docs_spip'); - $Tpdfs_ok = _request('Tpdfs_ok'); - $Tid_doc = _request('Tid_doc'); - $texte = facteur_mail_html2text($html); + $envoi_separe = _request('envoi_separe') ?? ''; + $pour = _request('pour'); $pour = explode(',', $pour); - $cc = explode(',', $cc); - $cci = explode(',', $cci); $destinataires = []; foreach ($pour as $dest) { @@ -223,12 +213,56 @@ function formulaires_gamumail_traiter_dist($slug, $destinataires = 0, $Tclient = if ($mail = sql_getfetsel('email', 'spip_auteurs', 'id_auteur='.$dest)) { $destinataires[] = $mail; } - } - elseif (email_valide($dest)) { + } elseif (email_valide($dest)) { $destinataires[] = $dest; } } + if (empty($envoi_separe)) { + gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, $retour); + } else { + $ok = true; + foreach ($destinataires as $d) { + $r = gamuSend($slug, $options, [$d], $Tclient, $Tpdf, $redirect); + if (!$r) { + $ok = false; + } + } + if (!$ok) { + $retour['message_erreur'] = _T("gamumail:erreur_envoi_mail"); + } + else { + $retour['message_ok'] = _T('gamumail:mail_envoye'); + + // dans le retour message_ok ajouter que le gamumail est OK + $retour['message_ok'] .= '@@gamumail_ok'; + } + } + + + if ($redirect AND $redirect != '') { + $retour['redirect'] = $redirect; + } + + return $retour; +} + + +function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, &$retour = []) { + + $cc = _request('cc'); + $cci = _request('cci'); + + $cc = explode(',', $cc); + $cci = explode(',', $cci); + + $sujet = _request('sujet'); + $html = propre(_request('texte')); + $docs_spip = _request('docs_spip'); + $Tpdfs_ok = _request('Tpdfs_ok'); + $Tid_doc = _request('Tid_doc'); + $texte = facteur_mail_html2text($html); + $pieces_jointes = []; if ($f = charger_fonction('traiter_av_pdf', 'gamumail', true)) { $options = $f($options, $destinataires, $Tclient, $Tpdf); @@ -399,9 +433,5 @@ function formulaires_gamumail_traiter_dist($slug, $destinataires = 0, $Tclient = } } - if ($redirect AND $redirect != '') { - $retour['redirect'] = $redirect; - } - - return $retour; + return $ok; } From 143faff6c4a06be152fd7bb6d2e5334c2c568779 Mon Sep 17 00:00:00 2001 From: tofulm Date: Fri, 31 Mar 2023 08:08:56 +0200 Subject: [PATCH 02/16] feat: ajout fichier traiter_pieces_jointes pour ajouter des pieces jointes avant l'envoi, utilie si on utilise envoi_separe --- formulaires/gamumail.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/formulaires/gamumail.php b/formulaires/gamumail.php index 84d9312..6be6c97 100644 --- a/formulaires/gamumail.php +++ b/formulaires/gamumail.php @@ -276,7 +276,7 @@ function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, & if (!empty($docs_spip)) { foreach ($docs_spip as $id_document) { $protected = ''; - $Tdocument = sql_fetsel('*','spip_documents','id_document='.intval($id_document)); + $Tdocument = sql_fetsel('*','spip_documents','id_document='.intval($id_document)); if ( array_key_exists('protected', $Tdocument) and $Tdocument['protected'] === 'oui' @@ -349,6 +349,20 @@ function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, & ]; } } + + if ($f = charger_fonction('traiter_pieces_jointes', 'gamumail', true)) { + $pc = $f($options, $destinataires, $Tclient, $Tpdf); + if (!empty($pc)) { + $pieces_jointes[] = $pc; + } + } + if ($f = charger_fonction($slug . '_traiter_pieces_jointes', 'gamumail', true)) { + $pc = $f($options, $destinataires, $Tclient, $Tpdf); + if (!empty($pc)) { + $pieces_jointes[] = $pc; + } + } + $html_header = ''; if (find_in_path('gamumail/'.$slug .'_html_header.html')) { $html_header = recuperer_fond('gamumail/'.$slug . '_html_header', $options); From 42ed572d43d77c826600f890dc6aa5d3cfc1121f Mon Sep 17 00:00:00 2001 From: tofulm Date: Tue, 4 Apr 2023 22:59:53 +0200 Subject: [PATCH 03/16] feat: ajout info corps + sujet dans le pipeline final --- formulaires/gamumail.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/formulaires/gamumail.php b/formulaires/gamumail.php index 6be6c97..dc4464f 100644 --- a/formulaires/gamumail.php +++ b/formulaires/gamumail.php @@ -401,6 +401,7 @@ function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, & 'pieces_jointes' => $pieces_jointes ]; + // surcharges de traiter : d'abord les surcharges pour tous les slugs (tous_traiter.php) puis les spécifiques par slug (nom_slug_traiter.php) if ($f = charger_fonction('traiter', 'gamumail', true)) { $corps = $f($corps, $options, $slug, $destinataires, $Tclient, $Tpdf, $redirect); @@ -417,7 +418,8 @@ function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, & ]); $sujet = $remplacement_generiques($args, $sujet); -//var_dump($corps);die; + $args['corps'] = $corps; + $args['sujet'] = $sujet; // envoyer ! $envoyer_mail = charger_fonction('envoyer_mail', 'inc/'); From 9c743d0e73688661d7b6a9159573451e2350594e Mon Sep 17 00:00:00 2001 From: tofulm Date: Tue, 4 Apr 2023 23:19:32 +0200 Subject: [PATCH 04/16] feat: appelle fonction traiter_pieces_jointes, en arg 1 = le slug --- formulaires/gamumail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/formulaires/gamumail.php b/formulaires/gamumail.php index dc4464f..e618059 100644 --- a/formulaires/gamumail.php +++ b/formulaires/gamumail.php @@ -351,7 +351,7 @@ function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, & } if ($f = charger_fonction('traiter_pieces_jointes', 'gamumail', true)) { - $pc = $f($options, $destinataires, $Tclient, $Tpdf); + $pc = $f($slug, $options, $destinataires, $Tclient, $Tpdf); if (!empty($pc)) { $pieces_jointes[] = $pc; } From 6c8ec91c956c30376bf28b55547f123450fdf9f3 Mon Sep 17 00:00:00 2001 From: tofulm Date: Tue, 4 Apr 2023 23:24:35 +0200 Subject: [PATCH 05/16] feat: ajout all_fichiers en plus de #SLUG_fichiers --- formulaires/gamumail.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/formulaires/gamumail.html b/formulaires/gamumail.html index d4262d7..24ca629 100644 --- a/formulaires/gamumail.html +++ b/formulaires/gamumail.html @@ -142,6 +142,14 @@
+ #SET{fichier,all_fichiers} + [(#CHEMIN{gamumail/#GET{fichier}.html}|oui) + #SET{erreurs,#ENV**{erreurs}|table_valeur{Tid_doc}} + [(#GET{erreurs})] +

<:gamumail:fichiers_annexes:>

+ + ] + #SET{fichier,#SLUG|concat{_fichiers}} [(#CHEMIN{gamumail/#GET{fichier}.html}|oui) #SET{erreurs,#ENV**{erreurs}|table_valeur{Tid_doc}} From ef9ab757848f2a0eea23dc1167d1fbbfbe0d5bdb Mon Sep 17 00:00:00 2001 From: tofulm Date: Tue, 4 Apr 2023 23:25:26 +0200 Subject: [PATCH 06/16] feat: on supprime le h2 fichier annexe, car pas de pb de compat --- formulaires/gamumail.html | 1 - 1 file changed, 1 deletion(-) diff --git a/formulaires/gamumail.html b/formulaires/gamumail.html index 24ca629..5bed229 100644 --- a/formulaires/gamumail.html +++ b/formulaires/gamumail.html @@ -146,7 +146,6 @@ [(#CHEMIN{gamumail/#GET{fichier}.html}|oui) #SET{erreurs,#ENV**{erreurs}|table_valeur{Tid_doc}} [(#GET{erreurs})] -

<:gamumail:fichiers_annexes:>

] From 17edcf7841f9c28a311be8e08e3429e01844019e Mon Sep 17 00:00:00 2001 From: tofulm Date: Thu, 6 Apr 2023 14:16:04 +0200 Subject: [PATCH 07/16] feat: compat spip 41 creation auteur --- gamumail_administrations.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gamumail_administrations.php b/gamumail_administrations.php index 3adb9b0..1a0c901 100644 --- a/gamumail_administrations.php +++ b/gamumail_administrations.php @@ -37,7 +37,7 @@ function gamumail_upgrade($nom_meta_base_version, $version_cible) { $maj['1.0.12'] = array(array('creer_compte_curl')); $maj['1.0.14'] = array(array('maj_tables', array('spip_gamumails'))); $maj['1.0.15'] = array(array('maj_tables', array('spip_gamumails'))); - + include_spip('base/upgrade'); maj_plugin($nom_meta_base_version, $version_cible, $maj); @@ -55,7 +55,9 @@ function creer_compte_curl(){ 'statut' => '1comite' ]; - $id_auteur = sql_insertq('spip_auteurs', $set); + include_spip('action/editer_auteur'); + $id_auteur = auteur_inserer(null, $set); + if ($id_auteur) { include_spip('inc/config'); ecrire_config('curl_login', $set['login']); From 88d4d9a32ee491c257478053aa6e0dd72a8bb3e6 Mon Sep 17 00:00:00 2001 From: tofulm Date: Thu, 6 Apr 2023 14:24:56 +0200 Subject: [PATCH 08/16] refactoring: utilise generer_url_public pour l'url du pdf --- inc/charger_pdf.php | 20 +++++--------------- paquet.xml | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/inc/charger_pdf.php b/inc/charger_pdf.php index 8a67873..ec1d35c 100644 --- a/inc/charger_pdf.php +++ b/inc/charger_pdf.php @@ -7,19 +7,9 @@ function inc_charger_pdf_dist($fichier_pdf, $contexte = []){ $login = lire_config('curl_login'); $password = lire_config('curl_mdp'); - $url = $GLOBALS['meta']['adresse_site'].'/spip.php?page=spipdf&spipdf='.$fichier_pdf; - if (is_array($contexte) and count($contexte)) { - foreach ($contexte as $champ => $val) { -/* if (intval($val) === $val) { - // if (intval($val)) { - $val = intval($val); - } else { - $val = "$val"; - } -*/ - $url .= "&$champ=$val"; - } - } + + $contexte['spipdf'] = $contexte['spipdf'] ?? $fichier_pdf ; + $url = generer_url_public('spipdf', $contexte, true, false); $CurlConnect = curl_init(); // pour une connexion https locale avec certificat auto-signé @@ -34,8 +24,8 @@ function inc_charger_pdf_dist($fichier_pdf, $contexte = []){ $retour = curl_exec($CurlConnect); if( ! $retour = curl_exec($CurlConnect)) { trigger_error(curl_error($CurlConnect)); - } + } curl_close($CurlConnect); - + return $retour; } diff --git a/paquet.xml b/paquet.xml index 9f7e3fd..b3c67e9 100644 --- a/paquet.xml +++ b/paquet.xml @@ -1,7 +1,7 @@ Date: Tue, 18 Apr 2023 14:28:03 +0200 Subject: [PATCH 09/16] feat: rend compatible spip_gamumails avec api objet_modifier --- base/gamumail.php | 13 +++++++------ gamumail_administrations.php | 2 +- paquet.xml | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/base/gamumail.php b/base/gamumail.php index bb89929..4a3016c 100644 --- a/base/gamumail.php +++ b/base/gamumail.php @@ -56,17 +56,18 @@ function gamumail_declarer_tables_objets_sql($tables) { 'statut' => 'varchar(20) DEFAULT "0" NOT NULL', 'public' => 'varchar(20) DEFAULT "oui" NOT NULL', 'editable' => 'varchar(5) DEFAULT "oui" NOT NULL', + 'date' => 'datetime NOT NULL DEFAULT "0000-00-00 00:00:00"', 'maj' => 'TIMESTAMP', - 'rang' => 'smallint(6) NOT NULL' + 'rang' => 'smallint(6) NOT NULL' ), 'key' => array( - 'PRIMARY KEY' => 'id_gamumail', - 'KEY statut' => 'statut', + 'PRIMARY KEY' => 'id_gamumail', + 'KEY statut' => 'statut', ), - 'titre' => 'slug AS titre, "" AS lang', + // 'titre' => 'slug AS titre, "" AS lang', #'date' => '', - 'champs_editables' => array('slug', 'sujet', 'texte','titre', 'editable'), - 'champs_versionnes' => array('slug', 'sujet', 'texte','titre', 'editable'), + 'champs_editables' => array('slug', 'sujet', 'texte','titre', 'editable', 'public', 'id_docs', 'rang', 'statut', 'date'), + 'champs_versionnes' => array('slug', 'sujet', 'texte','titre', 'editable', 'public', 'id_docs', 'rang', 'statut', 'date'), 'rechercher_champs' => array("slug" => 8), 'tables_jointures' => array(), 'statut'=> array( diff --git a/gamumail_administrations.php b/gamumail_administrations.php index 1a0c901..0bcc4ad 100644 --- a/gamumail_administrations.php +++ b/gamumail_administrations.php @@ -36,7 +36,7 @@ function gamumail_upgrade($nom_meta_base_version, $version_cible) { $maj['1.0.11'] = array( array('maj_tables', array('spip_gamumails'))); $maj['1.0.12'] = array(array('creer_compte_curl')); $maj['1.0.14'] = array(array('maj_tables', array('spip_gamumails'))); - $maj['1.0.15'] = array(array('maj_tables', array('spip_gamumails'))); + $maj['1.0.16'] = array(array('maj_tables', array('spip_gamumails'))); include_spip('base/upgrade'); diff --git a/paquet.xml b/paquet.xml index b3c67e9..d764349 100644 --- a/paquet.xml +++ b/paquet.xml @@ -1,12 +1,12 @@ GamuMail From 752a00ff4c3ca92c8e25b2cecaf10f742ad675f3 Mon Sep 17 00:00:00 2001 From: tofulm Date: Sat, 22 Apr 2023 16:59:53 +0200 Subject: [PATCH 10/16] feat: * le remplacement de @@nom@@ renvoi que la valeur du champ nom ou un espace pour supprimer @@nom@@ * le remplacement de @@prenom@@ renvoi que la valeur du champ prenom ou un espace pour supprimer @@prenom@@ --- inc/gamumail_remplacements.php | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/inc/gamumail_remplacements.php b/inc/gamumail_remplacements.php index 220f06c..f587e56 100644 --- a/inc/gamumail_remplacements.php +++ b/inc/gamumail_remplacements.php @@ -14,22 +14,21 @@ if (!defined('_ECRIRE_INC_VERSION')) { **/ function inc_gamumail_remplacements_dist($args, $html) { /** - * @@nom@@ => Prenom Nom | Nom (gère la présence/absence du champ prenom dans spip_auteurs) + * @@nom@@ => $nom ou un espace pour vider le champ @@nom@@ **/ - $nom = sql_getfetsel('nom', 'spip_auteurs', 'email='.sql_quote($args['destinataires'][0])); - $prenom = $nom; + $nom = sql_getfetsel('nom', 'spip_auteurs', 'email='.sql_quote($args['destinataires'][0])) ?? ' '; + $html = gamumail_remplacer_modele('nom', ucwords($nom), $html); + + /** + * @@prenom@@ => $prenom ou un espace pour vider le champ @@prenom@@ + **/ + $prenom = ' '; $trouver_table = charger_fonction('trouver_table', 'base'); $desc = $trouver_table('spip_auteurs'); - if (array_key_exists('prenom', $desc['field']) - and $prenom = sql_getfetsel('prenom', 'spip_auteurs', 'email='.sql_quote($args['destinataires'][0]))) { - $nom = $prenom.' '.$nom; - } - if ($nom) { - $html = gamumail_remplacer_modele('nom', ucwords($nom), $html); - } - if ($prenom) { - $html = gamumail_remplacer_modele('prenom', ucwords($prenom), $html); + if (array_key_exists('prenom', $desc['field'])) { + $prenom = sql_getfetsel('prenom', 'spip_auteurs', 'email='.sql_quote($args['destinataires'][0])) ?? ' '; } + $html = gamumail_remplacer_modele('prenom', ucwords($prenom), $html); /** * @@url_site@@ => URL du site From ecf2571f0609c6a5da09caece2696a158a26c6db Mon Sep 17 00:00:00 2001 From: tofulm Date: Sat, 22 Apr 2023 17:01:41 +0200 Subject: [PATCH 11/16] up de y, car on casse la compat sur le remplacement automatique de @@nom@@ et @@prenom@@ --- paquet.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paquet.xml b/paquet.xml index d764349..a519910 100644 --- a/paquet.xml +++ b/paquet.xml @@ -1,7 +1,7 @@ Date: Sat, 22 Apr 2023 17:42:18 +0200 Subject: [PATCH 12/16] =?UTF-8?q?feat:=20si=20on=20clique=20sur=20une=20ba?= =?UTF-8?q?lise,=20elle=20est=20copi=C3=A9e=20dans=20le=20presse=20papier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamumail/remplacements_slugs.html | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gamumail/remplacements_slugs.html b/gamumail/remplacements_slugs.html index b708955..b30f0d0 100644 --- a/gamumail/remplacements_slugs.html +++ b/gamumail/remplacements_slugs.html @@ -1,6 +1,6 @@ [(#REM) la liste des remplacements joués dans tous les slugs GamuMail - + tous ceux des plugins qui les documentent via $GLOBALS'remplacements_gamumail' + + tous ceux des plugins qui les documentent via $GLOBALS'remplacements_gamumail' inclure pour la page de configuration des gamumails @@ -9,8 +9,11 @@

<:gamumail:remplacements_disponibles:>

    -
  • [(#CLE)] : [(#VALEUR)]
  • +
  • [(#CLE)] : [(#VALEUR)]
<:gamumail:avertissement_remplacements:> + + + From 9678584fc3c6361501e20250d68c03bc50033b4f Mon Sep 17 00:00:00 2001 From: tofulm Date: Sat, 22 Apr 2023 17:50:43 +0200 Subject: [PATCH 13/16] avec les fichiers c'est mieux --- js/clipboard.js | 890 ++++++++++++++++++++++++++++++++++++++++++++ js/clipboard.min.js | 7 + js/toClip.js | 12 + 3 files changed, 909 insertions(+) create mode 100644 js/clipboard.js create mode 100644 js/clipboard.min.js create mode 100644 js/toClip.js diff --git a/js/clipboard.js b/js/clipboard.js new file mode 100644 index 0000000..aeb826f --- /dev/null +++ b/js/clipboard.js @@ -0,0 +1,890 @@ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["ClipboardJS"] = factory(); + else + root["ClipboardJS"] = factory(); +})(this, function() { +return /******/ (function() { // webpackBootstrap +/******/ var __webpack_modules__ = ({ + +/***/ 686: +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +"use strict"; + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + "default": function() { return /* binding */ clipboard; } +}); + +// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js +var tiny_emitter = __webpack_require__(279); +var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter); +// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js +var listen = __webpack_require__(370); +var listen_default = /*#__PURE__*/__webpack_require__.n(listen); +// EXTERNAL MODULE: ./node_modules/select/src/select.js +var src_select = __webpack_require__(817); +var select_default = /*#__PURE__*/__webpack_require__.n(src_select); +;// CONCATENATED MODULE: ./src/common/command.js +/** + * Executes a given operation type. + * @param {String} type + * @return {Boolean} + */ +function command(type) { + try { + return document.execCommand(type); + } catch (err) { + return false; + } +} +;// CONCATENATED MODULE: ./src/actions/cut.js + + +/** + * Cut action wrapper. + * @param {String|HTMLElement} target + * @return {String} + */ + +var ClipboardActionCut = function ClipboardActionCut(target) { + var selectedText = select_default()(target); + command('cut'); + return selectedText; +}; + +/* harmony default export */ var actions_cut = (ClipboardActionCut); +;// CONCATENATED MODULE: ./src/common/create-fake-element.js +/** + * Creates a fake textarea element with a value. + * @param {String} value + * @return {HTMLElement} + */ +function createFakeElement(value) { + var isRTL = document.documentElement.getAttribute('dir') === 'rtl'; + var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS + + fakeElement.style.fontSize = '12pt'; // Reset box model + + fakeElement.style.border = '0'; + fakeElement.style.padding = '0'; + fakeElement.style.margin = '0'; // Move element out of screen horizontally + + fakeElement.style.position = 'absolute'; + fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically + + var yPosition = window.pageYOffset || document.documentElement.scrollTop; + fakeElement.style.top = "".concat(yPosition, "px"); + fakeElement.setAttribute('readonly', ''); + fakeElement.value = value; + return fakeElement; +} +;// CONCATENATED MODULE: ./src/actions/copy.js + + + +/** + * Create fake copy action wrapper using a fake element. + * @param {String} target + * @param {Object} options + * @return {String} + */ + +var fakeCopyAction = function fakeCopyAction(value, options) { + var fakeElement = createFakeElement(value); + options.container.appendChild(fakeElement); + var selectedText = select_default()(fakeElement); + command('copy'); + fakeElement.remove(); + return selectedText; +}; +/** + * Copy action wrapper. + * @param {String|HTMLElement} target + * @param {Object} options + * @return {String} + */ + + +var ClipboardActionCopy = function ClipboardActionCopy(target) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + container: document.body + }; + var selectedText = ''; + + if (typeof target === 'string') { + selectedText = fakeCopyAction(target, options); + } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) { + // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange + selectedText = fakeCopyAction(target.value, options); + } else { + selectedText = select_default()(target); + command('copy'); + } + + return selectedText; +}; + +/* harmony default export */ var actions_copy = (ClipboardActionCopy); +;// CONCATENATED MODULE: ./src/actions/default.js +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + + + +/** + * Inner function which performs selection from either `text` or `target` + * properties and then executes copy or cut operations. + * @param {Object} options + */ + +var ClipboardActionDefault = function ClipboardActionDefault() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + // Defines base properties passed from constructor. + var _options$action = options.action, + action = _options$action === void 0 ? 'copy' : _options$action, + container = options.container, + target = options.target, + text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'. + + if (action !== 'copy' && action !== 'cut') { + throw new Error('Invalid "action" value, use either "copy" or "cut"'); + } // Sets the `target` property using an element that will be have its content copied. + + + if (target !== undefined) { + if (target && _typeof(target) === 'object' && target.nodeType === 1) { + if (action === 'copy' && target.hasAttribute('disabled')) { + throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); + } + + if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { + throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); + } + } else { + throw new Error('Invalid "target" value, use a valid Element'); + } + } // Define selection strategy based on `text` property. + + + if (text) { + return actions_copy(text, { + container: container + }); + } // Defines which selection strategy based on `target` property. + + + if (target) { + return action === 'cut' ? actions_cut(target) : actions_copy(target, { + container: container + }); + } +}; + +/* harmony default export */ var actions_default = (ClipboardActionDefault); +;// CONCATENATED MODULE: ./src/clipboard.js +function clipboard_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return clipboard_typeof(obj); } + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } + +function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } + +function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } + +function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } + +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } + +function _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } + +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } + +function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } + + + + + + +/** + * Helper function to retrieve attribute value. + * @param {String} suffix + * @param {Element} element + */ + +function getAttributeValue(suffix, element) { + var attribute = "data-clipboard-".concat(suffix); + + if (!element.hasAttribute(attribute)) { + return; + } + + return element.getAttribute(attribute); +} +/** + * Base class which takes one or more elements, adds event listeners to them, + * and instantiates a new `ClipboardAction` on each click. + */ + + +var Clipboard = /*#__PURE__*/function (_Emitter) { + _inherits(Clipboard, _Emitter); + + var _super = _createSuper(Clipboard); + + /** + * @param {String|HTMLElement|HTMLCollection|NodeList} trigger + * @param {Object} options + */ + function Clipboard(trigger, options) { + var _this; + + _classCallCheck(this, Clipboard); + + _this = _super.call(this); + + _this.resolveOptions(options); + + _this.listenClick(trigger); + + return _this; + } + /** + * Defines if attributes would be resolved using internal setter functions + * or custom functions that were passed in the constructor. + * @param {Object} options + */ + + + _createClass(Clipboard, [{ + key: "resolveOptions", + value: function resolveOptions() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + this.action = typeof options.action === 'function' ? options.action : this.defaultAction; + this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; + this.text = typeof options.text === 'function' ? options.text : this.defaultText; + this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body; + } + /** + * Adds a click event listener to the passed trigger. + * @param {String|HTMLElement|HTMLCollection|NodeList} trigger + */ + + }, { + key: "listenClick", + value: function listenClick(trigger) { + var _this2 = this; + + this.listener = listen_default()(trigger, 'click', function (e) { + return _this2.onClick(e); + }); + } + /** + * Defines a new `ClipboardAction` on each click event. + * @param {Event} e + */ + + }, { + key: "onClick", + value: function onClick(e) { + var trigger = e.delegateTarget || e.currentTarget; + var action = this.action(trigger) || 'copy'; + var text = actions_default({ + action: action, + container: this.container, + target: this.target(trigger), + text: this.text(trigger) + }); // Fires an event based on the copy operation result. + + this.emit(text ? 'success' : 'error', { + action: action, + text: text, + trigger: trigger, + clearSelection: function clearSelection() { + if (trigger) { + trigger.focus(); + } + + window.getSelection().removeAllRanges(); + } + }); + } + /** + * Default `action` lookup function. + * @param {Element} trigger + */ + + }, { + key: "defaultAction", + value: function defaultAction(trigger) { + return getAttributeValue('action', trigger); + } + /** + * Default `target` lookup function. + * @param {Element} trigger + */ + + }, { + key: "defaultTarget", + value: function defaultTarget(trigger) { + var selector = getAttributeValue('target', trigger); + + if (selector) { + return document.querySelector(selector); + } + } + /** + * Allow fire programmatically a copy action + * @param {String|HTMLElement} target + * @param {Object} options + * @returns Text copied. + */ + + }, { + key: "defaultText", + + /** + * Default `text` lookup function. + * @param {Element} trigger + */ + value: function defaultText(trigger) { + return getAttributeValue('text', trigger); + } + /** + * Destroy lifecycle. + */ + + }, { + key: "destroy", + value: function destroy() { + this.listener.destroy(); + } + }], [{ + key: "copy", + value: function copy(target) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + container: document.body + }; + return actions_copy(target, options); + } + /** + * Allow fire programmatically a cut action + * @param {String|HTMLElement} target + * @returns Text cutted. + */ + + }, { + key: "cut", + value: function cut(target) { + return actions_cut(target); + } + /** + * Returns the support of the given action, or all actions if no action is + * given. + * @param {String} [action] + */ + + }, { + key: "isSupported", + value: function isSupported() { + var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; + var actions = typeof action === 'string' ? [action] : action; + var support = !!document.queryCommandSupported; + actions.forEach(function (action) { + support = support && !!document.queryCommandSupported(action); + }); + return support; + } + }]); + + return Clipboard; +}((tiny_emitter_default())); + +/* harmony default export */ var clipboard = (Clipboard); + +/***/ }), + +/***/ 828: +/***/ (function(module) { + +var DOCUMENT_NODE_TYPE = 9; + +/** + * A polyfill for Element.matches() + */ +if (typeof Element !== 'undefined' && !Element.prototype.matches) { + var proto = Element.prototype; + + proto.matches = proto.matchesSelector || + proto.mozMatchesSelector || + proto.msMatchesSelector || + proto.oMatchesSelector || + proto.webkitMatchesSelector; +} + +/** + * Finds the closest parent that matches a selector. + * + * @param {Element} element + * @param {String} selector + * @return {Function} + */ +function closest (element, selector) { + while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { + if (typeof element.matches === 'function' && + element.matches(selector)) { + return element; + } + element = element.parentNode; + } +} + +module.exports = closest; + + +/***/ }), + +/***/ 438: +/***/ (function(module, __unused_webpack_exports, __webpack_require__) { + +var closest = __webpack_require__(828); + +/** + * Delegates event to a selector. + * + * @param {Element} element + * @param {String} selector + * @param {String} type + * @param {Function} callback + * @param {Boolean} useCapture + * @return {Object} + */ +function _delegate(element, selector, type, callback, useCapture) { + var listenerFn = listener.apply(this, arguments); + + element.addEventListener(type, listenerFn, useCapture); + + return { + destroy: function() { + element.removeEventListener(type, listenerFn, useCapture); + } + } +} + +/** + * Delegates event to a selector. + * + * @param {Element|String|Array} [elements] + * @param {String} selector + * @param {String} type + * @param {Function} callback + * @param {Boolean} useCapture + * @return {Object} + */ +function delegate(elements, selector, type, callback, useCapture) { + // Handle the regular Element usage + if (typeof elements.addEventListener === 'function') { + return _delegate.apply(null, arguments); + } + + // Handle Element-less usage, it defaults to global delegation + if (typeof type === 'function') { + // Use `document` as the first parameter, then apply arguments + // This is a short way to .unshift `arguments` without running into deoptimizations + return _delegate.bind(null, document).apply(null, arguments); + } + + // Handle Selector-based usage + if (typeof elements === 'string') { + elements = document.querySelectorAll(elements); + } + + // Handle Array-like based usage + return Array.prototype.map.call(elements, function (element) { + return _delegate(element, selector, type, callback, useCapture); + }); +} + +/** + * Finds closest match and invokes callback. + * + * @param {Element} element + * @param {String} selector + * @param {String} type + * @param {Function} callback + * @return {Function} + */ +function listener(element, selector, type, callback) { + return function(e) { + e.delegateTarget = closest(e.target, selector); + + if (e.delegateTarget) { + callback.call(element, e); + } + } +} + +module.exports = delegate; + + +/***/ }), + +/***/ 879: +/***/ (function(__unused_webpack_module, exports) { + +/** + * Check if argument is a HTML element. + * + * @param {Object} value + * @return {Boolean} + */ +exports.node = function(value) { + return value !== undefined + && value instanceof HTMLElement + && value.nodeType === 1; +}; + +/** + * Check if argument is a list of HTML elements. + * + * @param {Object} value + * @return {Boolean} + */ +exports.nodeList = function(value) { + var type = Object.prototype.toString.call(value); + + return value !== undefined + && (type === '[object NodeList]' || type === '[object HTMLCollection]') + && ('length' in value) + && (value.length === 0 || exports.node(value[0])); +}; + +/** + * Check if argument is a string. + * + * @param {Object} value + * @return {Boolean} + */ +exports.string = function(value) { + return typeof value === 'string' + || value instanceof String; +}; + +/** + * Check if argument is a function. + * + * @param {Object} value + * @return {Boolean} + */ +exports.fn = function(value) { + var type = Object.prototype.toString.call(value); + + return type === '[object Function]'; +}; + + +/***/ }), + +/***/ 370: +/***/ (function(module, __unused_webpack_exports, __webpack_require__) { + +var is = __webpack_require__(879); +var delegate = __webpack_require__(438); + +/** + * Validates all params and calls the right + * listener function based on its target type. + * + * @param {String|HTMLElement|HTMLCollection|NodeList} target + * @param {String} type + * @param {Function} callback + * @return {Object} + */ +function listen(target, type, callback) { + if (!target && !type && !callback) { + throw new Error('Missing required arguments'); + } + + if (!is.string(type)) { + throw new TypeError('Second argument must be a String'); + } + + if (!is.fn(callback)) { + throw new TypeError('Third argument must be a Function'); + } + + if (is.node(target)) { + return listenNode(target, type, callback); + } + else if (is.nodeList(target)) { + return listenNodeList(target, type, callback); + } + else if (is.string(target)) { + return listenSelector(target, type, callback); + } + else { + throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); + } +} + +/** + * Adds an event listener to a HTML element + * and returns a remove listener function. + * + * @param {HTMLElement} node + * @param {String} type + * @param {Function} callback + * @return {Object} + */ +function listenNode(node, type, callback) { + node.addEventListener(type, callback); + + return { + destroy: function() { + node.removeEventListener(type, callback); + } + } +} + +/** + * Add an event listener to a list of HTML elements + * and returns a remove listener function. + * + * @param {NodeList|HTMLCollection} nodeList + * @param {String} type + * @param {Function} callback + * @return {Object} + */ +function listenNodeList(nodeList, type, callback) { + Array.prototype.forEach.call(nodeList, function(node) { + node.addEventListener(type, callback); + }); + + return { + destroy: function() { + Array.prototype.forEach.call(nodeList, function(node) { + node.removeEventListener(type, callback); + }); + } + } +} + +/** + * Add an event listener to a selector + * and returns a remove listener function. + * + * @param {String} selector + * @param {String} type + * @param {Function} callback + * @return {Object} + */ +function listenSelector(selector, type, callback) { + return delegate(document.body, selector, type, callback); +} + +module.exports = listen; + + +/***/ }), + +/***/ 817: +/***/ (function(module) { + +function select(element) { + var selectedText; + + if (element.nodeName === 'SELECT') { + element.focus(); + + selectedText = element.value; + } + else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { + var isReadOnly = element.hasAttribute('readonly'); + + if (!isReadOnly) { + element.setAttribute('readonly', ''); + } + + element.select(); + element.setSelectionRange(0, element.value.length); + + if (!isReadOnly) { + element.removeAttribute('readonly'); + } + + selectedText = element.value; + } + else { + if (element.hasAttribute('contenteditable')) { + element.focus(); + } + + var selection = window.getSelection(); + var range = document.createRange(); + + range.selectNodeContents(element); + selection.removeAllRanges(); + selection.addRange(range); + + selectedText = selection.toString(); + } + + return selectedText; +} + +module.exports = select; + + +/***/ }), + +/***/ 279: +/***/ (function(module) { + +function E () { + // Keep this empty so it's easier to inherit from + // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) +} + +E.prototype = { + on: function (name, callback, ctx) { + var e = this.e || (this.e = {}); + + (e[name] || (e[name] = [])).push({ + fn: callback, + ctx: ctx + }); + + return this; + }, + + once: function (name, callback, ctx) { + var self = this; + function listener () { + self.off(name, listener); + callback.apply(ctx, arguments); + }; + + listener._ = callback + return this.on(name, listener, ctx); + }, + + emit: function (name) { + var data = [].slice.call(arguments, 1); + var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); + var i = 0; + var len = evtArr.length; + + for (i; i < len; i++) { + evtArr[i].fn.apply(evtArr[i].ctx, data); + } + + return this; + }, + + off: function (name, callback) { + var e = this.e || (this.e = {}); + var evts = e[name]; + var liveEvents = []; + + if (evts && callback) { + for (var i = 0, len = evts.length; i < len; i++) { + if (evts[i].fn !== callback && evts[i].fn._ !== callback) + liveEvents.push(evts[i]); + } + } + + // Remove event from queue to prevent memory leak + // Suggested by https://github.com/lazd + // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 + + (liveEvents.length) + ? e[name] = liveEvents + : delete e[name]; + + return this; + } +}; + +module.exports = E; +module.exports.TinyEmitter = E; + + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ if(__webpack_module_cache__[moduleId]) { +/******/ return __webpack_module_cache__[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ !function() { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function() { return module['default']; } : +/******/ function() { return module; }; +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ }(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ !function() { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = function(exports, definition) { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ }(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ !function() { +/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } +/******/ }(); +/******/ +/************************************************************************/ +/******/ // module exports must be returned from runtime so entry inlining is disabled +/******/ // startup +/******/ // Load entry module and return exports +/******/ return __webpack_require__(686); +/******/ })() +.default; +}); \ No newline at end of file diff --git a/js/clipboard.min.js b/js/clipboard.min.js new file mode 100644 index 0000000..1103f81 --- /dev/null +++ b/js/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1✔ copié`; + $(e.trigger).append(html); + setTimeout(() => { + $(e.trigger).children('.copierOk').remove(); + e.clearSelection(); + }, 1000); + }); +}); + From ecdc5d1134e6d21e1231fae7e039fe82b2f93a34 Mon Sep 17 00:00:00 2001 From: tofulm Date: Sun, 23 Apr 2023 11:40:27 +0200 Subject: [PATCH 14/16] =?UTF-8?q?feat:=20on=20n'utilise=20plus=20la=20lib?= =?UTF-8?q?=20pour=20le=20copi=C3=A9,=20on=20le=20fait=20via=20l'api=20js?= =?UTF-8?q?=20plus=20simplement.=20on=20ajoute=20aussi=20le=20copi=C3=A9?= =?UTF-8?q?=20dans=20le=20textarea,=20comme=20le=20fait=20le=20priv=C3=A9?= =?UTF-8?q?=20pour=20les=20modeles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamumail/remplacements_slugs.html | 2 +- js/clipboard.js | 890 ------------------------------ js/clipboard.min.js | 7 - js/toClip.js | 19 +- 4 files changed, 12 insertions(+), 906 deletions(-) delete mode 100644 js/clipboard.js delete mode 100644 js/clipboard.min.js diff --git a/gamumail/remplacements_slugs.html b/gamumail/remplacements_slugs.html index b30f0d0..b0bdd04 100644 --- a/gamumail/remplacements_slugs.html +++ b/gamumail/remplacements_slugs.html @@ -15,5 +15,5 @@ <:gamumail:avertissement_remplacements:> - + diff --git a/js/clipboard.js b/js/clipboard.js deleted file mode 100644 index aeb826f..0000000 --- a/js/clipboard.js +++ /dev/null @@ -1,890 +0,0 @@ -/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["ClipboardJS"] = factory(); - else - root["ClipboardJS"] = factory(); -})(this, function() { -return /******/ (function() { // webpackBootstrap -/******/ var __webpack_modules__ = ({ - -/***/ 686: -/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { - -"use strict"; - -// EXPORTS -__webpack_require__.d(__webpack_exports__, { - "default": function() { return /* binding */ clipboard; } -}); - -// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js -var tiny_emitter = __webpack_require__(279); -var tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter); -// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js -var listen = __webpack_require__(370); -var listen_default = /*#__PURE__*/__webpack_require__.n(listen); -// EXTERNAL MODULE: ./node_modules/select/src/select.js -var src_select = __webpack_require__(817); -var select_default = /*#__PURE__*/__webpack_require__.n(src_select); -;// CONCATENATED MODULE: ./src/common/command.js -/** - * Executes a given operation type. - * @param {String} type - * @return {Boolean} - */ -function command(type) { - try { - return document.execCommand(type); - } catch (err) { - return false; - } -} -;// CONCATENATED MODULE: ./src/actions/cut.js - - -/** - * Cut action wrapper. - * @param {String|HTMLElement} target - * @return {String} - */ - -var ClipboardActionCut = function ClipboardActionCut(target) { - var selectedText = select_default()(target); - command('cut'); - return selectedText; -}; - -/* harmony default export */ var actions_cut = (ClipboardActionCut); -;// CONCATENATED MODULE: ./src/common/create-fake-element.js -/** - * Creates a fake textarea element with a value. - * @param {String} value - * @return {HTMLElement} - */ -function createFakeElement(value) { - var isRTL = document.documentElement.getAttribute('dir') === 'rtl'; - var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS - - fakeElement.style.fontSize = '12pt'; // Reset box model - - fakeElement.style.border = '0'; - fakeElement.style.padding = '0'; - fakeElement.style.margin = '0'; // Move element out of screen horizontally - - fakeElement.style.position = 'absolute'; - fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically - - var yPosition = window.pageYOffset || document.documentElement.scrollTop; - fakeElement.style.top = "".concat(yPosition, "px"); - fakeElement.setAttribute('readonly', ''); - fakeElement.value = value; - return fakeElement; -} -;// CONCATENATED MODULE: ./src/actions/copy.js - - - -/** - * Create fake copy action wrapper using a fake element. - * @param {String} target - * @param {Object} options - * @return {String} - */ - -var fakeCopyAction = function fakeCopyAction(value, options) { - var fakeElement = createFakeElement(value); - options.container.appendChild(fakeElement); - var selectedText = select_default()(fakeElement); - command('copy'); - fakeElement.remove(); - return selectedText; -}; -/** - * Copy action wrapper. - * @param {String|HTMLElement} target - * @param {Object} options - * @return {String} - */ - - -var ClipboardActionCopy = function ClipboardActionCopy(target) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { - container: document.body - }; - var selectedText = ''; - - if (typeof target === 'string') { - selectedText = fakeCopyAction(target, options); - } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) { - // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange - selectedText = fakeCopyAction(target.value, options); - } else { - selectedText = select_default()(target); - command('copy'); - } - - return selectedText; -}; - -/* harmony default export */ var actions_copy = (ClipboardActionCopy); -;// CONCATENATED MODULE: ./src/actions/default.js -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - - - -/** - * Inner function which performs selection from either `text` or `target` - * properties and then executes copy or cut operations. - * @param {Object} options - */ - -var ClipboardActionDefault = function ClipboardActionDefault() { - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - // Defines base properties passed from constructor. - var _options$action = options.action, - action = _options$action === void 0 ? 'copy' : _options$action, - container = options.container, - target = options.target, - text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'. - - if (action !== 'copy' && action !== 'cut') { - throw new Error('Invalid "action" value, use either "copy" or "cut"'); - } // Sets the `target` property using an element that will be have its content copied. - - - if (target !== undefined) { - if (target && _typeof(target) === 'object' && target.nodeType === 1) { - if (action === 'copy' && target.hasAttribute('disabled')) { - throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); - } - - if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { - throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); - } - } else { - throw new Error('Invalid "target" value, use a valid Element'); - } - } // Define selection strategy based on `text` property. - - - if (text) { - return actions_copy(text, { - container: container - }); - } // Defines which selection strategy based on `target` property. - - - if (target) { - return action === 'cut' ? actions_cut(target) : actions_copy(target, { - container: container - }); - } -}; - -/* harmony default export */ var actions_default = (ClipboardActionDefault); -;// CONCATENATED MODULE: ./src/clipboard.js -function clipboard_typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return clipboard_typeof(obj); } - -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } - -function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } - -function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } - -function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } - -function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } - -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } - -function _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } - -function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } - -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } - -function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } - - - - - - -/** - * Helper function to retrieve attribute value. - * @param {String} suffix - * @param {Element} element - */ - -function getAttributeValue(suffix, element) { - var attribute = "data-clipboard-".concat(suffix); - - if (!element.hasAttribute(attribute)) { - return; - } - - return element.getAttribute(attribute); -} -/** - * Base class which takes one or more elements, adds event listeners to them, - * and instantiates a new `ClipboardAction` on each click. - */ - - -var Clipboard = /*#__PURE__*/function (_Emitter) { - _inherits(Clipboard, _Emitter); - - var _super = _createSuper(Clipboard); - - /** - * @param {String|HTMLElement|HTMLCollection|NodeList} trigger - * @param {Object} options - */ - function Clipboard(trigger, options) { - var _this; - - _classCallCheck(this, Clipboard); - - _this = _super.call(this); - - _this.resolveOptions(options); - - _this.listenClick(trigger); - - return _this; - } - /** - * Defines if attributes would be resolved using internal setter functions - * or custom functions that were passed in the constructor. - * @param {Object} options - */ - - - _createClass(Clipboard, [{ - key: "resolveOptions", - value: function resolveOptions() { - var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; - this.action = typeof options.action === 'function' ? options.action : this.defaultAction; - this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; - this.text = typeof options.text === 'function' ? options.text : this.defaultText; - this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body; - } - /** - * Adds a click event listener to the passed trigger. - * @param {String|HTMLElement|HTMLCollection|NodeList} trigger - */ - - }, { - key: "listenClick", - value: function listenClick(trigger) { - var _this2 = this; - - this.listener = listen_default()(trigger, 'click', function (e) { - return _this2.onClick(e); - }); - } - /** - * Defines a new `ClipboardAction` on each click event. - * @param {Event} e - */ - - }, { - key: "onClick", - value: function onClick(e) { - var trigger = e.delegateTarget || e.currentTarget; - var action = this.action(trigger) || 'copy'; - var text = actions_default({ - action: action, - container: this.container, - target: this.target(trigger), - text: this.text(trigger) - }); // Fires an event based on the copy operation result. - - this.emit(text ? 'success' : 'error', { - action: action, - text: text, - trigger: trigger, - clearSelection: function clearSelection() { - if (trigger) { - trigger.focus(); - } - - window.getSelection().removeAllRanges(); - } - }); - } - /** - * Default `action` lookup function. - * @param {Element} trigger - */ - - }, { - key: "defaultAction", - value: function defaultAction(trigger) { - return getAttributeValue('action', trigger); - } - /** - * Default `target` lookup function. - * @param {Element} trigger - */ - - }, { - key: "defaultTarget", - value: function defaultTarget(trigger) { - var selector = getAttributeValue('target', trigger); - - if (selector) { - return document.querySelector(selector); - } - } - /** - * Allow fire programmatically a copy action - * @param {String|HTMLElement} target - * @param {Object} options - * @returns Text copied. - */ - - }, { - key: "defaultText", - - /** - * Default `text` lookup function. - * @param {Element} trigger - */ - value: function defaultText(trigger) { - return getAttributeValue('text', trigger); - } - /** - * Destroy lifecycle. - */ - - }, { - key: "destroy", - value: function destroy() { - this.listener.destroy(); - } - }], [{ - key: "copy", - value: function copy(target) { - var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { - container: document.body - }; - return actions_copy(target, options); - } - /** - * Allow fire programmatically a cut action - * @param {String|HTMLElement} target - * @returns Text cutted. - */ - - }, { - key: "cut", - value: function cut(target) { - return actions_cut(target); - } - /** - * Returns the support of the given action, or all actions if no action is - * given. - * @param {String} [action] - */ - - }, { - key: "isSupported", - value: function isSupported() { - var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; - var actions = typeof action === 'string' ? [action] : action; - var support = !!document.queryCommandSupported; - actions.forEach(function (action) { - support = support && !!document.queryCommandSupported(action); - }); - return support; - } - }]); - - return Clipboard; -}((tiny_emitter_default())); - -/* harmony default export */ var clipboard = (Clipboard); - -/***/ }), - -/***/ 828: -/***/ (function(module) { - -var DOCUMENT_NODE_TYPE = 9; - -/** - * A polyfill for Element.matches() - */ -if (typeof Element !== 'undefined' && !Element.prototype.matches) { - var proto = Element.prototype; - - proto.matches = proto.matchesSelector || - proto.mozMatchesSelector || - proto.msMatchesSelector || - proto.oMatchesSelector || - proto.webkitMatchesSelector; -} - -/** - * Finds the closest parent that matches a selector. - * - * @param {Element} element - * @param {String} selector - * @return {Function} - */ -function closest (element, selector) { - while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { - if (typeof element.matches === 'function' && - element.matches(selector)) { - return element; - } - element = element.parentNode; - } -} - -module.exports = closest; - - -/***/ }), - -/***/ 438: -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -var closest = __webpack_require__(828); - -/** - * Delegates event to a selector. - * - * @param {Element} element - * @param {String} selector - * @param {String} type - * @param {Function} callback - * @param {Boolean} useCapture - * @return {Object} - */ -function _delegate(element, selector, type, callback, useCapture) { - var listenerFn = listener.apply(this, arguments); - - element.addEventListener(type, listenerFn, useCapture); - - return { - destroy: function() { - element.removeEventListener(type, listenerFn, useCapture); - } - } -} - -/** - * Delegates event to a selector. - * - * @param {Element|String|Array} [elements] - * @param {String} selector - * @param {String} type - * @param {Function} callback - * @param {Boolean} useCapture - * @return {Object} - */ -function delegate(elements, selector, type, callback, useCapture) { - // Handle the regular Element usage - if (typeof elements.addEventListener === 'function') { - return _delegate.apply(null, arguments); - } - - // Handle Element-less usage, it defaults to global delegation - if (typeof type === 'function') { - // Use `document` as the first parameter, then apply arguments - // This is a short way to .unshift `arguments` without running into deoptimizations - return _delegate.bind(null, document).apply(null, arguments); - } - - // Handle Selector-based usage - if (typeof elements === 'string') { - elements = document.querySelectorAll(elements); - } - - // Handle Array-like based usage - return Array.prototype.map.call(elements, function (element) { - return _delegate(element, selector, type, callback, useCapture); - }); -} - -/** - * Finds closest match and invokes callback. - * - * @param {Element} element - * @param {String} selector - * @param {String} type - * @param {Function} callback - * @return {Function} - */ -function listener(element, selector, type, callback) { - return function(e) { - e.delegateTarget = closest(e.target, selector); - - if (e.delegateTarget) { - callback.call(element, e); - } - } -} - -module.exports = delegate; - - -/***/ }), - -/***/ 879: -/***/ (function(__unused_webpack_module, exports) { - -/** - * Check if argument is a HTML element. - * - * @param {Object} value - * @return {Boolean} - */ -exports.node = function(value) { - return value !== undefined - && value instanceof HTMLElement - && value.nodeType === 1; -}; - -/** - * Check if argument is a list of HTML elements. - * - * @param {Object} value - * @return {Boolean} - */ -exports.nodeList = function(value) { - var type = Object.prototype.toString.call(value); - - return value !== undefined - && (type === '[object NodeList]' || type === '[object HTMLCollection]') - && ('length' in value) - && (value.length === 0 || exports.node(value[0])); -}; - -/** - * Check if argument is a string. - * - * @param {Object} value - * @return {Boolean} - */ -exports.string = function(value) { - return typeof value === 'string' - || value instanceof String; -}; - -/** - * Check if argument is a function. - * - * @param {Object} value - * @return {Boolean} - */ -exports.fn = function(value) { - var type = Object.prototype.toString.call(value); - - return type === '[object Function]'; -}; - - -/***/ }), - -/***/ 370: -/***/ (function(module, __unused_webpack_exports, __webpack_require__) { - -var is = __webpack_require__(879); -var delegate = __webpack_require__(438); - -/** - * Validates all params and calls the right - * listener function based on its target type. - * - * @param {String|HTMLElement|HTMLCollection|NodeList} target - * @param {String} type - * @param {Function} callback - * @return {Object} - */ -function listen(target, type, callback) { - if (!target && !type && !callback) { - throw new Error('Missing required arguments'); - } - - if (!is.string(type)) { - throw new TypeError('Second argument must be a String'); - } - - if (!is.fn(callback)) { - throw new TypeError('Third argument must be a Function'); - } - - if (is.node(target)) { - return listenNode(target, type, callback); - } - else if (is.nodeList(target)) { - return listenNodeList(target, type, callback); - } - else if (is.string(target)) { - return listenSelector(target, type, callback); - } - else { - throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); - } -} - -/** - * Adds an event listener to a HTML element - * and returns a remove listener function. - * - * @param {HTMLElement} node - * @param {String} type - * @param {Function} callback - * @return {Object} - */ -function listenNode(node, type, callback) { - node.addEventListener(type, callback); - - return { - destroy: function() { - node.removeEventListener(type, callback); - } - } -} - -/** - * Add an event listener to a list of HTML elements - * and returns a remove listener function. - * - * @param {NodeList|HTMLCollection} nodeList - * @param {String} type - * @param {Function} callback - * @return {Object} - */ -function listenNodeList(nodeList, type, callback) { - Array.prototype.forEach.call(nodeList, function(node) { - node.addEventListener(type, callback); - }); - - return { - destroy: function() { - Array.prototype.forEach.call(nodeList, function(node) { - node.removeEventListener(type, callback); - }); - } - } -} - -/** - * Add an event listener to a selector - * and returns a remove listener function. - * - * @param {String} selector - * @param {String} type - * @param {Function} callback - * @return {Object} - */ -function listenSelector(selector, type, callback) { - return delegate(document.body, selector, type, callback); -} - -module.exports = listen; - - -/***/ }), - -/***/ 817: -/***/ (function(module) { - -function select(element) { - var selectedText; - - if (element.nodeName === 'SELECT') { - element.focus(); - - selectedText = element.value; - } - else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { - var isReadOnly = element.hasAttribute('readonly'); - - if (!isReadOnly) { - element.setAttribute('readonly', ''); - } - - element.select(); - element.setSelectionRange(0, element.value.length); - - if (!isReadOnly) { - element.removeAttribute('readonly'); - } - - selectedText = element.value; - } - else { - if (element.hasAttribute('contenteditable')) { - element.focus(); - } - - var selection = window.getSelection(); - var range = document.createRange(); - - range.selectNodeContents(element); - selection.removeAllRanges(); - selection.addRange(range); - - selectedText = selection.toString(); - } - - return selectedText; -} - -module.exports = select; - - -/***/ }), - -/***/ 279: -/***/ (function(module) { - -function E () { - // Keep this empty so it's easier to inherit from - // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) -} - -E.prototype = { - on: function (name, callback, ctx) { - var e = this.e || (this.e = {}); - - (e[name] || (e[name] = [])).push({ - fn: callback, - ctx: ctx - }); - - return this; - }, - - once: function (name, callback, ctx) { - var self = this; - function listener () { - self.off(name, listener); - callback.apply(ctx, arguments); - }; - - listener._ = callback - return this.on(name, listener, ctx); - }, - - emit: function (name) { - var data = [].slice.call(arguments, 1); - var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); - var i = 0; - var len = evtArr.length; - - for (i; i < len; i++) { - evtArr[i].fn.apply(evtArr[i].ctx, data); - } - - return this; - }, - - off: function (name, callback) { - var e = this.e || (this.e = {}); - var evts = e[name]; - var liveEvents = []; - - if (evts && callback) { - for (var i = 0, len = evts.length; i < len; i++) { - if (evts[i].fn !== callback && evts[i].fn._ !== callback) - liveEvents.push(evts[i]); - } - } - - // Remove event from queue to prevent memory leak - // Suggested by https://github.com/lazd - // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 - - (liveEvents.length) - ? e[name] = liveEvents - : delete e[name]; - - return this; - } -}; - -module.exports = E; -module.exports.TinyEmitter = E; - - -/***/ }) - -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ if(__webpack_module_cache__[moduleId]) { -/******/ return __webpack_module_cache__[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/compat get default export */ -/******/ !function() { -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function() { return module['default']; } : -/******/ function() { return module; }; -/******/ __webpack_require__.d(getter, { a: getter }); -/******/ return getter; -/******/ }; -/******/ }(); -/******/ -/******/ /* webpack/runtime/define property getters */ -/******/ !function() { -/******/ // define getter functions for harmony exports -/******/ __webpack_require__.d = function(exports, definition) { -/******/ for(var key in definition) { -/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ }(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ !function() { -/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } -/******/ }(); -/******/ -/************************************************************************/ -/******/ // module exports must be returned from runtime so entry inlining is disabled -/******/ // startup -/******/ // Load entry module and return exports -/******/ return __webpack_require__(686); -/******/ })() -.default; -}); \ No newline at end of file diff --git a/js/clipboard.min.js b/js/clipboard.min.js deleted file mode 100644 index 1103f81..0000000 --- a/js/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.11 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1✔ copié`; - $(e.trigger).append(html); - setTimeout(() => { - $(e.trigger).children('.copierOk').remove(); - e.clearSelection(); - }, 1000); + $('.toClip').on('mousedown', function (e) { + e.preventDefault(); + const t = $(this).data('clipboard-text') ?? $(this).text(); + navigator.clipboard.writeText(t).then(() => { + barre_inserer(t); + const html = `✔ copié`; + $(this).append(html); + setTimeout(() => { + $(this).children('.copierOk').remove(); + }, 1000); + }); }); }); From 9a59e7a8b10b7dda34ef98591e2efeb05edcfb8b Mon Sep 17 00:00:00 2001 From: tofulm Date: Mon, 5 Jun 2023 20:43:09 +0200 Subject: [PATCH 15/16] feat: ajout de repondre_a --- css/gamumail.css | 8 ++++++++ formulaires/gamumail.html | 17 +++++++++++++++-- formulaires/gamumail.php | 11 +++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/css/gamumail.css b/css/gamumail.css index 2d72a1d..39dbfdf 100644 --- a/css/gamumail.css +++ b/css/gamumail.css @@ -205,6 +205,14 @@ width: 50px; } +.editer_repondre_a { + display: flex; +} + +.editer_repondre_a label { + width: 120px; +} + .reponse_formulaire { padding: 1rem; margin-bottom: 2rem; diff --git a/formulaires/gamumail.html b/formulaires/gamumail.html index 5bed229..6b38840 100644 --- a/formulaires/gamumail.html +++ b/formulaires/gamumail.html @@ -29,7 +29,7 @@ - +
#SET{name,envoi_separe} #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}} @@ -46,7 +46,7 @@
- +
@@ -71,6 +71,19 @@
+ +
+ #SET{name,repondre_a} + #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}} + #SET{obli,"obligatoire"} +
+ + [(#GET{erreurs})] + +
+
+ +
#SET{name,sujet} #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}} diff --git a/formulaires/gamumail.php b/formulaires/gamumail.php index e618059..d9f390d 100644 --- a/formulaires/gamumail.php +++ b/formulaires/gamumail.php @@ -26,6 +26,7 @@ function formulaires_gamumail_charger_dist($slug, $destinataires = 0, $Tclient = $Tcc = lire_config('gamumail/mail_cc') !== '' ? explode(',', lire_config('gamumail/mail_cc', '')) : []; $Tcci = lire_config('gamumail/mail_cci') !== '' ? explode(',', lire_config('gamumail/mail_cci', '')) : []; + $Trepondre_a = lire_config('gamumail/mail_repondre_a') !== '' ? explode(',', lire_config('gamumail/mail_repondre_a', '')) : []; if (!empty($destinataires) and !is_array($destinataires)) { $destinataires = explode(',', $destinataires); @@ -81,6 +82,7 @@ function formulaires_gamumail_charger_dist($slug, $destinataires = 0, $Tclient = 'pour' => implode(',', $Tmails), 'cc' => implode(',', $Tcc), 'cci' => implode(',', $Tcci), + 'repondre_a' => implode(',', $Trepondre_a), 'TFichierpdfs' => $TFichierPdf, 'Tpdfs_ok' => [], 'docs_spip' => $gamuMail['id_docs'] ?? '', @@ -250,11 +252,13 @@ function formulaires_gamumail_traiter_dist($slug, $destinataires = 0, $Tclient = function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, &$retour = []) { - $cc = _request('cc'); - $cci = _request('cci'); + $cc = _request('cc'); + $cci = _request('cci'); + $repondre_a = _request('repondre_a'); $cc = explode(',', $cc); $cci = explode(',', $cci); + $repondre_a = explode(',', $repondre_a); $sujet = _request('sujet'); $html = propre(_request('texte')); @@ -400,6 +404,9 @@ function gamuSend($slug, $options, $destinataires, $Tclient, $Tpdf, $redirect, & 'cci' => $cci, 'pieces_jointes' => $pieces_jointes ]; + if ($repondre_a) { + $corps['repondre_a'] = $repondre_a; + } // surcharges de traiter : d'abord les surcharges pour tous les slugs (tous_traiter.php) puis les spécifiques par slug (nom_slug_traiter.php) From 6aaba3f5fe5037bc48cb3ec0e8506ab276a4788a Mon Sep 17 00:00:00 2001 From: tofulm Date: Tue, 13 Jun 2023 15:33:26 +0200 Subject: [PATCH 16/16] recup de la master --- inc/envoyer_gamumail.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inc/envoyer_gamumail.php b/inc/envoyer_gamumail.php index 1eb614e..23639df 100644 --- a/inc/envoyer_gamumail.php +++ b/inc/envoyer_gamumail.php @@ -225,13 +225,18 @@ function inc_envoyer_gamumail($slug, $destinataires, $options = [], $Tid_doc_pie 'args' => $args, 'data' => $html )); + $sujet = pipeline('remplacements_slug',[ + 'args' => $args, + 'data' => $sujet + ]); // traitement des remplacements génériques fournis par Gamumail $remplacement_generiques = charger_fonction('gamumail_remplacements', 'inc'); $html = $remplacement_generiques($args, $html); + $sujet = $remplacement_generiques($args, $sujet); + include_spip('facteur_fonctions'); $texte = facteur_mail_html2text($html); - $corps = [ 'html' => $html, 'texte' => $texte, @@ -263,11 +268,6 @@ function inc_envoyer_gamumail($slug, $destinataires, $options = [], $Tid_doc_pie exit; } else { - $sujet = pipeline('remplacements_slug',[ - 'args' => $args, - 'data' => $sujet - ]); - $sujet = $remplacement_generiques($args, $sujet); // pour ne pas avoir de warning de la fonction envoyer_mail() on doit lui passer un paramètre $from et un $header $from = ''; $header = '';