[SPIP] v3.2.12 -> v3.2.12 - Reinstallation avec le spip_loader
[lhc/web/www.git] / www / plugins-dist / porte_plume / porte_plume_fonctions.php
1 <?php
2 /**
3 * Fonctions utiles pour le Porte Plume
4 *
5 * @plugin Porte Plume pour SPIP
6 * @license GPL
7 * @package SPIP\PortePlume\BarreOutils
8 */
9
10 if (!defined('_ECRIRE_INC_VERSION')) {
11 return;
12 }
13
14 /**
15 * Objet contenant les différents paramètres definissant une barre d'outils
16 * Markitup et permettant d'agir dessus
17 *
18 * @example
19 * $barre = new Barre_Outil($description);
20 *
21 * @package SPIP\PortePlume\BarreOutils
22 */
23 class Barre_outils {
24 /**
25 * Identifiant HTML de la barre
26 *
27 * @todo À supprimer car non utilisé !
28 * @var string
29 */
30 public $id = '';
31
32 /**
33 * Nom de la barre d'outil
34 *
35 * @var string
36 */
37 public $nameSpace = '';
38
39 /**
40 * Langue
41 *
42 * @todo À supprimer car non utilisé !
43 * @var string
44 */
45 public $lang = '';
46
47 /**
48 * Option de markitup : rafraîchir la prévisu ?
49 *
50 * @todo À supprimer car non utilisé !
51 * @var bool
52 */
53 public $previewAutoRefresh = false;
54
55 /**
56 * Option de markitup : nom de la fonction de prévisu
57 *
58 * @todo À supprimer car on le redéfini dans l'appel javascript !
59 * @var bool
60 */
61 public $previewParserPath = '';
62
63 /**
64 * Option de markitup : que faire sur l'appuie de Entrée ?
65 *
66 * @var array
67 */
68 public $onEnter = array();
69
70 /**
71 * Option de markitup : que faire sur l'appuie de Shift+Entrée ?
72 *
73 * @example array('keepDefault'=>false, 'replaceWith'=>"\n_ ")
74 * @var array
75 */
76 public $onShiftEnter = array();
77
78 /**
79 * Option de markitup : que faire sur l'appuie de Control+Entrée ?
80 *
81 * @var array
82 */
83 public $onCtrlEnter = array();
84
85 /**
86 * Option de markitup : que faire sur l'appuie d'une tabulation ?
87 *
88 * @var array
89 */
90 public $onTab = array();
91
92 /**
93 * Option de markitup : Code JS à exécuter avant une insertion
94 *
95 * @var string
96 */
97 public $beforeInsert = '';
98
99 /**
100 * Option de markitup : Code JS à exécuter après une insertion
101 *
102 * @var string
103 */
104 public $afterInsert = '';
105
106 /**
107 * Description des outils/boutons et leurs sous boutons éventuels
108 *
109 * @var array
110 */
111 public $markupSet = array();
112
113 /**
114 * Fonctions JS supplémentaires à écrire après la déclaration JSON
115 * des outils. Ces fonctions peuvent servir aux boutons.
116 *
117 * @var string
118 */
119 public $functions = '';
120
121 /**
122 * Liste des paramètres valides pour une description d'outils (markupSet)
123 *
124 * @var array
125 */
126 private $_liste_params_autorises = array(
127
128 'replaceWith',
129 'openWith',
130 'closeWith',
131 'openBlockWith',
132 // sur multiline, avant les lignes selectionnees
133 'closeBlockWith',
134 // sur multiline, apres les lignes selectionnees
135 'placeHolder',
136 // remplace par ce texte lorsqu'il n'y a pas de selection
137
138 'beforeInsert',
139 // avant l'insertion
140 'afterInsert',
141 // apres l'insertion
142 'beforeMultiInsert',
143 'afterMultiInsert',
144
145 'dropMenu',
146 // appelle un sous menu
147
148 'name',
149 // nom affiche au survol
150 'key',
151 // raccourcis clavier
152 'className',
153 // classe css utilisee
154 'lang',
155 // langues dont le bouton doit apparaitre - array
156 'lang_not',
157 // langues dont le bouton ne doit pas apparaitre - array
158 'selectionType',
159 // '','word','line' : type de selection (normale, aux mots les plus proches, a la ligne la plus proche)
160 'multiline',
161 // open/close sur chaque ligne (mais replace est applique sur l'ensemble de la selection)
162 'forceMultiline',
163 // pour faire comme si on faisait systematiquement un control+shift
164 // (et replace est applique sur chaque ligne de la selection)
165
166 'separator',
167
168 'call',
169 'keepDefault',
170
171 // cacher ou afficher facilement des boutons
172 'display',
173 // donner un identifiant unique au bouton (pour le php)
174 'id',
175 );
176
177 /**
178 * Constructeur
179 *
180 * Initialise la barre avec les paramètres transmis
181 * en n'adressant que les paramètres effectivement valides
182 *
183 * @api
184 * @param array $params Paramètres de la barre d'outil
185 * @return void
186 */
187 public function __construct($params = array()) {
188 foreach ($params as $p => $v) {
189 if (isset($this->$p)) {
190 // si tableau, on verifie les entrees
191 if (is_array($v)) {
192 $v = $this->verif_params($p, $v);
193 }
194 $this->$p = $v;
195 }
196 }
197 }
198
199
200 /**
201 * Vérifie que les paramètres d'une clé existent
202 * et retourne un tableau des paramètres valides
203 *
204 * @param string $nom
205 * Clé à vérifier (ex: 'markupSet')
206 * @param array $params
207 * Paramètres de cette clé (description des boutons ou sous boutons)
208 * @return array
209 * Paramètres, soustrait de ceux qui ne sont pas valides
210 */
211 public function verif_params($nom, $params = array()) {
212 // si markupset, on boucle sur les items
213 if (stripos($nom, 'markupSet') !== false) {
214 foreach ($params as $i => $v) {
215 $params[$i] = $this->verif_params($i, $v);
216 }
217 } // sinon on teste la validite
218 else {
219 foreach ($params as $p => $v) {
220 if (!in_array($p, $this->_liste_params_autorises)) {
221 unset($params[$p]);
222 }
223 }
224 }
225
226 return $params;
227 }
228
229 /**
230 * Permet d'affecter des paramètres à un élément de la barre
231 *
232 * La fonction retourne les paramètres, de sorte qu'on peut s'en servir
233 * pour simplement récupérer ceux-ci.
234 *
235 * Il est possible d'affecter des paramètres avant/après l'élément trouvé
236 * en definisant une valeur différente pour le $lieu : 'dedans','avant','apres'
237 * par defaut 'dedans' (modifie l'élément trouvé).
238 *
239 * Lorsqu'on demande d'insérer avant ou après, la fonction retourne
240 * les paramètres inserés
241 *
242 * @param array $tableau
243 * Tableau ou chercher les elements (sert pour la recursion)
244 * @param string $identifiant
245 * Identifiant du bouton a afficher
246 * @param array $params
247 * Paramètres à affecter à la trouvaille (ou avant ou après).
248 * Peut être un tableau clé/valeur ou un tableau de tableaux
249 * clé/valeur (sauf pour $lieu = dedans)
250 * @param string $lieu
251 * Lieu d'affectation des paramètres (dedans, avant, apres)
252 * @param bool $plusieurs
253 * Définit si $params est une forme simple (tableau cle/valeur)
254 * ou comporte plusieurs boutons (tableau de tableaux cle/valeur).
255 * @return array|bool
256 * Paramètres de l'élément modifié ou paramètres ajoutés
257 * False si l'identifiant cherché n'est pas trouvé
258 */
259 public function affecter(&$tableau, $identifiant, $params = array(), $lieu = 'dedans', $plusieurs = false) {
260 static $cle_de_recherche = 'id'; // ou className ?
261
262 if ($tableau === null) {// utile ?
263 $tableau = &$this->markupSet;
264 }
265
266 if (!in_array($lieu, array('dedans', 'avant', 'apres'))) {
267 $lieu = 'dedans';
268 }
269
270 // present en premiere ligne ?
271 $trouve = false;
272 foreach ($tableau as $i => $v) {
273 if (isset($v[$cle_de_recherche]) and ($v[$cle_de_recherche] == $identifiant)) {
274 $trouve = $i;
275 break;
276 }
277 }
278 // si trouve, affectations
279 if (($trouve !== false)) {
280 if ($params) {
281 // verifier que les insertions sont correctes
282 $les_params = ($plusieurs ? $params : array($params));
283 foreach ($les_params as $i => $un_params) {
284 $les_params[$i] = $this->verif_params($identifiant, $un_params);
285 }
286
287 // dedans on merge ($params uniquement tableau cle/valeur)
288 if ($lieu == 'dedans' && !$plusieurs) {
289 return $tableau[$trouve] = array_merge($tableau[$trouve], $les_params[0]);
290 } // avant ou apres, on insere ($params peut etre tableau cle/valeur ou tableau de tableaux cle/valeur)
291 elseif ($lieu == 'avant') {
292 array_splice($tableau, $trouve, 0, $les_params);
293
294 return $params;
295 } elseif ($lieu == 'apres') {
296 array_splice($tableau, $trouve + 1, 0, $les_params);
297
298 return $params;
299 }
300 }
301
302 return $tableau[$trouve];
303 }
304
305 // recursivons sinon !
306 foreach ($tableau as $i => $v) {
307 if (is_array($v)) {
308 foreach ($v as $m => $n) {
309 if (is_array($n)
310 and ($r = $this->affecter($tableau[$i][$m], $identifiant, $params, $lieu, $plusieurs))) {
311 return $r;
312 }
313 }
314 }
315 }
316
317 return false;
318 }
319
320
321 /**
322 * Permet d'affecter des paramètres à tous les éléments de la barre
323 * ou à une liste d'identifiants d'éléments indiqués.
324 *
325 * @param array $tableau
326 * Tableau où chercher les éléments
327 * @param array $params
328 * Paramètres à affecter aux éléments
329 * @param array $ids
330 * Tableau d'identifiants particuliers à qui on affecte les paramètres.
331 * Si vide, tous les identifiants seront modifiés
332 * @return bool
333 * false si aucun paramètre à affecter, true sinon.
334 */
335 public function affecter_a_tous(&$tableau, $params = array(), $ids = array()) {
336 if (!$params) {
337 return false;
338 }
339
340 if ($tableau === null) {
341 $tableau = &$this->markupSet;
342 }
343
344 $params = $this->verif_params('divers', $params);
345
346 // merge de premiere ligne
347 foreach ($tableau as $i => &$v) {
348 if (!$ids or in_array($v['id'], $ids)) {
349 $tableau[$i] = array_merge($tableau[$i], $params);
350 }
351 // recursion si sous-menu
352 if (isset($tableau[$i]['dropMenu'])) {
353 $this->affecter_a_tous($tableau[$i]['dropMenu'], $params, $ids);
354 }
355 }
356
357 return true;
358 }
359
360
361 /**
362 * Affecte les valeurs des paramètres indiqués au bouton demandé
363 * et retourne l'ensemble des paramètres du bouton (sinon false)
364 *
365 * @api
366 * @param string|array $identifiant
367 * Identifiant du ou des boutons.
368 * @param array $params
369 * Paramètres de l'ajout (tableau paramètre=>valeur)
370 * @return bool|array
371 * false si l'identifiant n'a pas été trouvé
372 * true si plusieurs identifiants,
373 * array sinon : description de l'identifiant cherché.
374 */
375 public function set($identifiant, $params = array()) {
376 // prudence tout de meme a pas tout modifier involontairement (si array)
377 if (!$identifiant) {
378 return false;
379 }
380
381 if (is_string($identifiant)) {
382 return $this->affecter($this->markupSet, $identifiant, $params);
383 } elseif (is_array($identifiant)) {
384 return $this->affecter_a_tous($this->markupSet, $params, $identifiant);
385 }
386
387 return false;
388 }
389
390 /**
391 * Retourne les parametres du bouton demande
392 *
393 * @api
394 * @param string|array $identifiant
395 * Identifiant du ou des boutons.
396 * @return bool|array
397 * false si l'identifiant n'est pas trouvé
398 * array sinon : Description de l'identifiant cherché.
399 */
400 public function get($identifiant) {
401 if ($a = $this->affecter($this->markupSet, $identifiant)) {
402 return $a;
403 }
404
405 return false;
406 }
407
408
409 /**
410 * Affiche le ou les boutons demandés
411 *
412 * @api
413 * @param string|array $identifiant
414 * Identifiant du ou des boutons
415 * @return bool|array
416 * false si l'identifiant n'a pas été trouvé
417 * true si plusieurs identifiants,
418 * array sinon : description de l'identifiant cherché.
419 */
420 public function afficher($identifiant) {
421 return $this->set($identifiant, array('display' => true));
422 }
423
424
425 /**
426 * Cache le ou les boutons demandés
427 *
428 * @api
429 * @param string|array $identifiant
430 * Identifiant du ou des boutons
431 * @return bool|array
432 * false si l'identifiant n'a pas été trouvé
433 * true si plusieurs identifiants,
434 * array sinon : description de l'identifiant cherché.
435 */
436 public function cacher($identifiant) {
437 return $this->set($identifiant, array('display' => false));
438 }
439
440
441 /**
442 * Affiche tous les boutons
443 *
444 * @api
445 * @return bool
446 * false si aucun paramètre à affecter, true sinon.
447 */
448 public function afficherTout() {
449 return $this->affecter_a_tous($this->markupSet, array('display' => true));
450 }
451
452 /**
453 * Cache tous les boutons
454 *
455 * @api
456 * @return bool
457 * false si aucun paramètre à affecter, true sinon.
458 */
459 public function cacherTout() {
460 return $this->affecter_a_tous($this->markupSet, array('display' => false));
461 }
462
463
464 /**
465 * Ajoute un bouton ou quelque chose, avant un autre déjà présent
466 *
467 * @api
468 * @param string $identifiant
469 * Identifiant du bouton où l'on doit se situer
470 * @param array $params
471 * Paramètres de l'ajout.
472 * Description d'un bouton (tableau clé/valeurs).
473 * @return array|bool
474 * Paramètres ajoutés avant
475 * False si l'identifiant cherché n'est pas trouvé
476 */
477 public function ajouterAvant($identifiant, $params) {
478 return $this->affecter($this->markupSet, $identifiant, $params, 'avant');
479 }
480
481 /**
482 * Ajoute plusieurs boutons, avant un autre déjà présent
483 *
484 * @api
485 * @param string $identifiant
486 * Identifiant du bouton où l'on doit se situer
487 * @param array $tableau_params
488 * Paramètres de l'ajout.
489 * Description de plusieurs boutons (tableau de tableaux clé/valeurs).
490 * @return array|bool
491 * Paramètres ajoutés avant
492 * False si l'identifiant cherché n'est pas trouvé
493 */
494 public function ajouterPlusieursAvant($identifiant, $tableau_params) {
495 return $this->affecter($this->markupSet, $identifiant, $tableau_params, 'avant', true);
496 }
497
498 /**
499 * Ajoute un bouton ou quelque chose, après un autre déjà présent
500 *
501 * @api
502 * @param string $identifiant
503 * Identifiant du bouton où l'on doit se situer
504 * @param array $params
505 * Paramètres de l'ajout.
506 * Description d'un bouton (tableau clé/valeurs).
507 * @return array|bool
508 * Paramètres ajoutés après
509 * False si l'identifiant cherché n'est pas trouvé
510 */
511 public function ajouterApres($identifiant, $params) {
512 return $this->affecter($this->markupSet, $identifiant, $params, 'apres');
513 }
514
515 /**
516 * Ajoute plusieurs boutons, après un autre déjà présent
517 *
518 * @api
519 * @param string $identifiant
520 * Identifiant du bouton où l'on doit se situer
521 * @param array $tableau_params
522 * Paramètres de l'ajout.
523 * Description de plusieurs boutons (tableau de tableaux clé/valeurs).
524 * @return array|bool
525 * Paramètres ajoutés après
526 * False si l'identifiant cherché n'est pas trouvé
527 */
528 public function ajouterPlusieursApres($identifiant, $tableau_params) {
529 return $this->affecter($this->markupSet, $identifiant, $tableau_params, 'apres', true);
530 }
531
532 /**
533 * Ajoute une fonction JS qui pourra être utilisée par les boutons
534 *
535 * @api
536 * @param string $fonction Code de la fonction JS
537 * @return void
538 */
539 public function ajouterFonction($fonction) {
540 if (false === strpos($this->functions, $fonction)) {
541 $this->functions .= "\n" . $fonction . "\n";
542 }
543 }
544
545 /**
546 * Supprimer les éléments non affichés (display:false)
547 * Et les séparateurs (li vides) selon la configuration
548 *
549 * @param array $tableau Tableau de description des outils
550 * @return void
551 */
552 public function enlever_elements_non_affiches(&$tableau) {
553 if ($tableau === null) { // utile ?
554 $tableau = &$this->markupSet;
555 }
556
557 foreach ($tableau as $p => &$v) {
558 if (isset($v['display']) and !$v['display']) {
559 unset($tableau[$p]);
560 // remettre les cles automatiques sinon json les affiche et ça plante.
561 $tableau = array_values($tableau);
562 } else {
563 // sinon, on lance une recursion sur les sous-menus
564 if (isset($v['dropMenu']) and is_array($v['dropMenu'])) {
565 $this->enlever_elements_non_affiches($tableau[$p]['dropMenu']);
566 // si le sous-menu est vide
567 // on enleve le sous menu.
568 // mais pas le parent ($tableau[$p]), qui peut effectuer une action.
569 if (empty($tableau[$p]['dropMenu'])) {
570 unset($tableau[$p]['dropMenu']);
571 }
572 }
573 }
574 }
575 }
576
577 /**
578 * Enlève les séparateurs pour améliorer l'accessibilité
579 * au détriment du stylage possible de ces séparateurs.
580 *
581 * Le bouton précédent le séparateur reçoit une classe CSS 'separateur_avant'
582 * Celui apres 'separateur_apres'
583 *
584 * @param array $tableau
585 * Tableau de description des outils
586 * @return void
587 **/
588 public function enlever_separateurs(&$tableau) {
589 if ($tableau === null) { // utile ?
590 $tableau = &$this->markupSet;
591 }
592
593
594 foreach ($tableau as $p => &$v) {
595 if (isset($v['separator']) and $v['separator']) {
596 if (isset($tableau[$p - 1])) {
597 if (!isset($tableau[$p - 1]['className'])) {
598 $tableau[$p - 1]['className'] = '';
599 }
600 $tableau[$p - 1]['className'] .= ' separateur_avant';
601 }
602 if (isset($tableau[$p + 1])) {
603 if (!isset($tableau[$p + 1]['className'])) {
604 $tableau[$p + 1]['className'] = '';
605 }
606 $tableau[$p + 1]['className'] .= " separateur separateur_apres $v[id]";
607 }
608 unset($tableau[$p]);
609 // remettre les cles automatiques sinon json les affiche et ça plante.
610 $tableau = array_values($tableau);
611 } else {
612 // sinon, on lance une recursion sur les sous-menus
613 if (isset($v['dropMenu']) and is_array($v['dropMenu'])) {
614 #$this->enlever_separateurs($tableau[$p]['dropMenu']);
615 }
616 }
617 }
618 }
619
620 /**
621 * Supprime les éléments vides (uniquement à la racine de l'objet)
622 * et uniquement si chaîne ou tableau.
623 *
624 * Supprime les paramètres privés
625 * Supprime les paramètres inutiles a markitup/json dans les paramètres markupSet
626 * (id, display, icone)
627 */
628 public function enlever_parametres_inutiles() {
629 foreach ($this as $p => $v) {
630 if ($p == 'markupSet') {
631 continue;
632 }
633 if (!$v) {
634 if (is_array($v) or is_string($v)) {
635 unset($this->$p);
636 }
637 } elseif ($p == 'functions') {
638 unset($this->$p);
639 }
640 }
641 foreach ($this->markupSet as $p => $v) {
642 foreach ($v as $n => $m) {
643 if (in_array($n, array('id', 'display'))) {
644 unset($this->markupSet[$p][$n]);
645 }
646 }
647 }
648 unset($this->_liste_params_autorises);
649 }
650
651
652 /**
653 * Crée la sortie json pour le javascript des paramètres de la barre
654 *
655 * @return string Déclaration json de la barre
656 */
657 public function creer_json() {
658 $barre = $this;
659 $type = $barre->nameSpace;
660 $fonctions = $barre->functions;
661
662 $barre->enlever_elements_non_affiches($this->markupSet);
663 $barre->enlever_separateurs($this->markupSet);
664 $barre->enlever_parametres_inutiles();
665
666 $json = Barre_outils::json_export($barre);
667
668 // on lance la transformation des &chose; en veritables caracteres
669 // sinon markitup restitue &laquo; au lieu de « directement
670 // lorsqu'on clique sur l'icone
671 include_spip('inc/charsets');
672 $json = unicode2charset(html2unicode($json));
673
674 return "\n\nbarre_outils_$type = " . $json . "\n\n $fonctions";
675 }
676
677 /**
678 * Transforme une variable PHP dans un équivalent javascript (json)
679 *
680 * Copié depuis ecrire/inc/json, mais modifié pour que les fonctions
681 * JavaScript ne soient pas encapsulées dans une chaîne (string)
682 *
683 * @access private
684 * @param mixed $var the variable
685 * @return string|boolean
686 * - string : js script
687 * - boolean false if error
688 */
689 public function json_export($var) {
690 $asso = false;
691 switch (true) {
692 case is_null($var):
693 return 'null';
694 case is_string($var):
695 if (strtolower(substr(ltrim($var), 0, 8)) == 'function') {
696 return $var;
697 }
698
699 return '"' . addcslashes($var, "\"\\\n\r") . '"';
700 case is_bool($var):
701 return $var ? 'true' : 'false';
702 case is_scalar($var):
703 return $var;
704 case is_object($var):
705 $var = get_object_vars($var);
706 $asso = true;
707 case is_array($var):
708 $keys = array_keys($var);
709 $ikey = count($keys);
710 while (!$asso && $ikey--) {
711 $asso = $ikey !== $keys[$ikey];
712 }
713 $sep = '';
714 if ($asso) {
715 $ret = '{';
716 foreach ($var as $key => $elt) {
717 $ret .= $sep . '"' . $key . '":' . Barre_outils::json_export($elt);
718 $sep = ',';
719 }
720
721 return $ret . "}\n";
722 } else {
723 $ret = '[';
724 foreach ($var as $elt) {
725 $ret .= $sep . Barre_outils::json_export($elt);
726 $sep = ',';
727 }
728
729 return $ret . "]\n";
730 }
731 }
732
733 return false;
734 }
735 }
736
737
738 /**
739 * Crée le code CSS pour les images des icones des barres d'outils
740 *
741 * S'appuie sur la description des jeux de barres disponibles et cherche
742 * une fonction barre_outils_($barre)_icones pour chaque barre et
743 * l'exécute si existe, attendant alors en retour un tableau de couples :
744 * nom de l'outil => nom de l'image
745 *
746 * @pipeline_appel porte_plume_lien_classe_vers_icone
747 *
748 * @return string Déclaration CSS des icones
749 */
750 function barre_outils_css_icones() {
751 // recuperer la liste, extraire les icones
752 $css = '';
753
754 // liste des barres
755 if (!$barres = barre_outils_liste()) {
756 return null;
757 }
758
759 // liste des classes css et leur correspondance avec une icone
760 $classe2icone = array();
761 foreach ($barres as $barre) {
762 include_spip('barre_outils/' . $barre);
763 if ($f = charger_fonction($barre . '_icones', 'barre_outils', true)) {
764 if (is_array($icones = $f())) {
765 $classe2icone = array_merge($classe2icone, $icones);
766 }
767 }
768 }
769
770 /**
771 * Permettre aux plugins d'étendre les icones connues du porte plume
772 *
773 * On passe la liste des icones connues au pipeline pour ceux qui
774 * ajoutent de simples icones à des barres existantes
775 *
776 * @pipeline_appel porte_plume_lien_classe_vers_icone
777 * @var array $classe2icone
778 * Couples identifiant de bouton => nom de l'image (ou tableau)
779 * Dans le cas d'un tableau, cela indique une sprite : (nom de l'image , position haut, position bas)
780 * Exemple : 'outil_header1' => array('spt-v1.png','-10px -226px')
781 */
782 $classe2icone = pipeline('porte_plume_lien_classe_vers_icone', $classe2icone);
783
784 // passage en css
785 foreach ($classe2icone as $n => $i) {
786 $pos = '';
787 if (is_array($i)) {
788 $pos = 'background-position:' . end($i);
789 $i = reset($i);
790 }
791 if (file_exists($i)) {
792 $file = $i;
793 } else {
794 $file = find_in_path("icones_barre/$i");
795 }
796 if ($file) {
797 $css .= "\n.markItUp .$n>a>em {background-image:url(" . protocole_implicite(url_absolue($file)) . ");$pos}";
798 }
799 }
800
801 return $css;
802 }
803
804
805 /**
806 * Retourne une instance de Barre_outils
807 * crée à partir du type de barre demandé
808 *
809 * Une fonction barre_outils_{type}_dist() retournant la barre doit
810 * donc exister.
811 *
812 * @param string $set
813 * Type de barre (ex: 'edition')
814 * @return Barre_Outils|bool
815 * La barre d'outil si la fonction a été trouvée, false sinon
816 */
817 function barre_outils_initialiser($set) {
818 if ($f = charger_fonction($set, 'barre_outils')) {
819 // retourne une instance de l'objet Barre_outils
820 return $f();
821 }
822
823 return false;
824 }
825
826 /**
827 * Retourne la liste des barres d'outils connues
828 *
829 * @return array|bool
830 * Tableau des noms de barres d'outils trouvées
831 * False si on ne trouve aucune barre.
832 */
833 function barre_outils_liste() {
834 static $sets = -1;
835 if ($sets !== -1) {
836 return $sets;
837 }
838
839 // on recupere l'ensemble des barres d'outils connues
840 if (!$sets = find_all_in_path('barre_outils/', '.*[.]php')
841 or !is_array($sets)
842 ) {
843 spip_log("[Scandale] Porte Plume ne trouve pas de barre d'outils !");
844 $sets = false;
845
846 return $sets;
847 }
848
849 foreach ($sets as $fichier => $adresse) {
850 $sets[$fichier] = substr($fichier, 0, -4); // juste le nom
851 }
852
853 return $sets;
854 }
855
856 /**
857 * Filtre appliquant les traitements SPIP d'un champ
858 *
859 * Applique les filtres prévus sur un champ (et eventuellement un type d'objet)
860 * sur un texte donné. Sécurise aussi le texte en appliquant safehtml().
861 *
862 * Ce mécanisme est à préférer au traditionnel #TEXTE*|propre
863 *
864 * traitements_previsu() consulte la globale $table_des_traitements et
865 * applique le traitement adequat. Si aucun traitement n'est trouvé,
866 * alors propre() est appliqué.
867 *
868 * @package SPIP\PortePlume\Fonctions
869 * @see champs_traitements() dans public/references.php
870 * @global table_des_traitements
871 *
872 * @param string $texte
873 * Texte source
874 * @param string $nom_champ
875 * Nom du champ (nom de la balise, en majuscules)
876 * @param string $type_objet
877 * L'objet a qui appartient le champ (en minuscules)
878 * @param string $connect
879 * Nom du connecteur de base de données
880 * @return string
881 * Texte traité avec les filtres déclarés pour le champ.
882 */
883 function traitements_previsu($texte, $nom_champ = '', $type_objet = '', $connect = null) {
884 include_spip('public/interfaces'); // charger les traitements
885
886 global $table_des_traitements;
887 if (!strlen($nom_champ) || !isset($table_des_traitements[$nom_champ])) {
888 $texte = propre($texte, $connect);
889 } else {
890 include_spip('base/abstract_sql');
891 $table = table_objet($type_objet);
892 $ps = $table_des_traitements[$nom_champ];
893 if (is_array($ps)) {
894 $ps = $ps[(strlen($table) && isset($ps[$table])) ? $table : 0];
895 }
896 if (!$ps) {
897 $texte = propre($texte, $connect);
898 } else {
899 // [FIXME] Éviter une notice sur le eval suivant qui ne connait
900 // pas la Pile ici. C'est pas tres joli...
901 $Pile = array(0 => array());
902 // remplacer le placeholder %s par le texte fourni
903 eval('$texte=' . str_replace('%s', '$texte', $ps) . ';');
904 }
905 }
906 // il faut toujours securiser le texte prévisualisé car il peut contenir n'importe quoi
907 // et servir de support a une attaque xss ou vol de cookie admin
908 // on ne peut donc se fier au statut de l'auteur connecté car le contenu ne vient pas
909 // forcément de lui
910 return safehtml($texte);
911 }
912
913
914
915
916 /**
917 * Retourne la définition de la barre markitup désignée.
918 * (cette déclaration est au format json)
919 *
920 * Deux pipelines 'porte_plume_pre_charger' et 'porte_plume_charger'
921 * permettent de récuperer l'objet de classe Barre_outil
922 * avant son export en json pour modifier des elements.
923 *
924 * @pipeline_appel porte_plume_barre_pre_charger
925 * Charge des nouveaux boutons au besoin
926 * @pipeline_appel porte_plume_barre_charger
927 * Affiche ou cache certains boutons
928 *
929 * @return string Déclaration json
930 */
931 function porte_plume_creer_json_markitup() {
932 // on recupere l'ensemble des barres d'outils connues
933 include_spip('porte_plume_fonctions');
934 if (!$sets = barre_outils_liste()) {
935 return null;
936 }
937
938 // 1) On initialise tous les jeux de barres
939 $barres = array();
940 foreach ($sets as $set) {
941 if (($barre = barre_outils_initialiser($set)) and is_object($barre)) {
942 $barres[$set] = $barre;
943 }
944 }
945
946 // 2) Préchargement
947
948 /**
949 * Charger des nouveaux boutons au besoin
950 *
951 * @example
952 * $barre = &$flux['spip'];
953 * $barre->ajouterApres('bold',array(params));
954 * $barre->ajouterAvant('bold',array(params));
955 *
956 * $bold = $barre->get('bold');
957 * $bold['id'] = 'bold2';
958 * $barre->ajouterApres('italic',$bold);
959 * @pipeline_appel porte_plume_barre_pre_charger
960 */
961 $barres = pipeline('porte_plume_barre_pre_charger', $barres);
962
963
964 // 3) Chargement
965
966 /**
967 * Cacher ou afficher certains boutons au besoin
968 *
969 * @example
970 * $barre = &$flux['spip'];
971 * $barre->afficher('bold');
972 * $barre->cacher('bold');
973 *
974 * $barre->cacherTout();
975 * $barre->afficher(array('bold','italic','header1'));
976 * @pipeline_appel porte_plume_barre_charger
977 */
978 $barres = pipeline('porte_plume_barre_charger', $barres);
979
980
981 // 4 On crée les jsons
982 $json = "";
983 foreach ($barres as $set => $barre) {
984 $json .= $barre->creer_json();
985 }
986
987 return $json;
988 }