diff --git a/action/porte_plume_previsu.php b/action/porte_plume_previsu.php index 9ab3680..40bea2f 100644 --- a/action/porte_plume_previsu.php +++ b/action/porte_plume_previsu.php @@ -35,4 +35,4 @@ function action_porte_plume_previsu_dist() { } echo recuperer_fond('prive/porte_plume_preview', $contexte); -} \ No newline at end of file +} diff --git a/barre_outils/edition.php b/barre_outils/edition.php index 53e8644..38d73e1 100644 --- a/barre_outils/edition.php +++ b/barre_outils/edition.php @@ -541,4 +541,4 @@ function barre_outils_edition_icones() { 'outil_clean' => array('spt-v1.png', '-10px -982px'), //'clean.png' 'outil_preview' => array('spt-v1.png', '-10px -1018px'), //'eye.png' ); -} \ No newline at end of file +} diff --git a/barre_outils/forum.php b/barre_outils/forum.php index 7c2fec8..a23d706 100644 --- a/barre_outils/forum.php +++ b/barre_outils/forum.php @@ -47,4 +47,4 @@ function barre_outils_forum() { )); return $barre; -} \ No newline at end of file +} diff --git a/porte_plume_fonctions.php b/porte_plume_fonctions.php index 1bd5c5f..137799a 100644 --- a/porte_plume_fonctions.php +++ b/porte_plume_fonctions.php @@ -1,906 +1,906 @@ -false, 'replaceWith'=>"\n_ ") - * @var array - */ - public $onShiftEnter = array(); - - /** - * Option de markitup : que faire sur l'appuie de Control+Entrée ? - * - * @var array - */ - public $onCtrlEnter = array(); - - /** - * Option de markitup : que faire sur l'appuie d'une tabulation ? - * - * @var array - */ - public $onTab = array(); - - /** - * Option de markitup : Code JS à exécuter avant une insertion - * - * @var string - */ - public $beforeInsert = ""; - - /** - * Option de markitup : Code JS à exécuter après une insertion - * - * @var string - */ - public $afterInsert = ""; - - /** - * Description des outils/boutons et leurs sous boutons éventuels - * - * @var array - */ - public $markupSet = array(); - - /** - * Fonctions JS supplémentaires à écrire après la déclaration JSON - * des outils. Ces fonctions peuvent servir aux boutons. - * - * @var string - */ - public $functions = ""; - - /** - * Liste des paramètres valides pour une description d'outils (markupSet) - * - * @var array - */ - private $_liste_params_autorises = array( - - 'replaceWith', - 'openWith', - 'closeWith', - 'openBlockWith', - // sur multiline, avant les lignes selectionnees - 'closeBlockWith', - // sur multiline, apres les lignes selectionnees - 'placeHolder', - // remplace par ce texte lorsqu'il n'y a pas de selection - - 'beforeInsert', - // avant l'insertion - 'afterInsert', - // apres l'insertion - 'beforeMultiInsert', - 'afterMultiInsert', - - 'dropMenu', - // appelle un sous menu - - 'name', - // nom affiche au survol - 'key', - // raccourcis clavier - 'className', - // classe css utilisee - 'lang', - // langues dont le bouton doit apparaitre - array - 'lang_not', - // langues dont le bouton ne doit pas apparaitre - array - 'selectionType', - // '','word','line' : type de selection (normale, aux mots les plus proches, a la ligne la plus proche) - 'multiline', - // open/close sur chaque ligne (mais replace est applique sur l'ensemble de la selection) - 'forceMultiline', - // pour faire comme si on faisait systematiquement un control+shift (et replace est applique sur chaque ligne de la selection) - - 'separator', - - 'call', - 'keepDefault', - - // cacher ou afficher facilement des boutons - 'display', - // donner un identifiant unique au bouton (pour le php) - 'id', - ); - - /** - * Constructeur - * - * Initialise la barre avec les paramètres transmis - * en n'adressant que les paramètres effectivement valides - * - * @api - * @param array $params Paramètres de la barre d'outil - * @return void - */ - function __construct($params = array()) { - foreach ($params as $p => $v) { - if (isset($this->$p)) { - // si tableau, on verifie les entrees - if (is_array($v)) { - $v = $this->verif_params($p, $v); - } - $this->$p = $v; - } - } - } - - - /** - * Vérifie que les paramètres d'une clé existent - * et retourne un tableau des paramètres valides - * - * @param string $nom - * Clé à vérifier (ex: 'markupSet') - * @param array $params - * Paramètres de cette clé (description des boutons ou sous boutons) - * @return array - * Paramètres, soustrait de ceux qui ne sont pas valides - */ - function verif_params($nom, $params = array()) { - // si markupset, on boucle sur les items - if (stripos($nom, 'markupSet') !== false) { - foreach ($params as $i => $v) { - $params[$i] = $this->verif_params($i, $v); - } - } // sinon on teste la validite - else { - foreach ($params as $p => $v) { - if (!in_array($p, $this->_liste_params_autorises)) { - unset($params[$p]); - } - } - } - - return $params; - } - - /** - * Permet d'affecter des paramètres à un élément de la barre - * - * La fonction retourne les paramètres, de sorte qu'on peut s'en servir - * pour simplement récupérer ceux-ci. - * - * Il est possible d'affecter des paramètres avant/après l'élément trouvé - * en definisant une valeur différente pour le $lieu : 'dedans','avant','apres' - * par defaut 'dedans' (modifie l'élément trouvé). - * - * Lorsqu'on demande d'insérer avant ou après, la fonction retourne - * les paramètres inserés - * - * @param array $tableau - * Tableau ou chercher les elements (sert pour la recursion) - * @param string $identifiant - * Identifiant du bouton a afficher - * @param array $params - * Paramètres à affecter à la trouvaille (ou avant ou après). - * Peut être un tableau clé/valeur ou un tableau de tableaux - * clé/valeur (sauf pour $lieu = dedans) - * @param string $lieu - * Lieu d'affectation des paramètres (dedans, avant, apres) - * @param bool $plusieurs - * Définit si $params est une forme simple (tableau cle/valeur) - * ou comporte plusieurs boutons (tableau de tableaux cle/valeur). - * @return array|bool - * Paramètres de l'élément modifié ou paramètres ajoutés - * False si l'identifiant cherché n'est pas trouvé - */ - function affecter(&$tableau, $identifiant, $params = array(), $lieu = 'dedans', $plusieurs = false) { - static $cle_de_recherche = 'id'; // ou className ? - - if ($tableau === null) // utile ? - { - $tableau = &$this->markupSet; - } - - if (!in_array($lieu, array('dedans', 'avant', 'apres'))) { - $lieu = 'dedans'; - } - - // present en premiere ligne ? - $trouve = false; - foreach ($tableau as $i => $v) { - if (isset($v[$cle_de_recherche]) and ($v[$cle_de_recherche] == $identifiant)) { - $trouve = $i; - break; - } - } - // si trouve, affectations - if (($trouve !== false)) { - if ($params) { - // verifier que les insertions sont correctes - $les_params = ($plusieurs ? $params : array($params)); - foreach ($les_params as $i => $un_params) { - $les_params[$i] = $this->verif_params($identifiant, $un_params); - } - - // dedans on merge ($params uniquement tableau cle/valeur) - if ($lieu == 'dedans' && !$plusieurs) { - return $tableau[$trouve] = array_merge($tableau[$trouve], $les_params[0]); - } // avant ou apres, on insere ($params peut etre tableau cle/valeur ou tableau de tableaux cle/valeur) - elseif ($lieu == 'avant') { - array_splice($tableau, $trouve, 0, $les_params); - - return $params; - } elseif ($lieu == 'apres') { - array_splice($tableau, $trouve+1, 0, $les_params); - - return $params; - } - } - - return $tableau[$trouve]; - } - - // recursivons sinon ! - foreach ($tableau as $i => $v) { - if (is_array($v)) { - foreach ($v as $m => $n) { - if (is_array($n) AND ($r = $this->affecter($tableau[$i][$m], $identifiant, $params, $lieu, $plusieurs))) { - return $r; - } - } - } - } - - return false; - } - - - /** - * Permet d'affecter des paramètres à tous les éléments de la barre - * ou à une liste d'identifiants d'éléments indiqués. - * - * @param array $tableau - * Tableau où chercher les éléments - * @param array $params - * Paramètres à affecter aux éléments - * @param array $ids - * Tableau d'identifiants particuliers à qui on affecte les paramètres. - * Si vide, tous les identifiants seront modifiés - * @return bool - * false si aucun paramètre à affecter, true sinon. - */ - function affecter_a_tous(&$tableau, $params = array(), $ids = array()) { - if (!$params) { - return false; - } - - if ($tableau === null) { - $tableau = &$this->markupSet; - } - - $params = $this->verif_params('divers', $params); - - // merge de premiere ligne - foreach ($tableau as $i => &$v) { - if (!$ids OR in_array($v['id'], $ids)) { - $tableau[$i] = array_merge($tableau[$i], $params); - } - // recursion si sous-menu - if (isset($tableau[$i]['dropMenu'])) { - $this->affecter_a_tous($tableau[$i]['dropMenu'], $params, $ids); - } - } - - return true; - } - - - /** - * Affecte les valeurs des paramètres indiqués au bouton demandé - * et retourne l'ensemble des paramètres du bouton (sinon false) - * - * @api - * @param string|array $identifiant - * Identifiant du ou des boutons. - * @param array $params - * Paramètres de l'ajout (tableau paramètre=>valeur) - * @return bool|array - * false si l'identifiant n'a pas été trouvé - * true si plusieurs identifiants, - * array sinon : description de l'identifiant cherché. - */ - function set($identifiant, $params = array()) { - // prudence tout de meme a pas tout modifier involontairement (si array) - if (!$identifiant) { - return false; - } - - if (is_string($identifiant)) { - return $this->affecter($this->markupSet, $identifiant, $params); - } elseif (is_array($identifiant)) { - return $this->affecter_a_tous($this->markupSet, $params, $identifiant); - } - - return false; - } - - /** - * Retourne les parametres du bouton demande - * - * @api - * @param string|array $identifiant - * Identifiant du ou des boutons. - * @return bool|array - * false si l'identifiant n'est pas trouvé - * array sinon : Description de l'identifiant cherché. - */ - function get($identifiant) { - if ($a = $this->affecter($this->markupSet, $identifiant)) { - return $a; - } - - return false; - } - - - /** - * Affiche le ou les boutons demandés - * - * @api - * @param string|array $identifiant - * Identifiant du ou des boutons - * @return bool|array - * false si l'identifiant n'a pas été trouvé - * true si plusieurs identifiants, - * array sinon : description de l'identifiant cherché. - */ - function afficher($identifiant) { - return $this->set($identifiant, array('display' => true)); - } - - - /** - * Cache le ou les boutons demandés - * - * @api - * @param string|array $identifiant - * Identifiant du ou des boutons - * @return bool|array - * false si l'identifiant n'a pas été trouvé - * true si plusieurs identifiants, - * array sinon : description de l'identifiant cherché. - */ - function cacher($identifiant) { - return $this->set($identifiant, array('display' => false)); - } - - - /** - * Affiche tous les boutons - * - * @api - * @return bool - * false si aucun paramètre à affecter, true sinon. - */ - function afficherTout() { - return $this->affecter_a_tous($this->markupSet, array('display' => true)); - } - - /** - * Cache tous les boutons - * - * @api - * @return bool - * false si aucun paramètre à affecter, true sinon. - */ - function cacherTout() { - return $this->affecter_a_tous($this->markupSet, array('display' => false)); - } - - - /** - * Ajoute un bouton ou quelque chose, avant un autre déjà présent - * - * @api - * @param string $identifiant - * Identifiant du bouton où l'on doit se situer - * @param array $params - * Paramètres de l'ajout. - * Description d'un bouton (tableau clé/valeurs). - * @return array|bool - * Paramètres ajoutés avant - * False si l'identifiant cherché n'est pas trouvé - */ - function ajouterAvant($identifiant, $params) { - return $this->affecter($this->markupSet, $identifiant, $params, 'avant'); - } - - /** - * Ajoute plusieurs boutons, avant un autre déjà présent - * - * @api - * @param string $identifiant - * Identifiant du bouton où l'on doit se situer - * @param array $tableau_params - * Paramètres de l'ajout. - * Description de plusieurs boutons (tableau de tableaux clé/valeurs). - * @return array|bool - * Paramètres ajoutés avant - * False si l'identifiant cherché n'est pas trouvé - */ - function ajouterPlusieursAvant($identifiant, $tableau_params) { - return $this->affecter($this->markupSet, $identifiant, $tableau_params, 'avant', true); - } - - /** - * Ajoute un bouton ou quelque chose, après un autre déjà présent - * - * @api - * @param string $identifiant - * Identifiant du bouton où l'on doit se situer - * @param array $params - * Paramètres de l'ajout. - * Description d'un bouton (tableau clé/valeurs). - * @return array|bool - * Paramètres ajoutés après - * False si l'identifiant cherché n'est pas trouvé - */ - function ajouterApres($identifiant, $params) { - return $this->affecter($this->markupSet, $identifiant, $params, 'apres'); - } - - /** - * Ajoute plusieurs boutons, après un autre déjà présent - * - * @api - * @param string $identifiant - * Identifiant du bouton où l'on doit se situer - * @param array $tableau_params - * Paramètres de l'ajout. - * Description de plusieurs boutons (tableau de tableaux clé/valeurs). - * @return array|bool - * Paramètres ajoutés après - * False si l'identifiant cherché n'est pas trouvé - */ - function ajouterPlusieursApres($identifiant, $tableau_params) { - return $this->affecter($this->markupSet, $identifiant, $tableau_params, 'apres', true); - } - - /** - * Ajoute une fonction JS qui pourra être utilisée par les boutons - * - * @api - * @param string $fonction Code de la fonction JS - * @return void - */ - function ajouterFonction($fonction) { - if (false === strpos($this->functions, $fonction)) { - $this->functions .= "\n" . $fonction . "\n"; - } - } - - /** - * Supprimer les éléments non affichés (display:false) - * Et les séparateurs (li vides) selon la configuration - * - * @param array $tableau Tableau de description des outils - * @return void - */ - function enlever_elements_non_affiches(&$tableau) { - if ($tableau === null) { // utile ? - $tableau = &$this->markupSet; - } - - foreach ($tableau as $p => &$v) { - if (isset($v['display']) AND !$v['display']) { - unset($tableau[$p]); - $tableau = array_values($tableau); // remettre les cles automatiques sinon json les affiche et ça plante. - } // sinon, on lance une recursion sur les sous-menus - else { - if (isset($v['dropMenu']) and is_array($v['dropMenu'])) { - $this->enlever_elements_non_affiches($tableau[$p]['dropMenu']); - // si le sous-menu est vide - // on enleve le sous menu. - // mais pas le parent ($tableau[$p]), qui peut effectuer une action. - if (empty($tableau[$p]['dropMenu'])) { - unset($tableau[$p]['dropMenu']); - } - } - } - } - } - - /** - * Enlève les séparateurs pour améliorer l'accessibilité - * au détriment du stylage possible de ces séparateurs. - * - * Le bouton précédent le séparateur reçoit une classe CSS 'separateur_avant' - * Celui apres 'separateur_apres' - * - * @param array $tableau - * Tableau de description des outils - * @return void - **/ - function enlever_separateurs(&$tableau) { - if ($tableau === null) { // utile ? - $tableau = &$this->markupSet; - } - - - foreach ($tableau as $p => &$v) { - if (isset($v['separator']) and $v['separator']) { - if (isset($tableau[$p-1])) { - if (!isset($tableau[$p-1]['className'])) { - $tableau[$p-1]['className'] = ""; - } - $tableau[$p-1]['className'] .= " separateur_avant"; - } - if (isset($tableau[$p+1])) { - if (!isset($tableau[$p+1]['className'])) { - $tableau[$p+1]['className'] = ""; - } - $tableau[$p+1]['className'] .= " separateur separateur_apres $v[id]"; - } - unset($tableau[$p]); - $tableau = array_values($tableau); // remettre les cles automatiques sinon json les affiche et ça plante. - } // sinon, on lance une recursion sur les sous-menus - else { - if (isset($v['dropMenu']) and is_array($v['dropMenu'])) { - #$this->enlever_separateurs($tableau[$p]['dropMenu']); - } - } - } - } - - /** - * Supprime les éléments vides (uniquement à la racine de l'objet) - * et uniquement si chaîne ou tableau. - * - * Supprime les paramètres privés - * Supprime les paramètres inutiles a markitup/json dans les paramètres markupSet - * (id, display, icone) - */ - function enlever_parametres_inutiles() { - foreach ($this as $p => $v) { - if (!$v) { - if (is_array($v) or is_string($v)) { - unset($this->$p); - } - } elseif ($p == 'functions') { - unset($this->$p); - } - } - foreach ($this->markupSet as $p => $v) { - foreach ($v as $n => $m) { - if (in_array($n, array('id', 'display'))) { - unset($this->markupSet[$p][$n]); - } - } - } - unset ($this->_liste_params_autorises); - } - - - /** - * Crée la sortie json pour le javascript des paramètres de la barre - * - * @return string Déclaration json de la barre - */ - function creer_json() { - $barre = $this; - $type = $barre->nameSpace; - $fonctions = $barre->functions; - - $barre->enlever_elements_non_affiches($this->markupSet); - $barre->enlever_separateurs($this->markupSet); - $barre->enlever_parametres_inutiles(); - - $json = Barre_outils::json_export($barre); - - // on lance la transformation des &chose; en veritables caracteres - // sinon markitup restitue « au lieu de « directement - // lorsqu'on clique sur l'icone - include_spip('inc/charsets'); - $json = unicode2charset(html2unicode($json)); - - return "\n\nbarre_outils_$type = " . $json . "\n\n $fonctions"; - } - - /** - * Transforme une variable PHP dans un équivalent javascript (json) - * - * Copié depuis ecrire/inc/json, mais modifié pour que les fonctions - * JavaScript ne soient pas encapsulées dans une chaîne (string) - * - * @access private - * @param mixed $var the variable - * @return string|boolean - * - string : js script - * - boolean false if error - */ - function json_export($var) { - $asso = false; - switch (true) { - case is_null($var) : - return 'null'; - case is_string($var) : - if (strtolower(substr(ltrim($var), 0, 8)) == 'function') { - return $var; - } - - return '"' . addcslashes($var, "\"\\\n\r") . '"'; - case is_bool($var) : - return $var ? 'true' : 'false'; - case is_scalar($var) : - return $var; - case is_object($var) : - $var = get_object_vars($var); - $asso = true; - case is_array($var) : - $keys = array_keys($var); - $ikey = count($keys); - while (!$asso && $ikey--) { - $asso = $ikey !== $keys[$ikey]; - } - $sep = ''; - if ($asso) { - $ret = '{'; - foreach ($var as $key => $elt) { - $ret .= $sep . '"' . $key . '":' . Barre_outils::json_export($elt); - $sep = ','; - } - - return $ret . "}\n"; - } else { - $ret = '['; - foreach ($var as $elt) { - $ret .= $sep . Barre_outils::json_export($elt); - $sep = ','; - } - - return $ret . "]\n"; - } - } - - return false; - } - -} - - -/** - * Crée le code CSS pour les images des icones des barres d'outils - * - * S'appuie sur la description des jeux de barres disponibles et cherche - * une fonction barre_outils_($barre)_icones pour chaque barre et - * l'exécute si existe, attendant alors en retour un tableau de couples : - * nom de l'outil => nom de l'image - * - * @pipeline_appel porte_plume_lien_classe_vers_icone - * - * @return string Déclaration CSS des icones - */ -function barre_outils_css_icones() { - // recuperer la liste, extraire les icones - $css = ""; - - // liste des barres - if (!$barres = barre_outils_liste()) { - return null; - } - - // liste des classes css et leur correspondance avec une icone - $classe2icone = array(); - foreach ($barres as $barre) { - include_spip('barre_outils/' . $barre); - if ($f = charger_fonction($barre . '_icones', 'barre_outils', true)) { - if (is_array($icones = $f())) { - $classe2icone = array_merge($classe2icone, $icones); - } - } - } - - /** - * Permettre aux plugins d'étendre les icones connues du porte plume - * - * On passe la liste des icones connues au pipeline pour ceux qui - * ajoutent de simples icones à des barres existantes - * - * @pipeline_appel porte_plume_lien_classe_vers_icone - * @var array $classe2icone - * Couples identifiant de bouton => nom de l'image (ou tableau) - * Dans le cas d'un tableau, cela indique une sprite : (nom de l'image , position haut, position bas) - * Exemple : 'outil_header1' => array('spt-v1.png','-10px -226px') - */ - $classe2icone = pipeline('porte_plume_lien_classe_vers_icone', $classe2icone); - - // passage en css - foreach ($classe2icone as $n => $i) { - $pos = ""; - if (is_array($i)) { - $pos = "background-position:" . end($i); - $i = reset($i); - } - if (file_exists($i)) { - $file = $i; - } else { - $file = find_in_path("icones_barre/$i"); - } - if ($file) { - $css .= "\n.markItUp .$n>a>em {background-image:url(" . protocole_implicite(url_absolue($file)) . ");$pos}"; - } - } - - return $css; -} - - -/** - * Retourne une instance de Barre_outils - * crée à partir du type de barre demandé - * - * Une fonction barre_outils_{type}_dist() retournant la barre doit - * donc exister. - * - * @param string $set - * Type de barre (ex: 'edition') - * @return Barre_Outils|bool - * La barre d'outil si la fonction a été trouvée, false sinon - */ -function barre_outils_initialiser($set) { - if ($f = charger_fonction($set, 'barre_outils')) { - // retourne une instance de l'objet Barre_outils - return $f(); - } - - return false; -} - -/** - * Retourne la liste des barres d'outils connues - * - * @return array|bool - * Tableau des noms de barres d'outils trouvées - * False si on ne trouve aucune barre. - */ -function barre_outils_liste() { - static $sets = -1; - if ($sets !== -1) { - return $sets; - } - - // on recupere l'ensemble des barres d'outils connues - if (!$sets = find_all_in_path('barre_outils/', '.*[.]php') - or !is_array($sets) - ) { - spip_log("[Scandale] Porte Plume ne trouve pas de barre d'outils !"); - $sets = false; - - return $sets; - } - - foreach ($sets as $fichier => $adresse) { - $sets[$fichier] = substr($fichier, 0, -4); // juste le nom - } - - return $sets; -} - -/** - * Filtre appliquant les traitements SPIP d'un champ - * - * Applique les filtres prévus sur un champ (et eventuellement un type d'objet) - * sur un texte donné. Sécurise aussi le texte en appliquant safehtml(). - * - * Ce mécanisme est à préférer au traditionnel #TEXTE*|propre - * - * traitements_previsu() consulte la globale $table_des_traitements et - * applique le traitement adequat. Si aucun traitement n'est trouvé, - * alors propre() est appliqué. - * - * @package SPIP\PortePlume\Fonctions - * @see champs_traitements() dans public/references.php - * @global table_des_traitements - * - * @param string $texte - * Texte source - * @param string $nom_champ - * Nom du champ (nom de la balise, en majuscules) - * @param string $type_objet - * L'objet a qui appartient le champ (en minuscules) - * @param string $connect - * Nom du connecteur de base de données - * @return string - * Texte traité avec les filtres déclarés pour le champ. - */ -function traitements_previsu($texte, $nom_champ = '', $type_objet = '', $connect = null) { - include_spip('public/interfaces'); // charger les traitements - - global $table_des_traitements; - if (!strlen($nom_champ) || !isset($table_des_traitements[$nom_champ])) { - $texte = propre($texte, $connect); - } else { - include_spip('base/abstract_sql'); - $table = table_objet($type_objet); - $ps = $table_des_traitements[$nom_champ]; - if (is_array($ps)) { - $ps = $ps[(strlen($table) && isset($ps[$table])) ? $table : 0]; - } - if (!$ps) { - $texte = propre($texte, $connect); - } else { - // [FIXME] Éviter une notice sur le eval suivant qui ne connait - // pas la Pile ici. C'est pas tres joli... - $Pile = array(0 => array()); - // remplacer le placeholder %s par le texte fourni - eval('$texte=' . str_replace('%s', '$texte', $ps) . ';'); - } - } - // il faut toujours securiser le texte prévisualisé car il peut contenir n'importe quoi - // et servir de support a une attaque xss ou vol de cookie admin - // on ne peut donc se fier au statut de l'auteur connecté car le contenu ne vient pas - // forcément de lui - return safehtml($texte); -} +false, 'replaceWith'=>"\n_ ") + * @var array + */ + public $onShiftEnter = array(); + + /** + * Option de markitup : que faire sur l'appuie de Control+Entrée ? + * + * @var array + */ + public $onCtrlEnter = array(); + + /** + * Option de markitup : que faire sur l'appuie d'une tabulation ? + * + * @var array + */ + public $onTab = array(); + + /** + * Option de markitup : Code JS à exécuter avant une insertion + * + * @var string + */ + public $beforeInsert = ""; + + /** + * Option de markitup : Code JS à exécuter après une insertion + * + * @var string + */ + public $afterInsert = ""; + + /** + * Description des outils/boutons et leurs sous boutons éventuels + * + * @var array + */ + public $markupSet = array(); + + /** + * Fonctions JS supplémentaires à écrire après la déclaration JSON + * des outils. Ces fonctions peuvent servir aux boutons. + * + * @var string + */ + public $functions = ""; + + /** + * Liste des paramètres valides pour une description d'outils (markupSet) + * + * @var array + */ + private $_liste_params_autorises = array( + + 'replaceWith', + 'openWith', + 'closeWith', + 'openBlockWith', + // sur multiline, avant les lignes selectionnees + 'closeBlockWith', + // sur multiline, apres les lignes selectionnees + 'placeHolder', + // remplace par ce texte lorsqu'il n'y a pas de selection + + 'beforeInsert', + // avant l'insertion + 'afterInsert', + // apres l'insertion + 'beforeMultiInsert', + 'afterMultiInsert', + + 'dropMenu', + // appelle un sous menu + + 'name', + // nom affiche au survol + 'key', + // raccourcis clavier + 'className', + // classe css utilisee + 'lang', + // langues dont le bouton doit apparaitre - array + 'lang_not', + // langues dont le bouton ne doit pas apparaitre - array + 'selectionType', + // '','word','line' : type de selection (normale, aux mots les plus proches, a la ligne la plus proche) + 'multiline', + // open/close sur chaque ligne (mais replace est applique sur l'ensemble de la selection) + 'forceMultiline', + // pour faire comme si on faisait systematiquement un control+shift (et replace est applique sur chaque ligne de la selection) + + 'separator', + + 'call', + 'keepDefault', + + // cacher ou afficher facilement des boutons + 'display', + // donner un identifiant unique au bouton (pour le php) + 'id', + ); + + /** + * Constructeur + * + * Initialise la barre avec les paramètres transmis + * en n'adressant que les paramètres effectivement valides + * + * @api + * @param array $params Paramètres de la barre d'outil + * @return void + */ + public function __construct($params = array()) { + foreach ($params as $p => $v) { + if (isset($this->$p)) { + // si tableau, on verifie les entrees + if (is_array($v)) { + $v = $this->verif_params($p, $v); + } + $this->$p = $v; + } + } + } + + + /** + * Vérifie que les paramètres d'une clé existent + * et retourne un tableau des paramètres valides + * + * @param string $nom + * Clé à vérifier (ex: 'markupSet') + * @param array $params + * Paramètres de cette clé (description des boutons ou sous boutons) + * @return array + * Paramètres, soustrait de ceux qui ne sont pas valides + */ + public function verif_params($nom, $params = array()) { + // si markupset, on boucle sur les items + if (stripos($nom, 'markupSet') !== false) { + foreach ($params as $i => $v) { + $params[$i] = $this->verif_params($i, $v); + } + } // sinon on teste la validite + else { + foreach ($params as $p => $v) { + if (!in_array($p, $this->_liste_params_autorises)) { + unset($params[$p]); + } + } + } + + return $params; + } + + /** + * Permet d'affecter des paramètres à un élément de la barre + * + * La fonction retourne les paramètres, de sorte qu'on peut s'en servir + * pour simplement récupérer ceux-ci. + * + * Il est possible d'affecter des paramètres avant/après l'élément trouvé + * en definisant une valeur différente pour le $lieu : 'dedans','avant','apres' + * par defaut 'dedans' (modifie l'élément trouvé). + * + * Lorsqu'on demande d'insérer avant ou après, la fonction retourne + * les paramètres inserés + * + * @param array $tableau + * Tableau ou chercher les elements (sert pour la recursion) + * @param string $identifiant + * Identifiant du bouton a afficher + * @param array $params + * Paramètres à affecter à la trouvaille (ou avant ou après). + * Peut être un tableau clé/valeur ou un tableau de tableaux + * clé/valeur (sauf pour $lieu = dedans) + * @param string $lieu + * Lieu d'affectation des paramètres (dedans, avant, apres) + * @param bool $plusieurs + * Définit si $params est une forme simple (tableau cle/valeur) + * ou comporte plusieurs boutons (tableau de tableaux cle/valeur). + * @return array|bool + * Paramètres de l'élément modifié ou paramètres ajoutés + * False si l'identifiant cherché n'est pas trouvé + */ + public function affecter(&$tableau, $identifiant, $params = array(), $lieu = 'dedans', $plusieurs = false) { + static $cle_de_recherche = 'id'; // ou className ? + + if ($tableau === null) // utile ? + { + $tableau = &$this->markupSet; + } + + if (!in_array($lieu, array('dedans', 'avant', 'apres'))) { + $lieu = 'dedans'; + } + + // present en premiere ligne ? + $trouve = false; + foreach ($tableau as $i => $v) { + if (isset($v[$cle_de_recherche]) and ($v[$cle_de_recherche] == $identifiant)) { + $trouve = $i; + break; + } + } + // si trouve, affectations + if (($trouve !== false)) { + if ($params) { + // verifier que les insertions sont correctes + $les_params = ($plusieurs ? $params : array($params)); + foreach ($les_params as $i => $un_params) { + $les_params[$i] = $this->verif_params($identifiant, $un_params); + } + + // dedans on merge ($params uniquement tableau cle/valeur) + if ($lieu == 'dedans' && !$plusieurs) { + return $tableau[$trouve] = array_merge($tableau[$trouve], $les_params[0]); + } // avant ou apres, on insere ($params peut etre tableau cle/valeur ou tableau de tableaux cle/valeur) + elseif ($lieu == 'avant') { + array_splice($tableau, $trouve, 0, $les_params); + + return $params; + } elseif ($lieu == 'apres') { + array_splice($tableau, $trouve + 1, 0, $les_params); + + return $params; + } + } + + return $tableau[$trouve]; + } + + // recursivons sinon ! + foreach ($tableau as $i => $v) { + if (is_array($v)) { + foreach ($v as $m => $n) { + if (is_array($n) and ($r = $this->affecter($tableau[$i][$m], $identifiant, $params, $lieu, $plusieurs))) { + return $r; + } + } + } + } + + return false; + } + + + /** + * Permet d'affecter des paramètres à tous les éléments de la barre + * ou à une liste d'identifiants d'éléments indiqués. + * + * @param array $tableau + * Tableau où chercher les éléments + * @param array $params + * Paramètres à affecter aux éléments + * @param array $ids + * Tableau d'identifiants particuliers à qui on affecte les paramètres. + * Si vide, tous les identifiants seront modifiés + * @return bool + * false si aucun paramètre à affecter, true sinon. + */ + public function affecter_a_tous(&$tableau, $params = array(), $ids = array()) { + if (!$params) { + return false; + } + + if ($tableau === null) { + $tableau = &$this->markupSet; + } + + $params = $this->verif_params('divers', $params); + + // merge de premiere ligne + foreach ($tableau as $i => &$v) { + if (!$ids or in_array($v['id'], $ids)) { + $tableau[$i] = array_merge($tableau[$i], $params); + } + // recursion si sous-menu + if (isset($tableau[$i]['dropMenu'])) { + $this->affecter_a_tous($tableau[$i]['dropMenu'], $params, $ids); + } + } + + return true; + } + + + /** + * Affecte les valeurs des paramètres indiqués au bouton demandé + * et retourne l'ensemble des paramètres du bouton (sinon false) + * + * @api + * @param string|array $identifiant + * Identifiant du ou des boutons. + * @param array $params + * Paramètres de l'ajout (tableau paramètre=>valeur) + * @return bool|array + * false si l'identifiant n'a pas été trouvé + * true si plusieurs identifiants, + * array sinon : description de l'identifiant cherché. + */ + public function set($identifiant, $params = array()) { + // prudence tout de meme a pas tout modifier involontairement (si array) + if (!$identifiant) { + return false; + } + + if (is_string($identifiant)) { + return $this->affecter($this->markupSet, $identifiant, $params); + } elseif (is_array($identifiant)) { + return $this->affecter_a_tous($this->markupSet, $params, $identifiant); + } + + return false; + } + + /** + * Retourne les parametres du bouton demande + * + * @api + * @param string|array $identifiant + * Identifiant du ou des boutons. + * @return bool|array + * false si l'identifiant n'est pas trouvé + * array sinon : Description de l'identifiant cherché. + */ + public function get($identifiant) { + if ($a = $this->affecter($this->markupSet, $identifiant)) { + return $a; + } + + return false; + } + + + /** + * Affiche le ou les boutons demandés + * + * @api + * @param string|array $identifiant + * Identifiant du ou des boutons + * @return bool|array + * false si l'identifiant n'a pas été trouvé + * true si plusieurs identifiants, + * array sinon : description de l'identifiant cherché. + */ + public function afficher($identifiant) { + return $this->set($identifiant, array('display' => true)); + } + + + /** + * Cache le ou les boutons demandés + * + * @api + * @param string|array $identifiant + * Identifiant du ou des boutons + * @return bool|array + * false si l'identifiant n'a pas été trouvé + * true si plusieurs identifiants, + * array sinon : description de l'identifiant cherché. + */ + public function cacher($identifiant) { + return $this->set($identifiant, array('display' => false)); + } + + + /** + * Affiche tous les boutons + * + * @api + * @return bool + * false si aucun paramètre à affecter, true sinon. + */ + public function afficherTout() { + return $this->affecter_a_tous($this->markupSet, array('display' => true)); + } + + /** + * Cache tous les boutons + * + * @api + * @return bool + * false si aucun paramètre à affecter, true sinon. + */ + public function cacherTout() { + return $this->affecter_a_tous($this->markupSet, array('display' => false)); + } + + + /** + * Ajoute un bouton ou quelque chose, avant un autre déjà présent + * + * @api + * @param string $identifiant + * Identifiant du bouton où l'on doit se situer + * @param array $params + * Paramètres de l'ajout. + * Description d'un bouton (tableau clé/valeurs). + * @return array|bool + * Paramètres ajoutés avant + * False si l'identifiant cherché n'est pas trouvé + */ + public function ajouterAvant($identifiant, $params) { + return $this->affecter($this->markupSet, $identifiant, $params, 'avant'); + } + + /** + * Ajoute plusieurs boutons, avant un autre déjà présent + * + * @api + * @param string $identifiant + * Identifiant du bouton où l'on doit se situer + * @param array $tableau_params + * Paramètres de l'ajout. + * Description de plusieurs boutons (tableau de tableaux clé/valeurs). + * @return array|bool + * Paramètres ajoutés avant + * False si l'identifiant cherché n'est pas trouvé + */ + public function ajouterPlusieursAvant($identifiant, $tableau_params) { + return $this->affecter($this->markupSet, $identifiant, $tableau_params, 'avant', true); + } + + /** + * Ajoute un bouton ou quelque chose, après un autre déjà présent + * + * @api + * @param string $identifiant + * Identifiant du bouton où l'on doit se situer + * @param array $params + * Paramètres de l'ajout. + * Description d'un bouton (tableau clé/valeurs). + * @return array|bool + * Paramètres ajoutés après + * False si l'identifiant cherché n'est pas trouvé + */ + public function ajouterApres($identifiant, $params) { + return $this->affecter($this->markupSet, $identifiant, $params, 'apres'); + } + + /** + * Ajoute plusieurs boutons, après un autre déjà présent + * + * @api + * @param string $identifiant + * Identifiant du bouton où l'on doit se situer + * @param array $tableau_params + * Paramètres de l'ajout. + * Description de plusieurs boutons (tableau de tableaux clé/valeurs). + * @return array|bool + * Paramètres ajoutés après + * False si l'identifiant cherché n'est pas trouvé + */ + public function ajouterPlusieursApres($identifiant, $tableau_params) { + return $this->affecter($this->markupSet, $identifiant, $tableau_params, 'apres', true); + } + + /** + * Ajoute une fonction JS qui pourra être utilisée par les boutons + * + * @api + * @param string $fonction Code de la fonction JS + * @return void + */ + public function ajouterFonction($fonction) { + if (false === strpos($this->functions, $fonction)) { + $this->functions .= "\n" . $fonction . "\n"; + } + } + + /** + * Supprimer les éléments non affichés (display:false) + * Et les séparateurs (li vides) selon la configuration + * + * @param array $tableau Tableau de description des outils + * @return void + */ + public function enlever_elements_non_affiches(&$tableau) { + if ($tableau === null) { // utile ? + $tableau = &$this->markupSet; + } + + foreach ($tableau as $p => &$v) { + if (isset($v['display']) and !$v['display']) { + unset($tableau[$p]); + $tableau = array_values($tableau); // remettre les cles automatiques sinon json les affiche et ça plante. + } // sinon, on lance une recursion sur les sous-menus + else { + if (isset($v['dropMenu']) and is_array($v['dropMenu'])) { + $this->enlever_elements_non_affiches($tableau[$p]['dropMenu']); + // si le sous-menu est vide + // on enleve le sous menu. + // mais pas le parent ($tableau[$p]), qui peut effectuer une action. + if (empty($tableau[$p]['dropMenu'])) { + unset($tableau[$p]['dropMenu']); + } + } + } + } + } + + /** + * Enlève les séparateurs pour améliorer l'accessibilité + * au détriment du stylage possible de ces séparateurs. + * + * Le bouton précédent le séparateur reçoit une classe CSS 'separateur_avant' + * Celui apres 'separateur_apres' + * + * @param array $tableau + * Tableau de description des outils + * @return void + **/ + public function enlever_separateurs(&$tableau) { + if ($tableau === null) { // utile ? + $tableau = &$this->markupSet; + } + + + foreach ($tableau as $p => &$v) { + if (isset($v['separator']) and $v['separator']) { + if (isset($tableau[$p - 1])) { + if (!isset($tableau[$p - 1]['className'])) { + $tableau[$p - 1]['className'] = ""; + } + $tableau[$p - 1]['className'] .= " separateur_avant"; + } + if (isset($tableau[$p + 1])) { + if (!isset($tableau[$p + 1]['className'])) { + $tableau[$p + 1]['className'] = ""; + } + $tableau[$p + 1]['className'] .= " separateur separateur_apres $v[id]"; + } + unset($tableau[$p]); + $tableau = array_values($tableau); // remettre les cles automatiques sinon json les affiche et ça plante. + } // sinon, on lance une recursion sur les sous-menus + else { + if (isset($v['dropMenu']) and is_array($v['dropMenu'])) { + #$this->enlever_separateurs($tableau[$p]['dropMenu']); + } + } + } + } + + /** + * Supprime les éléments vides (uniquement à la racine de l'objet) + * et uniquement si chaîne ou tableau. + * + * Supprime les paramètres privés + * Supprime les paramètres inutiles a markitup/json dans les paramètres markupSet + * (id, display, icone) + */ + public function enlever_parametres_inutiles() { + foreach ($this as $p => $v) { + if (!$v) { + if (is_array($v) or is_string($v)) { + unset($this->$p); + } + } elseif ($p == 'functions') { + unset($this->$p); + } + } + foreach ($this->markupSet as $p => $v) { + foreach ($v as $n => $m) { + if (in_array($n, array('id', 'display'))) { + unset($this->markupSet[$p][$n]); + } + } + } + unset($this->_liste_params_autorises); + } + + + /** + * Crée la sortie json pour le javascript des paramètres de la barre + * + * @return string Déclaration json de la barre + */ + public function creer_json() { + $barre = $this; + $type = $barre->nameSpace; + $fonctions = $barre->functions; + + $barre->enlever_elements_non_affiches($this->markupSet); + $barre->enlever_separateurs($this->markupSet); + $barre->enlever_parametres_inutiles(); + + $json = Barre_outils::json_export($barre); + + // on lance la transformation des &chose; en veritables caracteres + // sinon markitup restitue « au lieu de « directement + // lorsqu'on clique sur l'icone + include_spip('inc/charsets'); + $json = unicode2charset(html2unicode($json)); + + return "\n\nbarre_outils_$type = " . $json . "\n\n $fonctions"; + } + + /** + * Transforme une variable PHP dans un équivalent javascript (json) + * + * Copié depuis ecrire/inc/json, mais modifié pour que les fonctions + * JavaScript ne soient pas encapsulées dans une chaîne (string) + * + * @access private + * @param mixed $var the variable + * @return string|boolean + * - string : js script + * - boolean false if error + */ + public function json_export($var) { + $asso = false; + switch (true) { + case is_null($var) : + return 'null'; + case is_string($var) : + if (strtolower(substr(ltrim($var), 0, 8)) == 'function') { + return $var; + } + + return '"' . addcslashes($var, "\"\\\n\r") . '"'; + case is_bool($var) : + return $var ? 'true' : 'false'; + case is_scalar($var) : + return $var; + case is_object($var) : + $var = get_object_vars($var); + $asso = true; + case is_array($var) : + $keys = array_keys($var); + $ikey = count($keys); + while (!$asso && $ikey--) { + $asso = $ikey !== $keys[$ikey]; + } + $sep = ''; + if ($asso) { + $ret = '{'; + foreach ($var as $key => $elt) { + $ret .= $sep . '"' . $key . '":' . Barre_outils::json_export($elt); + $sep = ','; + } + + return $ret . "}\n"; + } else { + $ret = '['; + foreach ($var as $elt) { + $ret .= $sep . Barre_outils::json_export($elt); + $sep = ','; + } + + return $ret . "]\n"; + } + } + + return false; + } + +} + + +/** + * Crée le code CSS pour les images des icones des barres d'outils + * + * S'appuie sur la description des jeux de barres disponibles et cherche + * une fonction barre_outils_($barre)_icones pour chaque barre et + * l'exécute si existe, attendant alors en retour un tableau de couples : + * nom de l'outil => nom de l'image + * + * @pipeline_appel porte_plume_lien_classe_vers_icone + * + * @return string Déclaration CSS des icones + */ +function barre_outils_css_icones() { + // recuperer la liste, extraire les icones + $css = ""; + + // liste des barres + if (!$barres = barre_outils_liste()) { + return null; + } + + // liste des classes css et leur correspondance avec une icone + $classe2icone = array(); + foreach ($barres as $barre) { + include_spip('barre_outils/' . $barre); + if ($f = charger_fonction($barre . '_icones', 'barre_outils', true)) { + if (is_array($icones = $f())) { + $classe2icone = array_merge($classe2icone, $icones); + } + } + } + + /** + * Permettre aux plugins d'étendre les icones connues du porte plume + * + * On passe la liste des icones connues au pipeline pour ceux qui + * ajoutent de simples icones à des barres existantes + * + * @pipeline_appel porte_plume_lien_classe_vers_icone + * @var array $classe2icone + * Couples identifiant de bouton => nom de l'image (ou tableau) + * Dans le cas d'un tableau, cela indique une sprite : (nom de l'image , position haut, position bas) + * Exemple : 'outil_header1' => array('spt-v1.png','-10px -226px') + */ + $classe2icone = pipeline('porte_plume_lien_classe_vers_icone', $classe2icone); + + // passage en css + foreach ($classe2icone as $n => $i) { + $pos = ""; + if (is_array($i)) { + $pos = "background-position:" . end($i); + $i = reset($i); + } + if (file_exists($i)) { + $file = $i; + } else { + $file = find_in_path("icones_barre/$i"); + } + if ($file) { + $css .= "\n.markItUp .$n>a>em {background-image:url(" . protocole_implicite(url_absolue($file)) . ");$pos}"; + } + } + + return $css; +} + + +/** + * Retourne une instance de Barre_outils + * crée à partir du type de barre demandé + * + * Une fonction barre_outils_{type}_dist() retournant la barre doit + * donc exister. + * + * @param string $set + * Type de barre (ex: 'edition') + * @return Barre_Outils|bool + * La barre d'outil si la fonction a été trouvée, false sinon + */ +function barre_outils_initialiser($set) { + if ($f = charger_fonction($set, 'barre_outils')) { + // retourne une instance de l'objet Barre_outils + return $f(); + } + + return false; +} + +/** + * Retourne la liste des barres d'outils connues + * + * @return array|bool + * Tableau des noms de barres d'outils trouvées + * False si on ne trouve aucune barre. + */ +function barre_outils_liste() { + static $sets = -1; + if ($sets !== -1) { + return $sets; + } + + // on recupere l'ensemble des barres d'outils connues + if (!$sets = find_all_in_path('barre_outils/', '.*[.]php') + or !is_array($sets) + ) { + spip_log("[Scandale] Porte Plume ne trouve pas de barre d'outils !"); + $sets = false; + + return $sets; + } + + foreach ($sets as $fichier => $adresse) { + $sets[$fichier] = substr($fichier, 0, -4); // juste le nom + } + + return $sets; +} + +/** + * Filtre appliquant les traitements SPIP d'un champ + * + * Applique les filtres prévus sur un champ (et eventuellement un type d'objet) + * sur un texte donné. Sécurise aussi le texte en appliquant safehtml(). + * + * Ce mécanisme est à préférer au traditionnel #TEXTE*|propre + * + * traitements_previsu() consulte la globale $table_des_traitements et + * applique le traitement adequat. Si aucun traitement n'est trouvé, + * alors propre() est appliqué. + * + * @package SPIP\PortePlume\Fonctions + * @see champs_traitements() dans public/references.php + * @global table_des_traitements + * + * @param string $texte + * Texte source + * @param string $nom_champ + * Nom du champ (nom de la balise, en majuscules) + * @param string $type_objet + * L'objet a qui appartient le champ (en minuscules) + * @param string $connect + * Nom du connecteur de base de données + * @return string + * Texte traité avec les filtres déclarés pour le champ. + */ +function traitements_previsu($texte, $nom_champ = '', $type_objet = '', $connect = null) { + include_spip('public/interfaces'); // charger les traitements + + global $table_des_traitements; + if (!strlen($nom_champ) || !isset($table_des_traitements[$nom_champ])) { + $texte = propre($texte, $connect); + } else { + include_spip('base/abstract_sql'); + $table = table_objet($type_objet); + $ps = $table_des_traitements[$nom_champ]; + if (is_array($ps)) { + $ps = $ps[(strlen($table) && isset($ps[$table])) ? $table : 0]; + } + if (!$ps) { + $texte = propre($texte, $connect); + } else { + // [FIXME] Éviter une notice sur le eval suivant qui ne connait + // pas la Pile ici. C'est pas tres joli... + $Pile = array(0 => array()); + // remplacer le placeholder %s par le texte fourni + eval('$texte=' . str_replace('%s', '$texte', $ps) . ';'); + } + } + // il faut toujours securiser le texte prévisualisé car il peut contenir n'importe quoi + // et servir de support a une attaque xss ou vol de cookie admin + // on ne peut donc se fier au statut de l'auteur connecté car le contenu ne vient pas + // forcément de lui + return safehtml($texte); +} diff --git a/porte_plume_ieconfig.php b/porte_plume_ieconfig.php index 08fd0d1..21e517d 100644 --- a/porte_plume_ieconfig.php +++ b/porte_plume_ieconfig.php @@ -1,31 +1,31 @@ -