''); if (preg_match(_PREG_CRAYON, $class, $regs)) { list(,$nomcrayon,$type,$champ,$id) = $regs; $regs[] = $class; // A-t-on le droit de crayonner ? spip_log("autoriser('crayonner', $type, $id, NULL, array('modele'=>$champ)", 'crayons'); if (!autoriser('crayonner', $type, $id, null, array('modele'=>$champ))) { $return['$erreur'] = "$type $id: " . _U('crayons:non_autorise'); } else { // Trouver la fonction de controleur PHP à utiliser $f = charger_fonction($type.'_'.$champ, 'controleurs', true) or $f = charger_fonction($champ, 'controleurs', true) or $f = charger_fonction($type, 'controleurs', true) or $f = 'controleur_dist'; #spip_log("$type:$id:$champ controleur '$f'", 'crayons'); $f = pipeline('crayons_controleur', array( 'args' => array( 'nomcrayon' => $nomcrayon, 'type' => $type, 'champ' => $champ, 'id' => $id, 'class' => $class, ), 'data' => $f, )); list($html,$status) = $f($regs, $c); if ($status) { $return['$erreur'] = $html; } else { $return['$html'] = $html; } } } else { $return['$erreur'] = _U('crayons:donnees_mal_formatees'); } return $return; } /** * Contrôleur par défaut. * * Il recherche la présence d'un contrôleur au format html pour éditer le champ ou type de crayon demandé. * * S'il n'en trouve pas crée un contrôleur en se basant sur le type de champ dans la base de données, * mais se limite à afficher soit un 'textarea' (contrôleur texte), soit un 'input' (contrôleur ligne). * * @param array $regs * @param null $c * @return array Liste : HTML, erreur */ function controleur_dist($regs, $c = null) { list( , $nomcrayon, $type, $champ, $id, $class) = $regs; $options = array( 'class' => $class ); list($distant,$table) = distant_table($type); // Si le controleur est un squelette html, on va chercher // les champs qu'il lui faut dans la table demandee // Attention, un controleur multi-tables ne fonctionnera // que si les champs ont le meme nom dans toutes les tables // (par exemple: hyperlien est ok, mais pas nom) if (($fichier = find_in_path(($controleur = 'controleurs/' . $type . '_' . $champ) . '.html')) || ($fichier = find_in_path(($controleur = 'controleurs/' . $champ) .'.html'))) { if (!lire_fichier($fichier, $controldata)) { die('erreur lecture controleur'); } if (preg_match_all('/\bname=(["\'])#ENV\{name_(\w+)\}\1/', $controldata, $matches, PREG_PATTERN_ORDER)) { $champ = $matches[2]; } } else { $controleur = ''; } $valeur = valeur_colonne_table($type, $champ, $id); #spip_log(json_encode($valeur) ." = valeur_colonne_table($type, $champ, $id);", 'crayons'); if ($valeur === false) { return array("$type $id $champ: " . _U('crayons:pas_de_valeur'), 6); } /* if (is_scalar($valeur)) { $valeur = array($champ => $valeur); }*/ // type du crayon (a revoir quand le core aura type ses donnees) $inputAttrs = array(); if ($controleur) { $options['hauteurMini'] = 80; // base de hauteur mini $option['inmode'] = 'controleur'; $options['controleur'] = $controleur; } else { $sqltype = colonne_table($type, $champ); #spip_log("$type $champ sql : ".json_encode($sqltype), 'crayons'); $inmode = crayons_determine_input_mode($type, $champ, $sqltype); // car particulier prioritaire : si la valeur actuelle comporte des retour ligne il faut un mode texte if (preg_match(",[\n\r],", $valeur[$champ]) or ($champ == 'valeur') && ($id == 'descriptif_site')) { $inmode = 'texte'; } if ($inmode === 'texte') { // si la valeur fait plusieurs lignes on doit mettre un textarea // derogation specifique pour descriptif_site de spip_metas $options['hauteurMini'] = 80; // hauteur mini d'un textarea $option['inmode'] = 'texte'; } else { // ligne, hauteur naturelle $options['hauteurMaxi'] = 0; $option['inmode'] = 'ligne'; // c'est un nombre entier if ($sqltype['long']) { // si long est [4,3] sa longueur maxi est 8 (1234,123) if (is_array($sqltype['long'])) { if (count($sqltype['long']) == 2) { $inputAttrs['maxlength'] = $sqltype['long'][0] + 1 + $sqltype['long'][1]; } else { // on ne sait pas ce que c'est ! $inputAttrs['maxlength'] = $sqltype['long'][0]; } } else { $inputAttrs['maxlength'] = $sqltype['long']; } } } } #spip_log("$type $champ crayon : ".json_encode([$nomcrayon, $valeur, $options, $c]), 'crayons'); $crayon = new Crayon($nomcrayon, $valeur, $options, $c); $inputAttrs['style'] = implode('', $crayon->styles); #spip_log("$type $champ crayon : controleur : $controleur", 'crayons'); if (!$controleur) { $inputAttrs['style'] .= 'width:' . $crayon->largeur . 'px;' . ($crayon->hauteur ? ' height:' . $crayon->hauteur . 'px;' : ''); } $html = $controleur ? $crayon->formulaire(null, $inputAttrs) : $crayon->formulaire($option['inmode'], $inputAttrs); $status = null; return array($html,$status); } /** * Determiner le type d'input pour le crayon * heuristique automatique historique basee sur le type du champ * mais l'utilisateur peut definir une fonction personalisee par type pour ajuster champ par champ * le retour de la fonction utilisateur est ignoree si ce n'est pas ligne ou texte, et dans ce cas c'est la valeur automatique qui est prise en compte * @param string $type * @param string $champ * @param array $sqltype * @return string * texte ou ligne */ function crayons_determine_input_mode($type, $champ, $sqltype) { $inmode = 'ligne'; // autodetermination // on regarde le type tel que defini dans serial // (attention il y avait des blob dans les vieux spip) if ($sqltype && (in_array($sqltype['type'], array('mediumtext', 'longblob', 'longtext')) || (($sqltype['type'] == 'text' || $sqltype['type'] == 'blob') and in_array($champ, array('descriptif', 'bio'))))){ $inmode = 'texte'; } // si une fonction utilisateur existe pour ce type, on l'appelle if (function_exists($f = 'crayons_determine_input_mode_type_' . $type) or function_exists($f = $f . '_dist')) { $user_inmode = $f($type, $champ, $sqltype); if (in_array($user_inmode, ['ligne', 'texte'])) { $inmode = $user_inmode; } } return $inmode; } // Definition des crayons class Crayon { // le nom du crayon "type-modele-id" comme "article-introduction-237" var $name; // type, a priori une table, extrait du nom plus eventuellement base distante var $type; // table la table a crayonner var $table; // distant base distante var $distant; // modele, un champ comme "texte" ou un modele, extrait du nom var $modele; // l'identificateur dans le type, comme un numero d'article var $id; // la ou les valeurs des champs du crayon, tableau associatif champ => valeur var $texts = array(); // une cle unique pour chaque crayon demande var $key; // un md5 associe aux valeurs pour verifier et detecter si elles changent var $md5; // classe css var $class; // dimensions indicatives var $largeurMini = 170; var $largeurMaxi = 700; var $hauteurMini = 80; var $hauteurMaxi = 700; var $largeur; // le mode d'entree: texte, ligne ou controleur var $inmode = ''; // eventuellement le fond modele pour le controleur var $controleur = ''; var $styles = array(); // le constructeur du crayon // $name : son nom // $texts : tableau associatif des valeurs ou valeur unique si crayon monochamp // $options : options directes du crayon (developpement) function __construct($name, $texts = array(), $options = array(), $c = null) { $this->name = $name; list($this->type, $this->modele, $this->id) = array_pad(explode('-', $this->name, 3), 3, ''); list($this->distant,$this->table) = distant_table($this->type); if (is_scalar($texts) || is_null($texts)) { $texts = array($this->modele => $texts); } $this->texts = $texts; $this->key = strtr(uniqid('wid', true), '.', '_'); $this->md5 = $this->md5(); foreach ($options as $opt => $val) { $this->$opt = $val; } $this->dimension($c); $this->css(); } // calcul du md5 associe aux valeurs function md5() { #spip_log($this->texts, 'crayons'); return md5(serialize($this->texts)); } // dimensions indicatives function dimension($c) { // largeur du crayon $this->largeur = min(max(intval(_request('w', $c)), $this->largeurMini), $this->largeurMaxi); // hauteur maxi d'un textarea selon wh: window height $maxheight = min(max(intval(_request('wh', $c)) - 50, 400), $this->hauteurMaxi); $this->hauteur = min(max(intval(_request('h', $c)), $this->hauteurMini), $maxheight); $this->left = _request('left'); $this->top = _request('top'); $this->w = _request('w'); $this->h = _request('h'); $this->ww = _request('ww'); $this->wh = _request('wh'); } // recuperer les elements de style function css() { foreach (array('color', 'font-size', 'font-family', 'font-weight', 'line-height', 'min-height', 'text-align') as $property) { if (null !== ($p = _request($property))) { $this->styles[] = "$property:$p;"; } } $property = 'background-color'; if (!$p = _request($property) or $p == 'transparent') { $p = 'white'; } $this->styles[] = "$property:$p;"; } // formulaire standard function formulaire($contexte = array(), $inputAttrs = array()) { return $this->code() . $this->input($contexte, $inputAttrs); } // balises input type hidden d'identification du crayon function code() { return ''."\n" . ''."\n" . '' . "\n" . ''."\n" . '' ."\n" ; } /** * Fabriquer les balises des champs d'apres un modele controleurs/(type_)modele.html * * @param array $contexte * tableau (nom=>valeur) qui sera enrichi puis passe à recuperer_fond * @return string * le contenu de recuperer_fond du controleur */ function fond($contexte = array()) { include_spip('inc/filtres'); $contexte['id_' . $this->type] = $this->id; $contexte['id_' . $this->table] = $this->id; $contexte['crayon_type'] = $this->type; $contexte['crayon_modele'] = $this->modele; $contexte['lang'] = $GLOBALS['spip_lang']; $contexte['key'] = $this->key; $contexte['largeur'] = $this->largeur; $contexte['hauteur'] = $this->hauteur; $contexte['self'] = _request('self'); foreach ($this->texts as $champ => $val) { $contexte['name_' . $champ] = 'content_' . $this->key . '_' . $champ; } $contexte['style'] = join(' ', $this->styles); include_spip('public/assembler'); return recuperer_fond($this->controleur, $contexte); } /** * Fabriquer les balises du ou des champs * $attrs est un tableau (attr=>val) d'attributs communs ou pour le champs unique * * @param string|array $spec * soit un scalaire 'ligne' ou 'texte' précisant le type de balise * soit un array($champ=>array('type'=>'...', 'attrs'=>array(attributs specifique du champs))) * @return string * le html de l'input */ function input($spec = 'ligne', $attrs = array()) { if ($this->controleur) { return $this->fond($spec); } include_spip('inc/filtres'); $return = ''; foreach ($this->texts as $champ => $val) { $type = is_array($spec) ? $spec[$champ]['type'] : $spec; switch ($type) { case 'texte': $id = uniqid('wid'); $input = '\n"; break; case 'ligne': default: $input = ''."\n"; } if (is_array($spec) && isset($spec[$champ]['attrs'])) { foreach ($spec[$champ]['attrs'] as $attr => $val) { $input = inserer_attribut($input, $attr, $val); } } foreach ($attrs as $attr => $val) { $input = inserer_attribut($input, $attr, $val); } // petit truc crado pour mettre la barre typo si demandee // pour faire propre il faudra reprogrammer la bt en jquery $meta_crayon = isset($GLOBALS['meta']['crayons']) ? unserialize($GLOBALS['meta']['crayons']) : array(); if (isset($meta_crayon['barretypo']) and $meta_crayon['barretypo'] and $type == 'texte') { // Pas la peine de mettre cette barre si PortePlume est la if (!( function_exists('chercher_filtre') and $f = chercher_filtre('info_plugin') and $f('PORTE_PLUME', 'est_actif') ) ) { include_spip('inc/barre'); $input = "
" . (function_exists('afficher_barre') ? afficher_barre("document.getElementById('$id')") : '') . '
' . $input; } } $return .= $input; } return $return; } } /** * Fabriquer les boutons du formulaire * * @param array $boutons * Le tableau des boutons * @return string * Le html des boutons */ function crayons_boutons($boutons = array()) { $boutons['submit'] = array('ok', texte_backend(_T('bouton_enregistrer'))); $boutons['cancel'] = array('cancel', texte_backend(_T('crayons:annuler'))); $html = ''; foreach ($boutons as $bnam => $bdef) { if ($bdef) { $html .= ''; } } if ($html) { return '
'.$html.'
'; } } function crayons_formulaire($html, $action = 'crayons_store') { if (!$html) { return ''; } // on est oblige de recreer un Crayon pour connaitre la largeur du form. // Pb conceptuel a revoir $crayon = new Crayon(''); $class = ($crayon->largeur < 250 ? ' small' : ''); include_spip('inc/filtres'); return liens_absolus( '
' . '
' . $html . crayons_boutons() . '
' .'
' ); } // // Un Crayon avec une verification de code de securite // class SecureCrayon extends Crayon { function __construct($name, $text='') { parent::__construct($name, $text); } function code() { $code = parent::code(); $secu = md5($GLOBALS['meta']['alea_ephemere']. '=' . $this->name); return $code .''."\n"; } } /** * Action affichant le controleur html ou php adéquat * * on affiche le formulaire demande (controleur associe au crayon) * Si le crayon n'est pas de type "crayon", c'est un crayon etendu, qui * integre le formulaire requis à son controleur (pour avoir les boutons * du formulaire dans un controleur Draggable, par exemple, mais il y a * d'autres usages possibles) * */ function action_crayons_html_dist() { include_spip('inc/crayons'); // Utiliser la bonne langue d'environnement if (isset($GLOBALS['auteur_session']['lang']) and (!isset($GLOBALS['forcer_lang']) or !$GLOBALS['forcer_lang'] or ($GLOBALS['forcer_lang'] === 'non'))) { lang_select($GLOBALS['auteur_session']['lang']); } $return = affiche_controleur(_request('class')); if (!_request('type') or _request('type') == 'crayon') { if (!empty($return['$html'])) { $return['$html'] = crayons_formulaire($return['$html']); } } $json = trim(crayons_json_encode($return)); header('Content-Type: text/plain; charset=utf-8'); die($json); }