[PLUGINS] +crayons
[lhc/web/clavette_www.git] / www / plugins / crayons / action / crayons_html.php
1 <?php
2 /**
3 * Crayons
4 * plugin for spip
5 * (c) Fil, toggg 2006-2013
6 * licence GPL
7 */
8
9 if (!defined("_ECRIRE_INC_VERSION")) return;
10
11 /**
12 * Affiche le controleur (formulaire) d'un crayon
13 * suivant la classe CSS décrivant le champ à éditer (produit par #EDIT)
14 *
15 * @param string $class
16 * Class CSS décrivant le champ
17 * @param null $c
18 *
19 * @return array
20 * Tableau avec 2 entrées possibles :
21 * - '$erreur' : texte d'erreur éventuel
22 * - '$html' : code HTML du controleur
23 **/
24 function affiche_controleur($class, $c=null) {
25 $return = array('$erreur'=>'');
26
27 if (preg_match(_PREG_CRAYON, $class, $regs)) {
28 list(,$nomcrayon,$type,$champ,$id) = $regs;
29 $regs[] = $class;
30
31 // A-t-on le droit de crayonner ?
32 spip_log("autoriser('crayonner', $type, $id, NULL, array('modele'=>$champ)","crayons_distant");
33 if (!autoriser('crayonner',$type, $id, NULL, array('modele'=>$champ))) {
34 $return['$erreur'] = "$type $id: " . _U('crayons:non_autorise');
35 } else {
36 $f = charger_fonction($type.'_'.$champ, 'controleurs', true)
37 OR $f = charger_fonction($champ, 'controleurs', true)
38 OR $f = charger_fonction($type, 'controleurs', true)
39 OR $f = 'controleur_dist';
40 list($html,$status) = $f($regs, $c);
41 if ($status)
42 $return['$erreur'] = $html;
43 else
44 $return['$html'] = $html;
45 }
46 } else
47 $return['$erreur'] = _U('crayons:donnees_mal_formatees');
48
49 return $return;
50 }
51
52 function controleur_dist($regs, $c=null) {
53 list( , $nomcrayon, $type, $champ, $id, $class) = $regs;
54 $options = array(
55 'class' => $class
56 );
57 list($distant,$table) = distant_table($type);
58
59 // Si le controleur est un squelette html, on va chercher
60 // les champs qu'il lui faut dans la table demandee
61 // Attention, un controleur multi-tables ne fonctionnera
62 // que si les champs ont le meme nom dans toutes les tables
63 // (par exemple: hyperlien est ok, mais pas nom)
64 if (($fichier = find_in_path(
65 ($controleur = 'controleurs/' . $type . '_' . $champ) . '.html'))
66 || ($fichier = find_in_path(
67 ($controleur = 'controleurs/' . $champ) .'.html'))) {
68 if (!lire_fichier($fichier, $controldata))
69 die('erreur lecture controleur');
70 if (preg_match_all('/\bname=(["\'])#ENV\{name_(\w+)\}\1/',
71 $controldata, $matches, PREG_PATTERN_ORDER))
72 $champ = $matches[2];
73 } else
74 $controleur = '';
75
76 $valeur = valeur_colonne_table($type, $champ, $id);
77
78 #spip_log("$valeur = valeur_colonne_table($type, $champ, $id);");
79 #spip_log($champ);
80
81 if ($valeur === false)
82 return array("$type $id $champ: " . _U('crayons:pas_de_valeur'), 6);
83 /* if (is_scalar($valeur)) {
84 $valeur = array($champ => $valeur);
85 }*/
86
87 // type du crayon (a revoir quand le core aura type ses donnees)
88 $inputAttrs = array();
89 if ($controleur) {
90 $options['hauteurMini'] = 80; // base de hauteur mini
91 $option['inmode'] = 'controleur';
92 $options['controleur'] = $controleur;
93 } else
94 // si la valeur fait plusieurs lignes on doit mettre un textarea
95 // derogation specifique pour descriptif_site de spip_metas
96 if (
97 preg_match(",[\n\r],", $valeur[$champ])
98 OR (($champ == 'valeur') && ($id == 'descriptif_site'))
99 OR
100 // on regarde le type tel que defini dans serial
101 // (attention il y avait des blob dans les vieux spip)
102 ($sqltype = colonne_table($type, $champ)) &&
103 (in_array($sqltype['type'] , array('mediumtext', 'longblob', 'longtext')) ||
104 (($sqltype['type'] == 'text' || $sqltype['type'] == 'blob')
105 && in_array($champ, array('descriptif', 'bio'))))) {
106 $options['hauteurMini'] = 80; // hauteur mini d'un textarea
107 $option['inmode'] = 'texte';
108 } else { // ligne, hauteur naturelle
109 $options['hauteurMaxi'] = 0;
110 $option['inmode'] = 'ligne';
111 // c'est un nombre entier
112 if ($sqltype['long']) {
113 // si long est [4,3] sa longueur maxi est 8 (1234,123)
114 if (is_array($sqltype['long'])) {
115 if (count($sqltype['long']) == 2) {
116 $inputAttrs['maxlength'] = $sqltype['long'][0] + 1 + $sqltype['long'][1];
117 }
118 // on ne sait pas ce que c'est !
119 else {
120 $inputAttrs['maxlength'] = $sqltype['long'][0];
121 }
122 } else {
123 $inputAttrs['maxlength'] = $sqltype['long'];
124 }
125 }
126 }
127
128 $crayon = new Crayon($nomcrayon, $valeur, $options, $c);
129 $inputAttrs['style'] = implode('',$crayon->styles);
130
131 if (!$controleur) {
132 $inputAttrs['style'] .= 'width:' . $crayon->largeur . 'px;' .
133 ($crayon->hauteur ? ' height:' . $crayon->hauteur . 'px;' : '');
134 }
135
136 $html = $controleur ? $crayon->formulaire(null, $inputAttrs) :
137 $crayon->formulaire($option['inmode'], $inputAttrs);
138 $status = NULL;
139
140 return array($html,$status);
141 }
142
143 // Definition des crayons
144 class Crayon {
145 // le nom du crayon "type-modele-id" comme "article-introduction-237"
146 var $name;
147 // type, a priori une table, extrait du nom plus eventuellement base distante
148 var $type;
149 // table la table a crayonner
150 var $table;
151 // distant base distante
152 var $distant;
153 // modele, un champ comme "texte" ou un modele, extrait du nom
154 var $modele;
155 // l'identificateur dans le type, comme un numero d'article
156 var $id;
157 // la ou les valeurs des champs du crayon, tableau associatif champ => valeur
158 var $texts = array();
159 // une cle unique pour chaque crayon demande
160 var $key;
161 // un md5 associe aux valeurs pour verifier et detecter si elles changent
162 var $md5;
163 // dimensions indicatives
164 var $largeurMini = 170;
165 var $largeurMaxi = 700;
166 var $hauteurMini = 80;
167 var $hauteurMaxi = 700;
168 var $largeur;
169 // le mode d'entree: texte, ligne ou controleur
170 var $inmode = '';
171 // eventuellement le fond modele pour le controleur
172 var $controleur = '';
173 var $styles = array();
174
175 // le constructeur du crayon
176 // $name : son nom
177 // $texts : tableau associatif des valeurs ou valeur unique si crayon monochamp
178 // $options : options directes du crayon (developpement)
179 function Crayon($name, $texts = array(), $options = array(), $c=null) {
180 $this->name = $name;
181
182 list($this->type, $this->modele, $this->id) = array_pad(explode('-', $this->name, 3), 3, '');
183 list($this->distant,$this->table) = distant_table($this->type);
184 if (is_scalar($texts) || is_null($texts)) {
185 $texts = array($this->modele => $texts);
186 }
187 $this->texts = $texts;
188 $this->key = strtr(uniqid('wid', true), '.', '_');
189 $this->md5 = $this->md5();
190 foreach ($options as $opt=>$val) {
191 $this->$opt = $val;
192 }
193 $this->dimension($c);
194 $this->css();
195 }
196
197 // calcul du md5 associe aux valeurs
198 function md5() {
199 #spip_log($this->texts, 'crayons');
200 return md5(serialize($this->texts));
201 }
202
203 // dimensions indicatives
204 function dimension($c) {
205 // largeur du crayon
206 $this->largeur = min(max(intval(_request('w', $c)),
207 $this->largeurMini), $this->largeurMaxi);
208 // hauteur maxi d'un textarea selon wh: window height
209 $maxheight = min(max(intval(_request('wh', $c)) - 50, 400), $this->hauteurMaxi);
210 $this->hauteur = min(max(intval(_request('h', $c)), $this->hauteurMini), $maxheight);
211 $this->left = _request('left');
212 $this->top = _request('top');
213 $this->w = _request('w');
214 $this->h = _request('h');
215 $this->ww = _request('ww');
216 $this->wh = _request('wh');
217 }
218
219 // recuperer les elements de style
220 function css() {
221 foreach(array('color', 'font-size', 'font-family', 'font-weight', 'line-height', 'min-height', 'text-align') as $property) {
222 if (null !== ($p = _request($property)))
223 $this->styles[] = "$property:$p;";
224 }
225
226 $property = 'background-color';
227 if (!$p = _request($property)
228 OR $p == 'transparent') {
229 $p = 'white';
230 }
231 $this->styles[] = "$property:$p;";
232 }
233
234 // formulaire standard
235 function formulaire($contexte = array(), $inputAttrs = array()) {
236 return
237 $this->code() .
238 $this->input($contexte, $inputAttrs);
239 }
240
241 // balises input type hidden d'identification du crayon
242 function code() {
243 return
244 '<input type="hidden" class="crayon-id" name="crayons[]"'
245 .' value="'.$this->key.'" />'."\n"
246 . '<input type="hidden" name="name_'.$this->key
247 .'" value="'.$this->name.'" />'."\n"
248 . '<input type="hidden" name="class_' . $this->key
249 . '" value="' . $this->class . '" />' . "\n"
250 . '<input type="hidden" name="md5_'.$this->key
251 .'" value="'.$this->md5.'" />'."\n"
252 . '<input type="hidden" name="fields_'.$this->key
253 .'" value="'.join(',',array_keys($this->texts)).'" />'
254 ."\n"
255 ;
256 }
257
258 /**
259 * Fabriquer les balises des champs d'apres un modele controleurs/(type_)modele.html
260 *
261 * @param array $contexte
262 * tableau (nom=>valeur) qui sera enrichi puis passe à recuperer_fond
263 * @return string
264 * le contenu de recuperer_fond du controleur
265 */
266 function fond($contexte = array()) {
267 include_spip('inc/filtres');
268 $contexte['id_' . $this->type] = $this->id;
269 $contexte['id_' . $this->table] = $this->id;
270 $contexte['crayon_type'] = $this->type;
271 $contexte['crayon_modele'] = $this->modele;
272 $contexte['lang'] = $GLOBALS['spip_lang'];
273 $contexte['key'] = $this->key;
274 $contexte['largeur'] = $this->largeur;
275 $contexte['hauteur'] = $this->hauteur;
276 $contexte['self'] = _request('self');
277 foreach ($this->texts as $champ => $val) {
278 $contexte['name_' . $champ] = 'content_' . $this->key . '_' . $champ;
279 }
280 $contexte['style'] = join(' ',$this->styles);
281 include_spip('public/assembler');
282 return recuperer_fond($this->controleur, $contexte);
283 }
284
285 /**
286 * Fabriquer les balises du ou des champs
287 * $attrs est un tableau (attr=>val) d'attributs communs ou pour le champs unique
288 *
289 * @param string|array $spec
290 * soit un scalaire 'ligne' ou 'texte' précisant le type de balise
291 * soit un array($champ=>array('type'=>'...', 'attrs'=>array(attributs specifique du champs)))
292 * @return string
293 * le html de l'input
294 */
295 function input($spec = 'ligne', $attrs = array()) {
296 if ($this->controleur) {
297 return $this->fond($spec);
298 }
299 include_spip('inc/filtres');
300 $return = '';
301 foreach ($this->texts as $champ => $val) {
302 $type = is_array($spec) ? $spec[$champ]['type'] : $spec;
303 switch ($type) {
304 case 'texte':
305 $id = uniqid('wid');
306 $input = '<textarea style="width:100%;" class="crayon-active"'
307 . ' name="content_'.$this->key.'_'.$champ.'" id="'.$id.'">'
308 . "\n"
309 . entites_html($val)
310 . "</textarea>\n";
311 break;
312 case 'ligne':
313 default:
314 $input = '<input class="crayon-active text" type="text"'
315 . ' name="content_'.$this->key.'_'.$champ.'"'
316 . ' value="'
317 . entites_html($val)
318 . '" />'."\n";
319 }
320
321 if (is_array($spec) && isset($spec[$champ]['attrs'])) {
322 foreach ($spec[$champ]['attrs'] as $attr=>$val) {
323 $input = inserer_attribut($input, $attr, $val);
324 }
325 }
326
327 foreach ($attrs as $attr=>$val) {
328 $input = inserer_attribut($input, $attr, $val);
329 }
330
331 // petit truc crado pour mettre la barre typo si demandee
332 // pour faire propre il faudra reprogrammer la bt en jquery
333 $meta_crayon = isset($GLOBALS['meta']['crayons']) ? unserialize($GLOBALS['meta']['crayons']) : array();
334 if (isset($meta_crayon['barretypo'])
335 AND $meta_crayon['barretypo']
336 AND $type == 'texte') {
337 // Pas la peine de mettre cette barre si PortePlume est la
338 if (
339 !(
340 function_exists('chercher_filtre')
341 AND $f = chercher_filtre('info_plugin')
342 AND $f('PORTE_PLUME','est_actif')
343 )
344 ) {
345 include_spip('inc/barre');
346 $input = "<div style='width:".$this->largeur."px;height:23px;'>"
347 . (function_exists('afficher_barre')
348 ? afficher_barre("document.getElementById('$id')")
349 : '')
350 . '</div>'
351 . $input;
352 }
353 }
354
355 $return .= $input;
356 }
357 return $return;
358 }
359 }
360
361 /**
362 * Fabriquer les boutons du formulaire
363 *
364 * @param array $boutons
365 * Le tableau des boutons
366 * @return string
367 * Le html des boutons
368 */
369 function crayons_boutons($boutons = array()) {
370 $boutons['submit'] = array('ok', texte_backend(_T('bouton_enregistrer')));
371 $boutons['cancel'] = array('cancel', texte_backend(_T('crayons:annuler')));
372
373 $html = '';
374 foreach ($boutons as $bnam => $bdef) if ($bdef) {
375 $html .= '<button type="button" class="crayon-' . $bnam .
376 '" title="' . $bdef[1] . '">' . $bdef[1] . '</button>';
377 }
378
379 if ($html)
380 return '<div class="crayon-boutons"><div>'.$html.'</div></div>';
381 }
382
383 function crayons_formulaire($html, $action='crayons_store') {
384 if (!$html)
385 return '';
386
387 // on est oblige de recreer un Crayon pour connaitre la largeur du form.
388 // Pb conceptuel a revoir
389 $crayon = new Crayon("");
390 $class = ($crayon->largeur<250?" small":"");
391
392
393 include_spip('inc/filtres');
394 return liens_absolus(
395 '<div class="formulaire_spip">'
396 . '<form class="formulaire_crayon'.$class.'" method="post" action="'
397 . url_absolue(parametre_url(self(),'action', $action))
398 . '" enctype="multipart/form-data">'
399 . $html
400 . crayons_boutons()
401 . '</form>'
402 .'</div>'
403 );
404 }
405
406 //
407 // Un Crayon avec une verification de code de securite
408 //
409 class SecureCrayon extends Crayon {
410
411 function SecureCrayon($name, $text='') {
412 parent::Crayon($name, $text);
413 }
414
415 function code() {
416 $code = parent::code();
417 $secu = md5($GLOBALS['meta']['alea_ephemere']. '=' . $this->name);
418
419 return
420 $code
421 .'<input type="hidden" name="secu_'.$this->key.'" value="'.$secu.'" />'."\n";
422 }
423 }
424
425 /**
426 * Action affichant le controleur html ou php adéquat
427 *
428 * on affiche le formulaire demande (controleur associe au crayon)
429 * Si le crayon n'est pas de type "crayon", c'est un crayon etendu, qui
430 * integre le formulaire requis à son controleur (pour avoir les boutons
431 * du formulaire dans un controleur Draggable, par exemple, mais il y a
432 * d'autres usages possibles)
433 *
434 */
435 function action_crayons_html_dist() {
436 include_spip('inc/crayons');
437
438 // Utiliser la bonne langue d'environnement
439 if(!isset($GLOBALS['forcer_lang']) OR !$GLOBALS['forcer_lang'] OR ($GLOBALS['forcer_lang'] === 'non'))
440 lang_select($GLOBALS['auteur_session']['lang']);
441
442 $return = affiche_controleur(_request('class'));
443 if (!_request('type') OR _request('type') == 'crayon')
444 $return['$html'] = crayons_formulaire($return['$html']);
445
446 $json = trim(crayons_json_encode($return));
447
448 header("Content-Type: text/plain; charset=utf-8");
449 die($json);
450 }
451
452 ?>