PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins-dist/porte_plume/porte_plume_fonctions.php

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