[SPIP] +2.1.12
[velocampus/web/www.git] / www / extensions / porte_plume / inc / barre_outils.php
diff --git a/www/extensions/porte_plume/inc/barre_outils.php b/www/extensions/porte_plume/inc/barre_outils.php
new file mode 100644 (file)
index 0000000..4d3db65
--- /dev/null
@@ -0,0 +1,591 @@
+<?php\r
+/*\r
+ * Plugin Porte Plume pour SPIP 2\r
+ * Licence GPL\r
+ * Auteur Matthieu Marcillaud\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+include_spip('public/admin'); // pour stripos()\r
+\r
+/* pour compat 2.0 (inutile a partir de  2.1) */\r
+if (version_compare($GLOBALS['spip_version_branche'],'2.1.0 dev','<')) {\r
+       include_spip('inc/layer'); // pour effacer la globale browser_caret\r
+       $GLOBALS['browser_caret']="";\r
+}\r
+\r
+/**\r
+ * La class Barre_outils est un objet contenant les differents\r
+ * parametres definissant une barre markitup\r
+ * \r
+ */\r
+class Barre_outils{\r
+       var $id = "";\r
+       var $nameSpace = "";\r
+       var $lang = "";\r
+       var $previewAutoRefresh = false;\r
+       var $previewParserPath = "";\r
+       var $onEnter = array();\r
+       var $onShiftEnter = array();\r
+       var $onCtrlEnter = array();\r
+       var $onTab = array();\r
+       var $beforeInsert = "";\r
+       var $afterInsert = "";\r
+       var $markupSet = array();\r
+       \r
+       // liste de fonctions supplementaires a mettre apres le json\r
+       var $functions = "";\r
+       \r
+       // private\r
+       var $_liste_params_autorises = array(\r
+       \r
+               'replaceWith',\r
+               'openWith',\r
+               'closeWith',\r
+               'placeHolder', // remplace par ce texte lorsqu'il n'y a pas de selection\r
+               \r
+               'beforeInsert', // avant l'insertion\r
+               'afterInsert', // apres l'insertion\r
+               'beforeMultiInsert',\r
+               'afterMultiInsert',\r
+\r
+               'dropMenu', // appelle un sous menu\r
+               \r
+               'name', // nom affiche au survol\r
+               'key', // raccourcis clavier\r
+               'className', // classe css utilisee\r
+               'lang', // langues dont le bouton doit apparaitre - array\r
+               'lang_not', // langues dont le bouton ne doit pas apparaitre - array\r
+               'selectionType', // '','word','line' : type de selection (normale, aux mots les plus proches, a la ligne la plus proche) \r
+               'forceMultiline', // pour faire comme si on faisait systematiquement un control+shift (multi ligne)\r
+               \r
+               'separator',\r
+               \r
+               'call',\r
+               'keepDefault',\r
+               \r
+               \r
+               // icon est ajoute pour eventuellement creer un jour\r
+               // la css automatiquement...\r
+               // mais ca pose des problemes la tout de suite\r
+               // car il faudrait generer une css differente des qu'un bouton change\r
+               // ce qui est assez idiot\r
+               // ou alors il faudrait que jquery mette l'icone en fond des boutons automatiquement\r
+               'icon', \r
+               \r
+               // cacher ou afficher facilement des boutons\r
+               'display',\r
+               // donner un identifiant unique au bouton (pour le php)\r
+               'id',\r
+       );\r
+       \r
+       /**\r
+        * Initialise les parametres\r
+        * @param array $params :  param->valeur\r
+        */\r
+       function Barre_outils($params=array()){\r
+               foreach ($params as $p=>$v) {\r
+                       if (isset($this->$p)) {\r
+                               // si tableau, on verifie les entrees\r
+                               if (is_array($v)) {\r
+                                       $v = $this->verif_params($p,$v);\r
+                               }\r
+                               $this->$p = $v;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Verifie que les parametres transmis existent\r
+        * et retourne un tableau des parametres valides\r
+        * \r
+        * @param string $nom : cle du parametre (eventuel)\r
+        * @param array  $params : parametres du parametre (param->valeur)\r
+        */\r
+       function verif_params($nom, $params=array()) {\r
+               // si markupset, on boucle sur les items\r
+               if (stripos($nom, 'markupSet')!==false) {\r
+                       foreach ($params as $i=>$v) {\r
+                               $params[$i] = $this->verif_params($i, $v);\r
+                       }\r
+               } \r
+               // sinon on teste la validite\r
+               else {\r
+                       foreach ($params as $p=>$v) {\r
+                               if (!in_array($p, $this->_liste_params_autorises)) {\r
+                                       unset($params[$p]);\r
+                               }\r
+                       }\r
+               }\r
+               return $params;\r
+       }\r
+       \r
+       /**\r
+        * Permet d'affecter des parametres a un element de la barre\r
+        * La fonction retourne les parametres, de sorte qu'on peut s'en servir pour simplement recuperer ceux-ci.\r
+        * \r
+        * Il est possible d'affecter des parametres avant/apres l'element trouve\r
+        * en definisant une valeur differente pour le $lieu : 'dedans','avant','apres'\r
+        * par defaut 'dedans' (modifie l'element trouve).\r
+        * \r
+        * Lorsqu'on demande d'inserer avant ou apres, la fonction retourne les parametres inseres\r
+        * \r
+        * @param string $identifiant : identifiant du bouton a afficher\r
+        * @param array $params : parametres a affecter a la trouvaille\r
+        * @param string $lieu : lieu d'affectation des parametres (dedans, avant, apres)\r
+        * @param false/array $tableau : tableau ou chercher les elements (sert pour la recursion)\r
+        */\r
+       function affecter(&$tableau, $identifiant, $params=array(), $lieu='dedans'){\r
+               static $cle_de_recherche = 'id'; // ou className ?\r
+               \r
+               if ($tableau === null)\r
+                       $tableau = &$this->markupSet;\r
+                       \r
+               if (!in_array($lieu, array('dedans','avant','apres'))) \r
+                       $lieu = 'dedans';\r
+               \r
+               // present en premiere ligne ?\r
+               $trouve = false;\r
+               foreach ($tableau as $i=>$v){\r
+                       if (isset($v[$cle_de_recherche]) and ($v[$cle_de_recherche] == $identifiant)) {\r
+                               $trouve = $i;\r
+                               break;\r
+                       }\r
+               }\r
+               // si trouve, affectations\r
+               if (($trouve !== false)) {\r
+                       if ($params) {\r
+                               $params = $this->verif_params($identifiant, $params);\r
+                               // dedans on merge\r
+                               if ($lieu == 'dedans') {\r
+                                       return $tableau[$trouve] = array_merge($tableau[$trouve], $params);\r
+                               }\r
+                               // avant ou apres, on insere\r
+                               elseif ($lieu == 'avant') {\r
+                                       array_splice($tableau, $trouve, 0, array($params));\r
+                                       return $params;\r
+                               }\r
+                               elseif ($lieu == 'apres') {\r
+                                       array_splice($tableau, $trouve+1, 0, array($params));\r
+                                       return $params;\r
+                               }\r
+                       }\r
+                       return $tableau[$trouve];\r
+               }\r
+                               \r
+               // recursivons sinon !\r
+               foreach ($tableau as $i=>$v){\r
+                       if (is_array($v)) {\r
+                               foreach ($v as $m=>$n) {\r
+                                       if (is_array($n) AND ($r = $this->affecter($tableau[$i][$m], $identifiant, $params, $lieu))) \r
+                                               return $r;\r
+                               }\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+\r
+       \r
+       /**\r
+        * Permet d'affecter des parametres toutes les elements de la barre\r
+        * \r
+        * @param array $params : parametres a affecter a la trouvaille\r
+        * @param array $ids : tableau identifiants particuliers a qui on affecte les parametres\r
+        *                     si vide, tous les identifiants seront modifies\r
+        * @param false/array $tableau : tableau ou chercher les elements (sert pour la recursion)\r
+        */\r
+       function affecter_a_tous(&$tableau, $params=array(), $ids=array()){\r
+               if (!$params)\r
+                       return false;\r
+               \r
+               if ($tableau === null)\r
+                       $tableau = &$this->markupSet;\r
+\r
+               $params = $this->verif_params('divers', $params);\r
+\r
+               // merge de premiere ligne\r
+               foreach ($tableau as $i=>$v){\r
+                       if (!$ids OR in_array($v['id'], $ids)) {\r
+                               $tableau[$i] = array_merge($tableau[$i], $params);\r
+                       }\r
+                       // recursion si sous-menu\r
+                       if (isset($tableau[$i]['dropMenu'])) {\r
+                               $this->affecter_a_tous($tableau[$i]['dropMenu'], $params, $ids);\r
+                       }\r
+               }\r
+               return true;\r
+       }\r
+       \r
+               \r
+       /**\r
+        * Affecte les valeurs des parametres indiques au bouton demande\r
+        * et retourne l'ensemble des parametres du bouton (sinon false)\r
+        * \r
+        * @param string/array $identifiant : id du ou des boutons a afficher\r
+        * @param array $params : param->valeur\r
+        * @return mixed\r
+        */\r
+       function set($identifiant, $params=array()) {\r
+               // prudence tout de meme a pas tout modifier involontairement (si array)\r
+               if (!$identifiant) return false;\r
+                       \r
+               if (is_string($identifiant)) {\r
+                       return $this->affecter($this->markupSet, $identifiant, $params);\r
+               }\r
+               elseif (is_array($identifiant)) {\r
+                       return $this->affecter_a_tous($this->markupSet, $params, $identifiant);\r
+               }\r
+               return false;           \r
+       }\r
+       \r
+       /**\r
+        * Retourne les parametres du bouton demande\r
+        * \r
+        * @param string $identifiant : nom (de la classe du) bouton\r
+        * @return mixed\r
+        */\r
+       function get($identifiant) {\r
+               if ($a = $this->affecter($this->markupSet, $identifiant)) {\r
+                       return $a;\r
+               }\r
+               return false;           \r
+       }\r
+       \r
+                               \r
+       /**\r
+        * Affiche le bouton demande\r
+        * \r
+        * @param string $identifiant : nom (de la classe du) bouton a afficher\r
+        * @return true/false\r
+        */\r
+       function afficher($identifiant){\r
+               return $this->set($identifiant,array('display'=>true));\r
+       }\r
+       \r
+               \r
+       /**\r
+        * Cache le bouton demande\r
+        * \r
+        * @param string $identifiant : nom (de la classe du) bouton a afficher\r
+        * @return true/false\r
+        */\r
+       function cacher($identifiant){\r
+               return $this->set($identifiant,array('display'=>false));\r
+       }\r
+       \r
+                               \r
+       /**\r
+        * Affiche tous les boutons\r
+        * \r
+        * @param string $identifiant : nom (de la classe du) bouton a afficher\r
+        * @return true/false\r
+        */\r
+       function afficherTout(){\r
+               return $this->affecter_a_tous($this->markupSet, array('display'=>true));\r
+       }\r
+       \r
+       /**\r
+        * Cache tous les boutons\r
+        * \r
+        * @param string $identifiant : nom (de la classe du) bouton a afficher\r
+        * @return true/false\r
+        */\r
+       function cacherTout(){\r
+               return $this->affecter_a_tous($this->markupSet, array('display'=>false));\r
+       }\r
+       \r
+\r
+       /**\r
+        * ajouter un bouton ou quelque chose, avant un autre deja present\r
+        * \r
+        * @param string $identifiant : identifiant du bouton ou l'on doit se situer\r
+        * @param array $params : parametres de l'ajout\r
+        */\r
+       function ajouterAvant($identifiant, $params){\r
+               return $this->affecter($this->markupSet, $identifiant, $params, 'avant');\r
+       }\r
+       \r
+       /**\r
+        * ajouter un bouton ou quelque chose, apres un autre deja present\r
+        * \r
+        * @param string $identifiant : identifiant du bouton ou l'on doit se situer\r
+        * @param array $params : parametres de l'ajout\r
+        */\r
+       function ajouterApres($identifiant, $params){\r
+               return $this->affecter($this->markupSet, $identifiant, $params, 'apres');\r
+               \r
+       }\r
+               \r
+       /**\r
+        * ajouter une fonction js pour etre utilises dans les boutons\r
+        * \r
+        * @param string $fonction : code de la fonction js\r
+        * @return null\r
+        */\r
+       function ajouterFonction($fonction){\r
+               if (false === strpos($this->functions, $fonction)){\r
+                       $this->functions .= "\n" . $fonction . "\n";\r
+               }\r
+       }\r
+               \r
+       /**\r
+        * Supprimer les elements non affiches (display:false)\r
+        * \r
+        * @param false/array $tableau : tableau a analyser (sert pour la recursion)\r
+        */\r
+       function enlever_elements_non_affiches(&$tableau){\r
+               if ($tableau === null)\r
+                       $tableau = &$this->markupSet;\r
+               \r
+               foreach ($tableau as $p=>$v){\r
+\r
+                       if (isset($v['display']) AND !$v['display']) {\r
+                               unset($tableau[$p]);\r
+                               $tableau = array_values($tableau); // remettre les cles automatiques sinon json les affiche et ça plante.\r
+                       }\r
+                       // sinon, on lance une recursion sur les sous-menus\r
+                       else {\r
+                               if (isset($v['dropMenu']) and is_array($v['dropMenu'])) {\r
+                                       $this->enlever_elements_non_affiches($tableau[$p]['dropMenu']);\r
+                                       // si le sous-menu est vide, on enleve l'icone\r
+                                       if (!$tableau[$p]['dropMenu']) {\r
+                                               unset($tableau[$p]);\r
+                                               $tableau = array_values($tableau);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Supprime les elements vides (uniquement a la racine de l'objet)\r
+        * et uniquement si chaine ou tableau.\r
+        * \r
+        * Supprime les parametres prives\r
+        * Supprime les parametres inutiles a markitup/json dans les parametres markupSet\r
+        * (id, display, icone)\r
+        */\r
+       function enlever_parametres_inutiles() {\r
+               foreach($this as $p=>$v){\r
+                       if (!$v) {\r
+                               if (is_array($v) or is_string($v)) {\r
+                                       unset($this->$p);\r
+                               }\r
+                       } elseif ($p == 'functions') {\r
+                               unset($this->$p);\r
+                       }\r
+               }\r
+               foreach($this->markupSet as $p=>$v) {\r
+                       foreach ($v as $n=>$m) {\r
+                               if (in_array($n, array('id', 'display', 'icon'))) {\r
+                                       unset($this->markupSet[$p][$n]);\r
+                               }\r
+                       }\r
+               }\r
+               unset ($this->_liste_params_autorises);\r
+       }\r
+       \r
+       \r
+       /**\r
+        * Cree la sortie json pour le javascript des parametres de la barre\r
+        * et la retourne\r
+        * \r
+        * @return string : declaration json de la barre\r
+        */\r
+       function creer_json(){\r
+               $barre = $this;\r
+               $type = $barre->nameSpace;\r
+               $fonctions = $barre->functions;\r
+               \r
+               $barre->enlever_elements_non_affiches($this->markupSet);\r
+               $barre->enlever_parametres_inutiles();\r
+               \r
+               $json = Barre_outils::json_export($barre);\r
+\r
+               // on lance la transformation des &chose; en veritables caracteres\r
+               // sinon markitup restitue &laquo; au lieu de « directement\r
+               // lorsqu'on clique sur l'icone\r
+               include_spip('inc/charsets');\r
+               $json = unicode2charset(html2unicode($json));\r
+               return "\n\nbarre_outils_$type = ".$json . "\n\n $fonctions";           \r
+       }\r
+       \r
+       /**\r
+        * Transform a variable into its javascript equivalent (recursive)\r
+        * (depuis ecrire/inc/json, mais modifie pour que les fonctions\r
+        * js ne soient pas mises dans un string\r
+        * \r
+        * @access private\r
+        * @param mixed the variable\r
+        * @return string js script | boolean false if error\r
+        */\r
+       function json_export($var) {\r
+               $asso = false;\r
+               switch (true) {\r
+                       case is_null($var) :\r
+                               return 'null';\r
+                       case is_string($var) :\r
+                               if (strtolower(substr(ltrim($var),0,8))=='function')\r
+                                       return $var;\r
+                               return '"' . addcslashes($var, "\"\\\n\r") . '"';\r
+                       case is_bool($var) :\r
+                               return $var ? 'true' : 'false';\r
+                       case is_scalar($var) :\r
+                               return $var;\r
+                       case is_object( $var) :\r
+                               $var = get_object_vars($var);\r
+                               $asso = true;\r
+                       case is_array($var) :\r
+                               $keys = array_keys($var);\r
+                               $ikey = count($keys);\r
+                               while (!$asso && $ikey--) {\r
+                                       $asso = $ikey !== $keys[$ikey];\r
+                               }\r
+                               $sep = '';\r
+                               if ($asso) {\r
+                                       $ret = '{';\r
+                                       foreach ($var as $key => $elt) {\r
+                                               $ret .= $sep . '"' . $key . '":' . Barre_outils::json_export($elt);\r
+                                               $sep = ',';\r
+                                       }\r
+                                       return $ret ."}\n";\r
+                               } else {\r
+                                       $ret = '[';\r
+                                       foreach ($var as $elt) {\r
+                                               $ret .= $sep . Barre_outils::json_export($elt);\r
+                                               $sep = ',';\r
+                                       }\r
+                                       return $ret ."]\n";\r
+                               }\r
+               }\r
+               return false;\r
+       }\r
+       \r
+}\r
+\r
+\r
+\r
+/**\r
+ * Cette fonction cree la css pour les images\r
+ * des icones des barres d'outils\r
+ * en s'appuyant sur la description des jeux de barres disponibles.\r
+ * \r
+ * elle cherche une fonction barre_outils_($barre)_icones pour chaque\r
+ * barre et l'appelle si existe.\r
+ * \r
+ * @return string : declaration css des icones\r
+ */\r
+function barre_outils_css_icones(){\r
+       // recuperer la liste, extraire les icones\r
+       $css = "";\r
+       \r
+       // liste des barres\r
+       if (!$barres = barre_outils_liste()) \r
+               return null;\r
+               \r
+       // liste des classes css et leur correspondance avec une icone\r
+       $classe2icone = array();\r
+       foreach ($barres as $barre) {\r
+               include_spip('barre_outils/' . $barre);\r
+               if ($f = charger_fonction($barre . '_icones', 'barre_outils', true)) {\r
+                       if (is_array($icones = $f())) {\r
+                               $classe2icone = array_merge($classe2icone, $icones);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       // passer le tout dans un pipeline pour ceux qui ajoute de simples icones a des barres existantes\r
+       $classe2icone = pipeline('porte_plume_lien_classe_vers_icone',$classe2icone);\r
+       \r
+       // passage en css\r
+       foreach ($classe2icone as $n=>$i) {\r
+               $pos="";\r
+               if (is_array($i)){\r
+                       $pos = "background-position:".end($i);\r
+                 $i = reset($i);\r
+               }\r
+               $css .= "\n.markItUp .$n a b {background-image:url(".url_absolue(find_in_path("icones_barre/$i")).");$pos}";\r
+       }\r
+\r
+       return $css;\r
+}\r
+\r
+\r
+/**\r
+ * Retourne une instance de Barre_outils\r
+ * cree a partir du type de barre demande\r
+ * \r
+ * @param string $set : type de barre\r
+ * @return object/false : objet de type barre_outil\r
+ */\r
+function barre_outils_initialiser($set){\r
+       if ($f = charger_fonction($set, 'barre_outils')) {\r
+               // retourne une instance de l'objet Barre_outils\r
+               return $f();\r
+       }\r
+       return false;\r
+}\r
+\r
+/**\r
+ * Retourne la liste des barres d'outils connues\r
+ *\r
+ * @return array/false : tableau des noms de barres trouvees\r
+ */\r
+function barre_outils_liste(){\r
+       static $sets = -1;\r
+       if ($sets !== -1) \r
+               return $sets;\r
+       \r
+       // on recupere l'ensemble des barres d'outils connues\r
+       if (!$sets = find_all_in_path('barre_outils/','.*[.]php')\r
+       or !is_array($sets)) {\r
+               spip_log("[Scandale] Porte Plume ne trouve pas de barre d'outils !");\r
+               $sets = false;\r
+               return $sets;\r
+       }\r
+               \r
+       foreach($sets as $fichier=>$adresse) {\r
+               $sets[$fichier] = substr($fichier,0,-4); // juste le nom\r
+       }\r
+       return $sets;   \r
+}\r
+\r
+/**\r
+ * filtre appliquant les traitements SPIP d'un champ (et eventuellement d'un type d'objet) sur un texte\r
+ * (voir la fonction champs_traitements($p) dans : public/references.php)\r
+ * ce mecanisme est a preferer au traditionnel #TEXTE*|propre\r
+ * traitements_previsu() consulte la globale $table_des_traitements et applique le traitement adequat\r
+ * si aucun traitement n'est trouve, alors propre() est applique\r
+ * \r
+ * @param string $texte : texte source\r
+ * @param string $nom_champ : champ (en majuscules)\r
+ * @param string $type_objet : objet (en minuscules)\r
+ * @return string : texte traite\r
+ */\r
+function traitements_previsu($texte, $nom_champ='', $type_objet='', $connect=null) {\r
+       include_spip('public/interfaces'); // charger les traitements\r
+       safehtml($t);\r
+       global $table_des_traitements;\r
+       if(!strlen($nom_champ) || !isset($table_des_traitements[$nom_champ])) {\r
+               $texte = propre($texte, $connect);\r
+       }\r
+       else {\r
+               include_spip('base/abstract_sql');\r
+               $table = table_objet($type_objet);\r
+               $ps = $table_des_traitements[$nom_champ];\r
+               if(is_array($ps))\r
+                       $ps = $ps[(strlen($table) && isset($ps[$table])) ? $table : 0];\r
+               if(!$ps)\r
+                       $texte = propre($texte, $connect);\r
+               else\r
+                       // remplacer le placeholder %s par le texte fourni\r
+                       eval('$texte=' . str_replace('%s', '$texte', $ps) . ';');\r
+       }\r
+       // il faut toujours securiser le texte preivusalise car il peut contenir n'importe quoi\r
+       // et servir de support a une attaque xss ou vol de cookie admin\r
+       // on ne peut donc se fier au statut de l'auteur connecte car le contenu ne vient pas\r
+       // forcement de lui\r
+       return safehtml($texte);\r
+}\r
+?>\r