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