From: Ludovic CHEVALIER Date: Tue, 28 Apr 2015 09:34:09 +0000 (+0200) Subject: [PLUGINS] +crayons X-Git-Tag: production~8 X-Git-Url: http://git.cyclocoop.org/?p=lhc%2Fweb%2Fclavette_www.git;a=commitdiff_plain;h=39f8b2ffa1fd0a3c67d6c74ed0fee9af296ccbb8 [PLUGINS] +crayons --- diff --git a/www/plugins/crayons/action/crayons.php b/www/plugins/crayons/action/crayons.php new file mode 100644 index 0000000..bd7a7c8 --- /dev/null +++ b/www/plugins/crayons/action/crayons.php @@ -0,0 +1,33 @@ + \ No newline at end of file diff --git a/www/plugins/crayons/action/crayons_html.php b/www/plugins/crayons/action/crayons_html.php new file mode 100644 index 0000000..b9c6385 --- /dev/null +++ b/www/plugins/crayons/action/crayons_html.php @@ -0,0 +1,452 @@ +''); + + 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_distant"); + if (!autoriser('crayonner',$type, $id, NULL, array('modele'=>$champ))) { + $return['$erreur'] = "$type $id: " . _U('crayons:non_autorise'); + } else { + $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'; + 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; +} + +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("$valeur = valeur_colonne_table($type, $champ, $id);"); + #spip_log($champ); + + 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 + // si la valeur fait plusieurs lignes on doit mettre un textarea + // derogation specifique pour descriptif_site de spip_metas + if ( + preg_match(",[\n\r],", $valeur[$champ]) + OR (($champ == 'valeur') && ($id == 'descriptif_site')) + OR + // on regarde le type tel que defini dans serial + // (attention il y avait des blob dans les vieux spip) + ($sqltype = colonne_table($type, $champ)) && + (in_array($sqltype['type'] , array('mediumtext', 'longblob', 'longtext')) || + (($sqltype['type'] == 'text' || $sqltype['type'] == 'blob') + && in_array($champ, array('descriptif', 'bio'))))) { + $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]; + } + // on ne sait pas ce que c'est ! + else { + $inputAttrs['maxlength'] = $sqltype['long'][0]; + } + } else { + $inputAttrs['maxlength'] = $sqltype['long']; + } + } + } + + $crayon = new Crayon($nomcrayon, $valeur, $options, $c); + $inputAttrs['style'] = implode('',$crayon->styles); + + 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); +} + +// 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; + // 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 Crayon($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 SecureCrayon($name, $text='') { + parent::Crayon($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['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') + $return['$html'] = crayons_formulaire($return['$html']); + + $json = trim(crayons_json_encode($return)); + + header("Content-Type: text/plain; charset=utf-8"); + die($json); +} + +?> diff --git a/www/plugins/crayons/action/crayons_store.php b/www/plugins/crayons/action/crayons_store.php new file mode 100644 index 0000000..85ac161 --- /dev/null +++ b/www/plugins/crayons/action/crayons_store.php @@ -0,0 +1,534 @@ +0) + $content[$field] = $_FILES['content_'.$crayon.'_'.$field]; + else + $content[$field] = false; + // cf. valeur passee dans crayon->md5() : false ou filemtime() du logo + } else { + /** + * le changement de charset n'est plus necessaire + * depuis jquery 1.5 (feature non documentee de jquery!) + */ + if (isset($_POST['content_'.$crayon.'_'.$field])) { + $content[$field] = is_array($_POST['content_'.$crayon.'_'.$field]) + ?implode(',',$_POST['content_'.$crayon.'_'.$field]) + :$_POST['content_'.$crayon.'_'.$field]; + } else { + $content[$field] = null; + } + } + } + } + + // Si les donnees POSTees ne correspondent pas a leur md5, + // il faut les traiter + if (isset($name) + AND md5(serialize($content)) != $_POST['md5_'.$crayon]) { + if (!isset($_POST['secu_'.$crayon]) + OR verif_secu($name, $_POST['secu_'.$crayon])) { + $results[] = array($name, $content, $_POST['md5_'.$crayon], $crayon); + } + else + return false; // erreur secu + } + // cas inchange + else + $results[] = array($name, $content, false, $crayon); + } + + return $results; +} + + +function crayons_store($options = array()) { + // permettre de surcharger les fonctions de recuperation des valeurs + // et de sauvegardes de celles-ci + $options = array_merge(array( + 'f_get_valeur' => 'crayons_store_get_valeur', + 'f_set_modifs' => 'crayons_store_set_modifs', + ), $options); + + include_spip('inc/crayons'); + $wdgcfg = wdgcfg(); + + $return = array('$erreur'=>''); + + $postees = post_crayons(); + + $modifs = $updates = array(); + if (!is_array($postees)) { + $return['$erreur'] = _U('crayons:donnees_mal_formatees'); + } else { + foreach ($postees as $postee) + if ($postee[2] !== false) { + $name = $postee[0]; + $content = $postee[1]; + + if ($content && preg_match(_PREG_CRAYON, 'crayon '.$name, $regs)) { + list(,$crayon,$type,$modele,$id) = $regs; + $wid = $postee[3]; + + spip_log("autoriser('crayonner', $type, $id, NULL, array('modele'=>$modele)","crayons_distant"); + if (!autoriser('crayonner', $type, $id, NULL, array('modele'=>$modele))) { + $return['$erreur'] = + "$type $id: " . _U('crayons:non_autorise'); + } else { + + // recuperer l'existant pour calculer son md5 et verifier + // qu'il n'a pas ete modifie entre-temps + $get_valeur = $options['f_get_valeur']; + $data = $get_valeur($content, $regs); + + $md5 = md5(serialize($data)); + + // est-ce que le champ a ete modifie dans la base entre-temps ? + if ($md5 != $postee[2]) { + // si oui, la modif demandee correspond peut-etre + // a la nouvelle valeur ? dans ce cas on procede + // comme si "pas de modification", sinon erreur + if ($md5 != md5(serialize($content))) { + $return['$erreur'] = "$type $id $modele: " . + _U('crayons:modifie_par_ailleurs'); + } + } + + $modifs[] = array($type, $modele, $id, $content, $wid); + + /* aiguillage pour verification de la saisie + Pour traitement ulterieur les fonctions de verifications doivent renvoyer $invalides : + $invalides[wid_champ]['msg'] -> message de saisie invalide + $invalides[wid_champ]['retour'] -> caracteres invalides */ + $f = 'verifier_'.$type.'_'.$modele; + if (function_exists($f)) { + if (count( $invalides = $f($modifs) )) { + $return['$invalides'] = $invalides; + } + + } + } + } + } + } + + if (!$modifs AND !$return['$erreur']) { + $return['$erreur'] = $wdgcfg['msgNoChange'] ? + _U('crayons:pas_de_modification') : ' '; + $return['$annuler'] = true; + } + + // un champ invalide ... ou rien ==> on ne fait rien ! + if (isset($return['$invalides']) && $return['$invalides']) + return $return; + + // une quelconque erreur ... ou rien ==> on ne fait rien ! + if (isset($return['$erreur']) && $return['$erreur']) + return $return; + + // on traite toutes les modifications + // en appelant la fonction adequate de traitement + $set_modifs = $options['f_set_modifs']; + $return = $set_modifs($modifs, $return); + + // une quelconque erreur ... ou rien ==> on ne fait rien ! + if ($return['$erreur']) + return $return; + + // et maintenant refaire l'affichage des crayons modifies + include_spip('inc/texte'); + foreach ($modifs as $m) { + list($type, $modele, $id, $content, $wid) = $m; + $f = charger_fonction($type.'_'.$modele, 'vues', true) + OR $f = charger_fonction($modele, 'vues', true) + OR $f = charger_fonction($type, 'vues', true) + OR $f = 'vues_dist'; + $return[$wid] = $f($type, $modele, $id, $content, $wid); + } + return $return; +} + +// recuperer une valeur en fonction des parametres recuperes +// cette fonction cherche une valeur d'une colonne d'une table SQL +function crayons_store_get_valeur($content, $regs) { + list(,$crayon,$type,$modele,$id) = $regs; + return valeur_colonne_table($type, array_keys($content), $id); +} + +// stocke les valeurs envoyees dans des colonnes de table SQL +function crayons_store_set_modifs($modifs, $return) { + // sinon on bosse : toutes les modifs ont ete acceptees + // verifier qu'on a tout ce qu'il faut pour mettre a jour la base + // et regrouper les mises a jour par type/id + foreach ($modifs as $modif) { + list($type, $modele, $id, $content, $wid) = $modif; + + $fun = ''; + // si le crayon est un MODELE avec une fonction xxx_revision associee + // cas ou une fonction xxx_revision existe + if (function_exists($f = $type.'_'. $modele . "_revision") + OR function_exists($f = $modele . "_revision") + OR function_exists($f = $type . "_revision")) + $fun = $f; + + // si on est en SPIP 3+ et qu'on edite un objet editorial bien declare + // passer par l'API objet_modifier + elseif (function_exists('lister_tables_objets_sql') + AND $tables_objet = lister_tables_objets_sql() + AND isset($tables_objet[table_objet_sql($type)])) { + $fun = 'crayons_objet_modifier'; + } + + // sinon spip < 3 (ou pas un objet edito) + // on teste les objets connus et on route sur les fonctions correspondantes + else switch($type) { + case 'article': + $fun = 'crayons_update_article'; + break; + case 'breve': + include_spip('action/editer_breve'); + $fun = 'revisions_breves'; + break; + case 'forum': + include_spip('inc/forum'); + $fun = 'enregistre_et_modifie_forum'; + break; + case 'rubrique': + include_spip('action/editer_rubrique'); + $fun = 'revisions_rubriques'; + break; + case 'syndic': + case 'site': + include_spip('action/editer_site'); + $fun = 'revisions_sites'; + break; + case 'document': + include_spip('plugins/installer'); + include_spip('inc/plugin'); + if (spip_version_compare($GLOBALS['spip_version_branche'], '3.0.0alpha', '>=')) { + include_spip('action/editer_document'); + $fun = 'document_modifier'; + } else { + include_spip('inc/modifier'); + $fun = 'revision_document'; + } + break; + // cas geres de la maniere la plus standard + case 'auteur': + case 'mot': + case 'signature': + case 'petition': + default: + include_spip('inc/modifier'); + $fun = 'revision_'.$type; + break; + } + + // si on a pas reussi on passe par crayons_update() qui fera un update sql brutal + if (!$fun or !function_exists($fun)) { + $fun = 'crayons_update'; + // $return['$erreur'] = "$type: " . _U('crayons:non_implemente'); + // break; + } + + if (!isset($updates[$type][$fun])) { + $updates[$type][$fun] = array(); + } + if (!isset($updates[$type][$fun][$id])) { + $updates[$type][$fun][$id] = array('wdg'=>array(), 'chval'=>array()); + } + // pour reaffecter le retour d'erreur sql au cas ou + $updates[$type][$fun][$id]['wdg'][] = $wid; + foreach ($content as $champtable => $val) { + $updates[$type][$fun][$id]['chval'][$champtable] = $val; + } + } + + // il manque une fonction de mise a jour ==> on ne fait rien ! + if ($return['$erreur']) + return $return; + + // hop ! mises a jour table par table et id par id + foreach ($updates as $type => $idschamps) + foreach ($idschamps as $fun => $ids) { + foreach ($ids as $id => $champsvaleurs) { + /* cas particulier du logo dans un crayon complexe : + ce n'est pas un champ de la table */ + if (isset($champsvaleurs['chval']['logo'])) { + spip_log('revision logo', 'crayons'); + logo_revision($id, $champsvaleurs['chval'], $type, $champsvaleurs['wdg']); + unset($champsvaleurs['chval']['logo']); + } + if (count($champsvaleurs['chval'])) { + // -- revisions_articles($id_article, $c) -- + spip_log("$fun($id ...)", 'crayons'); + $updok = $fun($id, $champsvaleurs['chval'], $type, $champsvaleurs['wdg']); + // Renvoyer erreur si update base distante echoue, on ne regarde pas les updates base local car ils ne renvoient rien + list($distant,$table) = distant_table($type); + if ($distant AND !$updok) + $return['$erreur'] = "$type: " . _U('crayons:update_impossible'); + } + } + } + + return $return; +} + +// +// VUE +// +function vues_dist($type, $modele, $id, $content, $wid){ + // pour ce qui a une {lang_select} par defaut dans la boucle, + // la regler histoire d'avoir la bonne typo dans le propre() + // NB: ceci n'a d'impact que sur le "par defaut" en bas + list($distant,$table) = distant_table($type); + if (colonne_table($type, 'lang')) { + $b = valeur_colonne_table($type, 'lang', $id); + lang_select($a = array_pop($b)); + } else { + lang_select($a = $GLOBALS['meta']['langue_site']); + } + + // chercher vues/article_toto.html + // sinon vues/toto.html + if (find_in_path( ($fond = 'vues/' . $type . '_' . $modele) . '.html') + OR find_in_path( ($fond = 'vues/' . $modele) .'.html') + OR find_in_path( ($fond = 'vues/' . $type) .'.html')) { + $contexte = array( + 'id_' . $table => $id, + 'crayon_type' => $type, + 'crayon_modele' => $modele, + 'champ' => $modele, + 'class' => _request('class_'.$wid), + 'self' => _request('self'), + 'lang' => $GLOBALS['spip_lang'] + ); + $contexte = array_merge($contexte, $content); + include_spip('public/assembler'); + return recuperer_fond($fond, $contexte); + } + // vue par defaut + else { + // Par precaution on va rechercher la valeur + // dans la base de donnees (meme si a priori la valeur est + // ce qu'on vient d'envoyer, il y a nettoyage des caracteres et + // eventuellement d'autres filtres de saisie...) + $bdd = valeur_colonne_table($type, $modele, $id); + if (count($bdd)) { + $valeur = array_pop($bdd); + } else { + // les champs n'ont pas ete retrouves dans la base + // ce qui signifie a priori que nous sommes en face d'une cle primaire compose + // et qu'un crayon a modifie un element de cette cle (c'est pas malin !) + // dans ce cas, on reaffiche a minima ce qu'on vient de publier + // mais il sera impossible de le reediter dans la foulee avec le meme crayon + // (car l'identifiant du crayon se base sur l'id). + // Il faudra donc recharger la page pour pouvoir reediter. + if (is_scalar($id)) { + $valeur = $content[$modele]; + } + } + + // seul spip core sait rendre les donnees + if (in_array($modele, + array('chapo', 'texte', 'descriptif', 'ps', 'bio'))) { + return propre($valeur); + } else { + return typo($valeur); + } + } +} + + +/** + * Fonction de mise a jour par API editer_objet + * @param $id + * @param $data + * @param $type + * @param $ref + * @return bool|mixed|string + */ +function crayons_objet_modifier($id, $data, $type, $ref) { + if (include_spip('action/editer_objet') + AND function_exists('objet_modifier')) { + return objet_modifier(objet_type($type),$id,$data); + } + // fallback + return crayons_update($id, $data, $type); +} + +// +// Fonctions de mise a jour generique +// +function crayons_update($id, $colval = array(), $type = ''){ + if (!$colval OR !count($colval)) + return false; + list($distant,$table) = distant_table($type); + + if ($distant) { + list($nom_table, $where) = table_where($type, $id); + if (!$nom_table) + return false; + + $update = $sep = ''; + foreach ($colval as $col => $val) { + $update .= $sep . '`' . $col . '`=' . _q($val); + $sep = ', '; + } + + $a = spip_query($q = + 'UPDATE `' . $nom_table . '` SET ' . $update . ' WHERE ' . $where , $distant ); + + #spip_log($q); + include_spip('inc/invalideur'); + suivre_invalideur($cond, $modif=true); + } + else { + // cle primaire composee : 3-4-rubrique + // calculer un where approprie + // et modifier sans passer par la fonction destinee aux tables principales + // on limite a SPIP 2 mini car sql_updateq n'est pas mappe dans les crayons_compat + if (is_scalar($id) and ($GLOBALS['spip_version_code'] >= '1.93')) { + list($nom_table, $where) = table_where($type, $id, true); // where sous forme de tableau + $a = sql_updateq($nom_table, $colval, $where); + } else { + // modification d'une table principale + include_spip('inc/modifier'); + $a = modifier_contenu($type, $id, array(), $colval); + } + } + + return $a; +} + +// +// Fonctions de mise a jour +// +function crayons_update_article($id_article, $c = false) { + include_spip('action/editer_article'); + + // Enregistrer les nouveaux contenus + revisions_articles($id_article, $c); + + // En cas de statut ou de id_rubrique + // NB: instituer_article veut id_parent, et pas id_rubrique ! + if (isset($c['id_rubrique'])) { + $c['id_parent'] = $c['id_rubrique']; + unset ($c['id_rubrique']); + } + instituer_article($id_article, $c); +} + +/** + * Enregistre les modifications sur une configuration + * suite à un crayon sur une meta + * + * La colonne est toujours 'valeur' pour ces données. + * La donnée à enregistrer peut-être une sous partie de configuration. + * Si c'est le cas, on gère l'enregistrement via ecrire_config. + * + * @param string $a + * Nom ou clé de la meta (descriptif_site ou demo__truc pour demo/truc) + * @param bool|array $c + * Liste des champs modifiés + * Ici, 'valeur' normalement. + * @return void +**/ +function revision_meta($a, $c = false) { + if (isset($c['valeur'])) { + // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc}) + $a = str_replace('__', '/', $a); + spip_log("meta '$a' = '$c[valeur]'", 'crayons'); + // eviter de planter les vieux SPIP + if (false === strpos($a, '/')) { + ecrire_meta($a, $c['valeur']); + // SPIP 3 ou Bonux 2 ou CFG + } else { + include_spip('inc/config'); + ecrire_config($a, $c['valeur']); + } + include_spip('inc/invalideur'); + suivre_invalideur('meta'); + } +} + + +// TODO: +// Ce modele est cense enregistrer les tags sous forme de ?? +// une ligne dans un champ spip_articles.tags, et/ou des mots-cles... +function modeles_tags($id, $c) { + var_dump($id); #id_article + var_dump($c); # perturbant : ici on a array('id_article'=>'valeur envoyee') +} + +function action_crayons_store_dist() { + return action_crayons_store_args(); +} + +// permettre de passer une autre fonction de stockage des informations +function action_crayons_store_args($store = 'crayons_store') { + header("Content-Type: text/plain; charset=".$GLOBALS['meta']['charset']); + lang_select($GLOBALS['auteur_session']['lang']); + + $r = $store(); + + // Si on a ete appeles par jQuery, on renvoie tout, c'est le client + // crayons.js qui va traiter l'affichage du resultat et status + # Attention le test $_SERVER["HTTP_X_REQUESTED_WITH"] === "XMLHttpRequest" + # n'est pas bon car le cas d'un fichier uploade via iframe n'est pas detecte + + // S'il y a une adresse de redirection, on renvoie vers elle + // En cas d'erreur il faudrait ajouter &err=... dans l'url ? + if (_request('redirect')) { + if (!$r['$erreur'] + OR $r['$annuler']) { + include_spip('inc/headers'); + redirige_par_entete(_request('redirect')); + } else { + echo "

".$r['$erreur']."

\n"; + + foreach ($r as $wid => $v) { + if ($wid !== '$erreur') + echo "
$v

\n"; + } + echo "" + .quote_amp(_request('redirect')) + ."\n"; + } + } + + // Cas normal : JSON + else { + echo crayons_json_export($r); + } + + exit; +} + +?> diff --git a/www/plugins/crayons/action/crayons_upload.php b/www/plugins/crayons/action/crayons_upload.php new file mode 100644 index 0000000..f09e7be --- /dev/null +++ b/www/plugins/crayons/action/crayons_upload.php @@ -0,0 +1,61 @@ +=')) + define('_SPIP3', true); + } + if (defined('_SPIP3')) { + include_spip('action/ajouter_documents'); + $ajouter_un_document = charger_fonction('ajouter_un_document','action'); + $id = $ajouter_un_document("new", $file, $type, $id, 'document'); + } else { + include_spip('inc/ajouter_documents'); + $id = ajouter_un_document($source, $nom_envoye, $type, $id, 'document', $id_document=0, $documents_actifs, $titrer=true); + } + } + + if (!$id) + $erreur = "erreur !"; + + $a = recuperer_fond('modeles/uploader_item',array('id_document' => $id, 'erreur' => $erreur)); + + echo $a; +} + +?> diff --git a/www/plugins/crayons/controleurs/article_intro.html b/www/plugins/crayons/controleurs/article_intro.html new file mode 100644 index 0000000..87a4d05 --- /dev/null +++ b/www/plugins/crayons/controleurs/article_intro.html @@ -0,0 +1,11 @@ +[(#REM) + + Controleur pour le crayon 'article_intro' , uniquement html + +] +#CACHE{0} + + + diff --git a/www/plugins/crayons/controleurs/article_intro2.html b/www/plugins/crayons/controleurs/article_intro2.html new file mode 100644 index 0000000..803dd07 --- /dev/null +++ b/www/plugins/crayons/controleurs/article_intro2.html @@ -0,0 +1,17 @@ +[(#REM) + + Controleur pour le crayon 'article_intro2' , uniquement html + +] +#CACHE{0} + +
+Introduction + + +
+ diff --git a/www/plugins/crayons/controleurs/article_intro3.php b/www/plugins/crayons/controleurs/article_intro3.php new file mode 100644 index 0000000..491cb70 --- /dev/null +++ b/www/plugins/crayons/controleurs/article_intro3.php @@ -0,0 +1,39 @@ + 234)); + + $return = array( + // html + $n->formulaire( + // champs et attributs propres + array( + 'descriptif' => array('type' => 'texte', 'attrs' => array( + 'style' => 'height:' . ceil($n->hauteur*2/13) . 'px;' . + 'width:' . $n->largeur . 'px;')), + 'chapo' => array('type' => 'texte', 'attrs' => array( + 'style' => 'height:' . ceil($n->hauteur*4/13) . 'px;' . + 'width:' . $n->largeur . 'px;')), + 'texte' => array('type' => 'texte', 'attrs' => array( + 'style' => 'height:' . ceil($n->hauteur*4/13) . 'px;' . + 'width:' . $n->largeur . 'px;'))) //, + // attributs communs :( marche pas pour style , pas 2 fois ? +// array('style' => 'width:' . $n->largeur . 'px;') + ), + // status + null); + + return $return; +} + +?> diff --git a/www/plugins/crayons/controleurs/article_introduction.html b/www/plugins/crayons/controleurs/article_introduction.html new file mode 100644 index 0000000..75bb5bf --- /dev/null +++ b/www/plugins/crayons/controleurs/article_introduction.html @@ -0,0 +1,54 @@ +[(#REM) + + Controleur pour le crayon 'article_introduction' php+html + + (les balises écrites ci-dessous sont volontairement avec un espace pour ne pas être + compilée) + + Appelé via # EDIT{introduction} dans une boucle article + + Affiche les trois champs : + - descriptif (si rempli, il sera le rendu de # INTRODUCTION) + - chapo + - texte + + Si aucun descriptif, le rendu de # INTRODUCTION est par défaut les 600 premiers caractères de + # CHAPO + # TEXTE + +] +#CACHE{0} + +
    +
  • +

    <:crayons:legend_introduction_article:>

    +

    <:crayons:explication_introduction_article:>

    +
      +
    • + + +
    • + [(#CONFIG{articles_chapeau}|=={oui}|oui) +
    • + + +
    • ] +
    • + + +
    • +
    +
  • +
+ diff --git a/www/plugins/crayons/controleurs/article_introduction.php b/www/plugins/crayons/controleurs/article_introduction.php new file mode 100644 index 0000000..4768534 --- /dev/null +++ b/www/plugins/crayons/controleurs/article_introduction.php @@ -0,0 +1,28 @@ + 234, + 'controleur' => 'controleurs/article_introduction')); + + $contexte = array( + 'h_descriptif' => (int)ceil($n->hauteur*2/13), + 'h_chapo' => (int)ceil($n->hauteur*4/13), + 'h_texte' => (int)ceil($n->hauteur*4/13)); + $html = $n->formulaire($contexte); + $status = NULL; + + return array($html, $status); +} + +?> diff --git a/www/plugins/crayons/controleurs/article_texte.html b/www/plugins/crayons/controleurs/article_texte.html new file mode 100644 index 0000000..03e8303 --- /dev/null +++ b/www/plugins/crayons/controleurs/article_texte.html @@ -0,0 +1,17 @@ +[(#REM) + + Controleur pour le crayon 'article_intro' , uniquement html + +] +#CACHE{0} + + + +[(#CONFIG{crayons/upload}|?{ + #MODELE{uploader_liste,id_article} + +})] + + diff --git a/www/plugins/crayons/controleurs/auteur_email.html b/www/plugins/crayons/controleurs/auteur_email.html new file mode 100644 index 0000000..2272130 --- /dev/null +++ b/www/plugins/crayons/controleurs/auteur_email.html @@ -0,0 +1,11 @@ +[(#REM) + + Controleur pour le crayon 'auteur_email', uniquement html + +] +#CACHE{0} + + + + diff --git a/www/plugins/crayons/controleurs/auteur_nom.html b/www/plugins/crayons/controleurs/auteur_nom.html new file mode 100644 index 0000000..d1ad82f --- /dev/null +++ b/www/plugins/crayons/controleurs/auteur_nom.html @@ -0,0 +1,11 @@ +[(#REM) + + Controleur pour le crayon 'auteur_nom', uniquement html + +] +#CACHE{0} + + + + diff --git a/www/plugins/crayons/controleurs/auteur_qui.html b/www/plugins/crayons/controleurs/auteur_qui.html new file mode 100644 index 0000000..b10d005 --- /dev/null +++ b/www/plugins/crayons/controleurs/auteur_qui.html @@ -0,0 +1,26 @@ +[(#REM) + + Controleur pour le crayon 'auteur_qui', uniquement html + +] +#CACHE{0} + + +
    +
  • +

    <:crayons:legend_controleur_qui:>

    +
      +
    • + + +
    • +
    • + + +
    • +
    +
  • +
+ diff --git a/www/plugins/crayons/controleurs/breve_hyperlien.html b/www/plugins/crayons/controleurs/breve_hyperlien.html new file mode 100644 index 0000000..a90378a --- /dev/null +++ b/www/plugins/crayons/controleurs/breve_hyperlien.html @@ -0,0 +1,9 @@ + +
Hyperlien + +
+ +
+ diff --git a/www/plugins/crayons/controleurs/document_fichier.html b/www/plugins/crayons/controleurs/document_fichier.html new file mode 100644 index 0000000..7471fca --- /dev/null +++ b/www/plugins/crayons/controleurs/document_fichier.html @@ -0,0 +1,46 @@ +[(#REM) + + Controleur pour le crayon 'document' + +] +#CACHE{0} + + +[(#REM) En fonction de du contexte, choisir un logo ] + + + +[(#SET{image,[]})] + + + + [(#SET{logo,[(#GET{image}|image_reduire{0,40})]})] + + [(#REM) hacke l'url pour eviter le cache du navigateur ] + [(#SET{url,[(#GET{logo}|extraire_attribut{src} + |parametre_url{s,#EVAL{time()}})]})] + + [(#GET{logo}|inserer_attribut{src,#GET{url}} + |inserer_attribut{style,vertical-align:middle;})] +   <:crayons:legend_controleur_fichier_remplacer{extension=#EXTENSION}:> + [((#GET{image} + |extraire_attribut{width})×[(#GET{image} + |extraire_attribut{height})]px)] + + + + + +[(#REM) + +TODO: document distant (cf. document_fichier_revision dans inc/crayons) + +
+ + +] + + + + diff --git a/www/plugins/crayons/controleurs/extra.html b/www/plugins/crayons/controleurs/extra.html new file mode 100644 index 0000000..1863ec4 --- /dev/null +++ b/www/plugins/crayons/controleurs/extra.html @@ -0,0 +1,38 @@ +[(#REM) + + Controleur pour le crayon 'extra' + +] +#CACHE{0} + + +extra + + + + +[(#EXTRA**|extra_saisie{auteurs,#STATUT})] + + + +[(#EXTRA**|extra_saisie{articles,#ID_RUBRIQUE})] + + + +[(#EXTRA**|extra_saisie{breves,#ID_RUBRIQUE})] + + + +[(#EXTRA**|extra_saisie{rubriques,#ID_SECTEUR})] + + + +[(#EXTRA**|extra_saisie{sites,#ID_RUBRIQUE})] + + + + + + + + \ No newline at end of file diff --git a/www/plugins/crayons/controleurs/extra_fonctions.php b/www/plugins/crayons/controleurs/extra_fonctions.php new file mode 100644 index 0000000..9dacf6e --- /dev/null +++ b/www/plugins/crayons/controleurs/extra_fonctions.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/www/plugins/crayons/controleurs/forum_email.html b/www/plugins/crayons/controleurs/forum_email.html new file mode 100644 index 0000000..ec7cc13 --- /dev/null +++ b/www/plugins/crayons/controleurs/forum_email.html @@ -0,0 +1,11 @@ +[(#REM) + + Controleur pour le crayon 'forum-email', uniquement html + +] +#CACHE{0} + + + + diff --git a/www/plugins/crayons/controleurs/forum_id_article.html b/www/plugins/crayons/controleurs/forum_id_article.html new file mode 100644 index 0000000..703cce7 --- /dev/null +++ b/www/plugins/crayons/controleurs/forum_id_article.html @@ -0,0 +1,33 @@ +[(#REM) + + Controleur pour le crayon 'forum-id_article' + + NB: il est possible d'ajouter ci-dessous un second menu + qui permettrait de passer d'un article a une breve ; la seule + difficulte etant de savoir remettre a zero la valeur id_article + si une breve a ete selectionnee (et vice-versa) + + Tant qu'on en pas besoin, hein, on va laisser comme a. + +] +#CACHE{0} + +0}> + + +
+Associer ce forum à l'article : + +
+
+ + + diff --git a/www/plugins/crayons/controleurs/forum_nom.html b/www/plugins/crayons/controleurs/forum_nom.html new file mode 100644 index 0000000..d40980b --- /dev/null +++ b/www/plugins/crayons/controleurs/forum_nom.html @@ -0,0 +1,11 @@ +[(#REM) + + Controleur pour le crayon 'forum-nom', uniquement html + +] +#CACHE{0} + + + + diff --git a/www/plugins/crayons/controleurs/forum_qui.html b/www/plugins/crayons/controleurs/forum_qui.html new file mode 100644 index 0000000..933a329 --- /dev/null +++ b/www/plugins/crayons/controleurs/forum_qui.html @@ -0,0 +1,15 @@ +[(#REM) + + Controleur pour le crayon 'forum_qui', uniquement html + +] +#CACHE{0} + + +
Qui ? +
+ +
+ diff --git a/www/plugins/crayons/controleurs/hyperlien.html b/www/plugins/crayons/controleurs/hyperlien.html new file mode 100644 index 0000000..1a4b65d --- /dev/null +++ b/www/plugins/crayons/controleurs/hyperlien.html @@ -0,0 +1,114 @@ +[(#REM) + + Controleur pour le crayon 'hyperlien', uniquement html + + (attention pour les syndic_articles et breves, les champs ne sont + pas les memes, il faut donc un autre controleur) + +] +#CACHE{0} + + +
    +
  • +

    <:crayons:legend_controleur_hyperlien:>

    +
      +
    • + + +
    • +
    • + + +
    • +
    +
  • +
+ + + +
    +
  • +

    <:crayons:legend_controleur_hyperlien:>

    +
      +
    • + + +
    • +
    • + + +
    • +
    +
  • +
+ + + +
    +
  • +

    <:crayons:legend_controleur_hyperlien:>

    +
      +
    • + + +
    • +
    • + + +
    • +
    +
  • +
+ + + +
    +
  • +

    <:crayons:legend_controleur_hyperlien:>

    +
      +
    • + + +
    • +
    • + + +
    • +
    +
  • +
+ + + +
    +
  • +

    <:crayons:legend_controleur_hyperlien:>

    +
      +
    • + + +
    • +
    • + + +
    • +
    +
  • +
+ + + + + + diff --git a/www/plugins/crayons/controleurs/id_parent.html b/www/plugins/crayons/controleurs/id_parent.html new file mode 100644 index 0000000..6961863 --- /dev/null +++ b/www/plugins/crayons/controleurs/id_parent.html @@ -0,0 +1,31 @@ +[(#REM) + + Controleur pour le crayon 'id_parent', uniquement html + + Utilisable dans une boucle rubriques et articles + On affiche toutes les rubriques même non publiées + On sépare visuellement les sous rubriques + +] +#CACHE{0} + +#SET{id,#ID_RUBRIQUE} + + +#SET{id,#ID_PARENT} + + + + + \ No newline at end of file diff --git a/www/plugins/crayons/controleurs/logo.html b/www/plugins/crayons/controleurs/logo.html new file mode 100644 index 0000000..324ae9c --- /dev/null +++ b/www/plugins/crayons/controleurs/logo.html @@ -0,0 +1,51 @@ +[(#REM) + + Controleur pour le crayon 'logo' + +] +#CACHE{0} + +[(#REM) En fonction de du contexte, choisir un logo ] +[(#SET{image,[(#ID_ARTICLE|?{#LOGO_ARTICLE_NORMAL} + |sinon{[(#ID_AUTEUR|?{#LOGO_AUTEUR_NORMAL})]} + |sinon{[(#ID_BREVE|?{#LOGO_BREVE_NORMAL})]} + |sinon{[(#ID_RUBRIQUE|?{[(#LOGO_RUBRIQUE_NORMAL|extraire_attribut{src}|match{[(#EVAL{_DIR_IMG})]rubon0\.}|?{'',#LOGO_RUBRIQUE_NORMAL})]})]} + |sinon{[(#ID_SYNDIC_ARTICLE|?{#LOGO_SYNDIC_ARTICLE})]} + |sinon{[(#ID_SYNDIC|?{#LOGO_SITE_NORMAL})]} + |sinon{[(#ID_MOT|?{#LOGO_MOT_NORMAL})]})]})] +[(#GET{image}|?{ + [(#SET{logo,[(#GET{image}|image_reduire{64})]})] + [(#REM) hacke l'url pour eviter le cache du navigateur ] + [(#SET{url,[(#GET{logo}|extraire_attribut{src} + |parametre_url{s,#EVAL{time()}})]})] + [(#SET{legend, + <:crayons:legend_controleur_logo_remplacer:> + [((#GET{image} + |extraire_attribut{width})×[(#GET{image} + |extraire_attribut{height})]px)] : + })] + [(#SET{supprimer, + [
+ +
] + })] +})] + +
    +
  • +

    + [(#GET{legend}|sinon{<:crayons:legend_controleur_logo:>})] + [
    (#GET{logo}|inserer_attribut{src,#GET{url}} + |inserer_attribut{style,vertical-align:middle;})
    ] +

    +
      + +
    +
  • +
\ No newline at end of file diff --git a/www/plugins/crayons/controleurs/mots_article_brut.html b/www/plugins/crayons/controleurs/mots_article_brut.html new file mode 100644 index 0000000..159cc16 --- /dev/null +++ b/www/plugins/crayons/controleurs/mots_article_brut.html @@ -0,0 +1,20 @@ +[(#REM) + + Controleur pour le crayon 'mots_article_brut' + +] +#CACHE{0} + +
Mots-clé pour #TITRE (#ID_ARTICLE) + + + + +Pas d'existant + +
+ diff --git a/www/plugins/crayons/controleurs/portfolio.php b/www/plugins/crayons/controleurs/portfolio.php new file mode 100644 index 0000000..19e3c8f --- /dev/null +++ b/www/plugins/crayons/controleurs/portfolio.php @@ -0,0 +1,29 @@ +\"\"
';") + . http_script('', generer_url_public('jquery.js')) + . http_script('', _DIR_JAVASCRIPT . 'layer.js','') + . afficher_documents_colonne($id, $type, 'portfolio'); + + $status = NULL; + + return array($html, $status); +} + + + + +?> diff --git a/www/plugins/crayons/controleurs/signature_email.html b/www/plugins/crayons/controleurs/signature_email.html new file mode 100644 index 0000000..ec501bb --- /dev/null +++ b/www/plugins/crayons/controleurs/signature_email.html @@ -0,0 +1,11 @@ +[(#REM) + + Controleur pour le crayon 'signature-email', uniquement html + +] +#CACHE{0} + + + + diff --git a/www/plugins/crayons/controleurs/signature_nom.html b/www/plugins/crayons/controleurs/signature_nom.html new file mode 100644 index 0000000..1f8136c --- /dev/null +++ b/www/plugins/crayons/controleurs/signature_nom.html @@ -0,0 +1,10 @@ +[(#REM) + + Controleur pour le crayon 'signature-nom', uniquement html +] +#CACHE{0} + + + + diff --git a/www/plugins/crayons/controleurs/signature_qui.html b/www/plugins/crayons/controleurs/signature_qui.html new file mode 100644 index 0000000..fbb208c --- /dev/null +++ b/www/plugins/crayons/controleurs/signature_qui.html @@ -0,0 +1,16 @@ +[(#REM) + + Controleur pour le crayon 'signature_qui', uniquement html + +] +#CACHE{0} + + +
Qui ? + +
+ +
+ diff --git a/www/plugins/crayons/controleurs/statut.html b/www/plugins/crayons/controleurs/statut.html new file mode 100644 index 0000000..e532361 --- /dev/null +++ b/www/plugins/crayons/controleurs/statut.html @@ -0,0 +1,26 @@ + +[(#REM) + + Un crayon pour changer le statut (autrement dit, une gomme) + + Plutot qu'un menu on peut avoir envie de faire une interface plus jolie + mais techniquement ça tourne (version SVN > 1.9.2). + +] + + +#SET{id,#STATUT} + + + + + + diff --git a/www/plugins/crayons/controleurs/syndic_article_hyperlien.html b/www/plugins/crayons/controleurs/syndic_article_hyperlien.html new file mode 100644 index 0000000..f8026f0 --- /dev/null +++ b/www/plugins/crayons/controleurs/syndic_article_hyperlien.html @@ -0,0 +1,17 @@ +[(#REM) + + Controleur pour le crayon 'hyperlien' des articles syndiques + +] +#CACHE{0} + + +
Hyperlien + +
+ +
+ diff --git a/www/plugins/crayons/controleurs/vignette.html b/www/plugins/crayons/controleurs/vignette.html new file mode 100644 index 0000000..db99f92 --- /dev/null +++ b/www/plugins/crayons/controleurs/vignette.html @@ -0,0 +1,49 @@ +[(#REM) + + Controleur pour le crayon 'vignette' + Ce crayon ne s'applique qu'aux documents + On le mets dans une boucle documents contenant le critère {tous} au cas + ou le document ne soit pas considere comme publie + +] +#CACHE{0} + + +[(#SET{image,[(#ID_VIGNETTE|>{0}|?{#LOGO_DOCUMENT})]})] +[(#GET{image}|?{ + [(#SET{vignette,[(#GET{image}|image_reduire{64})]})] + [(#REM) hacke l'url pour eviter le cache du navigateur ] + [(#SET{url,[(#GET{vignette}|extraire_attribut{src} + |parametre_url{s,#EVAL{time()}})]})] + [(#SET{legend, + <:crayons:legend_controleur_vignette_remplacer:> + [((#GET{image} + |extraire_attribut{width})×[(#GET{image} + |extraire_attribut{height})]px)] : + })] + [(#SET{supprimer, + [
+ +
] + })] +})] + +
    +
  • +

    + [(#GET{legend}|sinon{<:crayons:legend_controleur_vignette:>})] + [
    (#GET{vignette}|inserer_attribut{src,#GET{url}} + |inserer_attribut{style,vertical-align:middle;})
    ] +

    +
      +
    • +
      + +
      + #GET{supprimer} +
    • +
    +
  • +
+ \ No newline at end of file diff --git a/www/plugins/crayons/crayons.css b/www/plugins/crayons/crayons.css new file mode 100644 index 0000000..4c62420 --- /dev/null +++ b/www/plugins/crayons/crayons.css @@ -0,0 +1,40 @@ +em.crayon-img-changed { display: none; } +.crayon-changed em.crayon-img-changed { display: block; } +.crayon-changed em.crayon-crayon { display: none; } +em.crayon-edit, +em.crayon-crayon { display: none; } +.crayon-boutons, +.crayon-searching { float: right;padding:0;text-align: right;} +.crayon-boutons button { border:1px solid; cursor: pointer;display:inline-block; } +.crayon-boutons .crayon-submit { background: #e6efc2 url(images/ok-16.png) 2px center no-repeat; color: #264409; border-color: #c6d880;float:right;margin-bottom: 0.5em;margin-left:0.5em;padding-left:20px;} +.crayon-boutons .crayon-cancel { background: #fbe3e4 url(images/annuler-16.png) center center no-repeat; color: #8a1f11; border-color: #fbc2c4;width: 40px; text-indent: -3000em;padding-right:20px;} +.small .crayon-boutons {float:none;} +.small .crayon-boutons .crayon-submit {text-indent: -3000em;background-position: center;width: 40px;} +.small .crayon-boutons .crayon-cancel {float:left;} + +.crayon-icones { float: right; width: 20px; text-align: right; position: relative; top:0; left:0; z-index:4999; } +.crayon-icones span,.crayon-icones em { position:absolute; left:0; } +em.crayon-edit, +em.crayon-crayon, +em.crayon-img-changed { cursor: pointer; border:0; } + +/* definition des icones */ +.crayon-icones em.crayon-crayon { background: url(images/crayon20.png) no-repeat; height: 20px; width: 20px; } +.crayon-icones em.crayon-searching { background: url(images/searching.gif) no-repeat; height: 13px; width: 13px; } +.crayon-icones em.crayon-edit { background: url(images/edit.png) no-repeat; height: 20px; width: 20px; } +.crayon-icones em.crayon-img-changed { background: url(images/changed.png) no-repeat; height: 20px; width: 20px; } + +.formulaire_crayon .crayon-active { padding: 1px; border: 1px inset; font: inherit; display:block; } +.crayon-html .formulaire_crayon { max-width: 703px; } +.crayon-html textarea { overflow: auto; font: inherit; } +.crayon-html { z-index:5000; } +.crayon-html .crayon-boutons { position:absolute; right:0px; } +.crayon-html .small .crayon-boutons {position: relative;} + + +.crayon-invalide { display: block; background-color: #ff8888; border: 1px dashed #ff0000; } +.crayon-invalide p { margin:0; padding: 1%; font-style: italic; font-size: 80%; } +/* resizer */ +.resizehandle { background:transparent url("images/resizer.png") no-repeat scroll 50%; cursor:ns-resize; font-size:0.1em; width: auto !important;margin-right: 150px;} +.small .resizehandle {margin-right: 0;} +.resizehandle_boutons { margin-top: -16px; } diff --git a/www/plugins/crayons/crayons.js.html b/www/plugins/crayons/crayons.js.html new file mode 100644 index 0000000..748b8e9 --- /dev/null +++ b/www/plugins/crayons/crayons.js.html @@ -0,0 +1,35 @@ +[(#REM) + + Charger la librairie crayons et ses addenda + +] +#HTTP_HEADER{'Content-Type: text/javascript'} + +[(#ENV**{debug_crayons}|?{ + #CACHE{0} +, + #CACHE{7*24*3600,cache-client} +})] + +/* cQuery est jQuery, renommee pour eviter tout conflit */ + +[(#CHEMIN{js/jquery.js}|pack_cQuery)] + +cQuery.noConflict(); + +[(#CHEMIN{js/jquery.form.js}|pack_cQuery)] + +[(#CHEMIN{js/jquery.px.js}|pack_cQuery)] + +[(#CHEMIN{js/crayons.js}|pack_cQuery)] + +[(#CHEMIN{js/resizehandle.js}|pack_cQuery)] + +[(#CHEMIN{js/jquery.html5uploader.min.js}|pack_cQuery)] + +[(#CONFIG{crayons}|match{s:11:"yellow_fade";s:2:"on";}|?{' ',''}) + [(#CHEMIN{js/crayons-fade.js}|pack_cQuery)] +] + +[(#REM) Appeler la callback si demandee ] +[(#ENV{callback})();] \ No newline at end of file diff --git a/www/plugins/crayons/crayons.js_fonctions.php b/www/plugins/crayons/crayons.js_fonctions.php new file mode 100644 index 0000000..e427f9e --- /dev/null +++ b/www/plugins/crayons/crayons.js_fonctions.php @@ -0,0 +1,46 @@ +pack())) + return $t; + + // erreur + spip_log('erreur de pack_js'); + return $flux; +} + +?> diff --git a/www/plugins/crayons/crayons_fonctions.php b/www/plugins/crayons/crayons_fonctions.php new file mode 100644 index 0000000..5cb3280 --- /dev/null +++ b/www/plugins/crayons/crayons_fonctions.php @@ -0,0 +1,462 @@ +$champ))", "crayons_distant"); + } + if (autoriser('modifier', $type, $id, null, array('champ'=>$champ))) { + if (!isset($droits['.' . $crayon])) { + $droits['.' . $crayon] = 0; + } + $droits['.' . $crayon]++; + $droits_accordes ++; + } + } + + // et les signaler dans la page + if ($droits_accordes == count($regs)) { // tous les droits + $page = Crayons_preparer_page($page, '*', $wdgcfg); + } elseif ($droits) { // seulement certains droits, preciser lesquels + $page = Crayons_preparer_page($page, join(',', array_keys($droits)), $wdgcfg); + } + + return $page; +} + +/** + * Ajoute les scripts css et js nécessaires aux crayons dans le code HTML + * + * @uses crayons_var2js() + * + * @param string $page + * Code HTML de la page complète ou du header seulement + * @param string $droits + * - Liste de css définissant les champs crayonnables + * (séparés par virgule) dont l'édition est autorisée + * - "*" si tous sont autorisés + * @param array $wdgcfg + * Description de la configuration des crayons (attribut => valeur) + * @param string $mode + * - page : toute la page est présente dans `$page` + * - head : seul le header est présent dans `$page` + * @return +**/ +function &Crayons_preparer_page(&$page, $droits, $wdgcfg = array(), $mode = 'page') { + /** + * Si pas forcer_lang, on charge le contrôleur dans la langue que l'utilisateur a dans le privé + */ + if (!isset($GLOBALS['forcer_lang']) or !$GLOBALS['forcer_lang'] or ($GLOBALS['forcer_lang'] === 'non')) { + lang_select($GLOBALS['auteur_session']['lang']); + } + + $jsFile = generer_url_public('crayons.js'); + if (_DEBUG_CRAYONS) { + $jsFile = parametre_url($jsFile, 'debug_crayons', 1, '&'); + } + include_spip('inc/filtres'); // rien que pour direction_css() :( + $cssFile = direction_css(find_in_path('crayons.css')); + + $config = crayons_var2js(array( + 'imgPath' => dirname(find_in_path('images/crayon.png')), + 'droits' => $droits, + 'dir_racine' => _DIR_RACINE, + 'self' => self('&'), + 'txt' => array( + 'error' => _U('crayons:svp_copier_coller'), + 'sauvegarder' => $wdgcfg['msgAbandon'] ? _U('crayons:sauvegarder') : '' + ), + 'img' => array( + 'searching' => array( + 'txt' => _U('crayons:veuillez_patienter') + ), + 'crayon' => array( + 'txt' => _U('crayons:editer') + ), + 'edit' => array( + 'txt' => _U('crayons:editer_tout') + ), + 'img-changed' => array( + 'txt' => _U('crayons:deja_modifie') + ) + ), + 'cfg' => $wdgcfg + )); + + + // Est-ce que PortePlume est la ? + $meta_crayon = isset($GLOBALS['meta']['crayons']) ? unserialize($GLOBALS['meta']['crayons']): array(); + $pp = ''; + if (isset($meta_crayon['barretypo']) && $meta_crayon['barretypo']) { + if (function_exists('chercher_filtre') + and $f = chercher_filtre('info_plugin') + and $f('PORTE_PLUME','est_actif')) { + + $pp = <<"; + $incJS = <</* */ + +EOH; + + if ($mode == 'head') { + //js inline avant les css, sinon ca bloque le chargement + $page = $page . $incJS . $incCSS; + return $page; + } + + $pos_head = strpos($page, ''); + if ($pos_head === false) { + return $page; + } + + // js inline avant la premiere css, ou sinon avant la fin du head + $pos_link = strpos($page, ''); + $page = substr_replace($page, $incCSS, $pos_head, 0); + + return $page; +} + +/** + * Balise indiquant un champ SQL crayonnable + * + * @note + * Si cette fonction est absente, `balise_EDIT_dist()` déclarée par SPIP + * ne retourne rien + * + * @example + * ``` + *
#TEXTE
+ *
#PS
+ * ``` + * + * @param Champ $p + * Pile au niveau de la balise + * @return Champ + * Pile complétée par le code à générer +**/ +function balise_EDIT($p) { + + // le code compile de ce qui se trouve entre les {} de la balise + $label = interprete_argument_balise(1, $p); + + // Verification si l'on est dans le cas d'une meta + // #EDIT{meta-descriptif_site} ou #EDIT{meta-demo/truc} + if (preg_match('/meta-(.*)\'/', $label, $meta)) { + $type = 'meta'; + $label= 'valeur'; + $primary = $meta[1]; + $p->code = "classe_boucle_crayon('" + . $type + ."','" + .$label + ."'," + . "str_replace('/', '__', '$primary')" # chaque / doit être remplacé pour CSS. + .").' '"; + $p->interdire_scripts = false; + return $p; + } + + $i_boucle = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle; + // #EDIT hors boucle? ne rien faire + if (!isset($p->boucles[$i_boucle]) or !$type = ($p->boucles[$i_boucle]->type_requete)) { + $p->code = "''"; + $p->interdire_scripts = false; + return $p; + } + + // crayon sur une base distante 'nua__article-intro-5' + if ($distant = $p->boucles[$i_boucle]->sql_serveur) { + $type = $distant.'__'.$type; + } + + // le compilateur 1.9.2 ne calcule pas primary pour les tables secondaires + // il peut aussi arriver une table sans primary (par ex: une vue) + if (!($primary = $p->boucles[$i_boucle]->primary)) { + include_spip('inc/vieilles_defs'); # 1.9.2 pour trouver_def_table + if (function_exists('trouver_def_table')) { + list($nom, $desc) = trouver_def_table( + $p->boucles[$i_boucle]->type_requete, + $p->boucles[$i_boucle] + ); + $primary = $desc['key']['PRIMARY KEY']; + } + } + // On rajoute ici un debug dans le cas où aucune clé primaire n'est trouvée. + // Cela peut se présenter par exemple si on utilise #EDIT{monchamp} directement + // dans une boucle CONDITION sans faire référence au nom de la boucle d'au dessus. + if (!$primary) { + erreur_squelette(_T('crayons:absence_cle_primaire'), $p); + } + + $primary = explode(',', $primary); + $id = array(); + foreach ($primary as $key) { + $id[] = champ_sql(trim($key), $p); + } + $primary = implode(".'-'.", $id); + + $p->code = "classe_boucle_crayon('" + . $type + ."'," + .sinon($label, "''") + ."," + . $primary + .").' '"; + $p->interdire_scripts = false; + return $p; +} + +/** + * Balise indiquant une configuration crayonnable + * + * @example + * ``` + *
#DESCRIPTIF_SITE_SPIP
+ *
#CONFIG{demo/truc}
+ * ``` + * + * @param Champ $p + * Pile au niveau de la balise + * @return Champ + * Pile complétée par le code à générer +**/ +function balise_EDIT_CONFIG_dist($p) { + + // le code compile de ce qui se trouve entre les {} de la balise + $config = interprete_argument_balise(1, $p); + if (!$config) { + return $p; + } + + // chaque / du nom de config doit être transformé pour css. + // nous utiliserons '__' à la place. + + $type = 'meta'; + $label= 'valeur'; + + $p->code = "classe_boucle_crayon('" + . $type + . "','" + . $label + . "'," + . "str_replace('/', '__', $config)" + . ").' '"; + $p->interdire_scripts = false; + return $p; +} + +/** + * Crée le controleur du crayon indiqué par la classe CSS + * + * @param string $class + * Class CSS de crayon tel que créé par #EDIT + * @return string + * HTML du crayon, sinon texte d'erreur +**/ +function creer_le_crayon($class) { + include_spip('inc/crayons'); + include_spip('action/crayons_html'); + $a = affiche_controleur($class, array('w' => 485, 'h' => 300, 'wh' => 500)); + return $a['$erreur'] ? $a['$erreur'] : $a['$html']; +} + +/** + * Balise `#CRAYON` affichant un formulaire de crayon + * + * SI `?edit=1;` + * + * @example + * ``` + * #CRAYON{ps} + * ``` + * + * @param Champ $p + * Pile au niveau de la balise + * @return Champ + * Pile complétée par le code à générer +**/ +function balise_CRAYON($p) { + $p = balise_EDIT($p); + $p->code = 'creer_le_crayon('.$p->code.')'; + return $p; +} + + +/** + * Donne la classe CSS crayon + * + * En fonction : + * - du type de la boucle + * (attention aux exceptions pour `#EDIT` dans les boucles HIERARCHIE et SITES) + * - du champ demande (vide, + ou se terminant par + : (+)classe type--id) + * - de l'id courant + * + * @param string $type + * Type d'objet, ou "meta" pour un champ de configuration + * @param string $champ + * Champ SQL concerné + * @param int|string $id + * Identifiant de la ligne sql + * @return string + * Classes CSS (à ajouter dans le HTML à destination du javascript de Crayons) +**/ +function classe_boucle_crayon($type, $champ, $id) { + // $type = objet_type($type); + $type = $type[strlen($type) - 1] == 's' ? + substr($type, 0, -1) : + str_replace( + array('hierarchie','syndication'), + array('rubrique','site'), + $type + ); + + $plus = (substr($champ, -1) == '+' and $champ = substr($champ, 0, -1)) + ? " $type--$id" + : ''; + + // test rapide pour verifier que l'id est valide (a-zA-Z0-9) + if (false !== strpos($id, ' ')) { + spip_log("L'identifiant ($id) ne pourra être géré ($type | $champ)", 'crayons'); + return 'crayon_id_ingerable'; + } + + return 'crayon ' . $type . '-' . $champ . '-' . $id . $plus; +} + +?> diff --git a/www/plugins/crayons/fonds/cfg_crayons.html b/www/plugins/crayons/fonds/cfg_crayons.html new file mode 100644 index 0000000..df6eef9 --- /dev/null +++ b/www/plugins/crayons/fonds/cfg_crayons.html @@ -0,0 +1,11 @@ + + + + + +#CACHE{0} +
+#FORMULAIRE_CONFIGURER_CRAYONS +
diff --git a/www/plugins/crayons/formulaires/configurer_crayons.html b/www/plugins/crayons/formulaires/configurer_crayons.html new file mode 100644 index 0000000..54d2c8b --- /dev/null +++ b/www/plugins/crayons/formulaires/configurer_crayons.html @@ -0,0 +1,118 @@ + + + + +
+ +

[(#CHEMIN{images/crayon-24.png}|image_reduire{24}|inserer_attribut{class,cadre-icone}|inserer_attribut{alt,''})]<:crayons:titre_config_crayons:>

+ +[

(#ENV*{message_ok})

] +[

(#ENV*{message_erreur})

] + +
+
+#ACTION_FORMULAIRE{#ENV{action}} +
    +#SET{erreurs,#ENV**{erreurs}|table_valeur{barretypo}} +
  • + + [(#GET{erreurs})] +
    + + + [(#PLUGIN{porte_plume,version}|version_compare{'1.5','>='}|oui) + [

    + (#VAL{PORTE_PLUME_PUBLIC}|defined|et{#VAL{PORTE_PLUME_PUBLIC}|constant} + |ou{#CONFIG{barre_outils_public}|=={non}}) + <:crayons:activation_barre_impossible:> +

    ] + ] +
    +
  • + +#SET{erreurs,#ENV**{erreurs}|table_valeur{msgNoChange}} +
  • + + [(#GET{erreurs})] +
    + + +
    +
    + + +
    +
  • + +#SET{erreurs,#ENV**{erreurs}|table_valeur{filet}} +
  • + + [(#GET{erreurs})] +
    + + +
    +
    + + +
    +
    + + +
    +
  • + + +#SET{erreurs,#ENV**{erreurs}|table_valeur{reduire_logo}} +
  • + + [(#GET{erreurs})] +

    <:crayons:explication_reduire_logo:>

    + +
  • + +
  • +

    <:crayons:legend_editer_prive:>

    +
      + #SET{erreurs,#ENV**{erreurs}|table_valeur{espaceprive}} +
    • + + [(#GET{erreurs})] +
      + + +
      +
    • + #SET{erreurs,#ENV**{erreurs}|table_valeur{exec_autorise}} +
    • + + [(#GET{erreurs})] +

      <:crayons:explication_exec_autorise:>

      + +
    • +
    +
  • + + +
  • +

    <:crayons:legend_documents:>

    +
      +
    • + + [(#GET{erreurs})] +
      + + +
      +
    • +
    +
  • + + +
+

+ +

+
+
+
diff --git a/www/plugins/crayons/images/annuler-16.png b/www/plugins/crayons/images/annuler-16.png new file mode 100644 index 0000000..fd4c41a Binary files /dev/null and b/www/plugins/crayons/images/annuler-16.png differ diff --git a/www/plugins/crayons/images/changed.png b/www/plugins/crayons/images/changed.png new file mode 100644 index 0000000..12829fa Binary files /dev/null and b/www/plugins/crayons/images/changed.png differ diff --git a/www/plugins/crayons/images/crayon-128.png b/www/plugins/crayons/images/crayon-128.png new file mode 100644 index 0000000..51d52ee Binary files /dev/null and b/www/plugins/crayons/images/crayon-128.png differ diff --git a/www/plugins/crayons/images/crayon-24.png b/www/plugins/crayons/images/crayon-24.png new file mode 100644 index 0000000..4370da9 Binary files /dev/null and b/www/plugins/crayons/images/crayon-24.png differ diff --git a/www/plugins/crayons/images/crayon-32.png b/www/plugins/crayons/images/crayon-32.png new file mode 100644 index 0000000..ef17876 Binary files /dev/null and b/www/plugins/crayons/images/crayon-32.png differ diff --git a/www/plugins/crayons/images/crayon.png b/www/plugins/crayons/images/crayon.png new file mode 100644 index 0000000..74d9c22 Binary files /dev/null and b/www/plugins/crayons/images/crayon.png differ diff --git a/www/plugins/crayons/images/crayon20.png b/www/plugins/crayons/images/crayon20.png new file mode 100644 index 0000000..c8e3851 Binary files /dev/null and b/www/plugins/crayons/images/crayon20.png differ diff --git a/www/plugins/crayons/images/edit.png b/www/plugins/crayons/images/edit.png new file mode 100644 index 0000000..aa0c5d6 Binary files /dev/null and b/www/plugins/crayons/images/edit.png differ diff --git a/www/plugins/crayons/images/ok-16.png b/www/plugins/crayons/images/ok-16.png new file mode 100755 index 0000000..c277e6b Binary files /dev/null and b/www/plugins/crayons/images/ok-16.png differ diff --git a/www/plugins/crayons/images/pencil.png b/www/plugins/crayons/images/pencil.png new file mode 100644 index 0000000..8be4812 Binary files /dev/null and b/www/plugins/crayons/images/pencil.png differ diff --git a/www/plugins/crayons/images/resizer.png b/www/plugins/crayons/images/resizer.png new file mode 100644 index 0000000..5f42c4f Binary files /dev/null and b/www/plugins/crayons/images/resizer.png differ diff --git a/www/plugins/crayons/images/searching.gif b/www/plugins/crayons/images/searching.gif new file mode 100644 index 0000000..01d48f3 Binary files /dev/null and b/www/plugins/crayons/images/searching.gif differ diff --git a/www/plugins/crayons/inc/compat_crayons.php b/www/plugins/crayons/inc/compat_crayons.php new file mode 100644 index 0000000..5eba693 --- /dev/null +++ b/www/plugins/crayons/inc/compat_crayons.php @@ -0,0 +1,100 @@ + diff --git a/www/plugins/crayons/inc/crayons-json.php b/www/plugins/crayons/inc/crayons-json.php new file mode 100644 index 0000000..5311c5e --- /dev/null +++ b/www/plugins/crayons/inc/crayons-json.php @@ -0,0 +1,93 @@ + $elt) { + $ret .= $sep . '"' . $key . '":' . crayons_var2js($elt); + $sep = ','; + } + return $ret ."}"; + } else { + $ret = '['; + foreach ($var as $elt) { + $ret .= $sep . crayons_var2js($elt); + $sep = ','; + } + return $ret ."]"; + } + } + return false; +} + +// Un json_encode qui marche en iso (la spec JSON exige utf-8) +function crayons_json_encode($v) { + if ($GLOBALS['meta']['charset'] == 'utf-8' + AND function_exists('json_encode')) + return json_encode($v); + + $v = crayons_var2js($v); + + if ($GLOBALS['meta']['charset'] != 'utf-8') { + include_spip('inc/charsets'); + $v = charset2unicode($v); + } + + return $v; +} + +// http://doc.spip.org/@json_export +function crayons_json_export($var) { + return crayons_json_encode($var); + +/// Il semble que ce hack n'ait plus lieu d'etre avec jquery 1.5 +/* + // flag indiquant qu'on est en iframe et qu'il faut proteger nos + // donnees dans un "; + else + return $var; +*/ +} + +?> diff --git a/www/plugins/crayons/inc/crayons.php b/www/plugins/crayons/inc/crayons.php new file mode 100644 index 0000000..2039c27 --- /dev/null +++ b/www/plugins/crayons/inc/crayons.php @@ -0,0 +1,701 @@ +\'"]+?\b((\w+)-(\w+)-(\w+(?:-\w+)*))\b,'); + +// Compatibilite pour 1.92 : on a besoin de sql_fetch et table_objet_sql +if ($GLOBALS['spip_version_code'] < '1.93' AND $f = charger_fonction('compat_crayons', 'inc')) + $f(); + +// Autoriser les crayons sur les tables non SPIP ? +// Par defaut : oui (pour les admins complets, si autoriser_defaut_dist()) ; +// mettre a false en cas de mutualisation par prefixe de table, +// sinon on ne peut pas garantir que les sites sont hermetiques +if(!defined('_CRAYONS_TABLES_EXTERNES')) + define('_CRAYONS_TABLES_EXTERNES', true); + +// Autorisations non prevues par le core +include_spip('inc/autoriser'); + +include_spip('inc/crayons-json'); + +if (!function_exists('autoriser_meta_modifier_dist')) { +/** + * Autorisation d'éditer les configurations dans spip_meta + * + * Les admins complets OK pour certains champs, + * Sinon, il faut être webmestre + * + * @note + * Attention sur les SPIP < 11515 (avant 04/2008) inc/autoriser + * passe seulement intval($id) alors qu'ici la cle est une chaine... + * + * @param string $faire Action demandée + * @param string $type Type d'objet sur lequel appliquer l'action + * @param int $id Identifiant de l'objet + * @param array $qui Description de l'auteur demandant l'autorisation + * @param array $opt Options de cette autorisation + * @return bool true s'il a le droit, false sinon +**/ +function autoriser_meta_modifier_dist($faire, $type, $id, $qui, $opt) { + // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc}) + // $id = str_replace('__', '/', $id); + if (in_array("$id", array( + 'nom_site', 'slogan_site', 'descriptif_site', 'email_webmaster' + ))) + return autoriser('configurer', null, null, $qui); + else + return autoriser('webmestre', null, null, $qui); +} +} + +// table spip_messages, la c'est tout simplement non (peut mieux faire, +// mais c'est a voir dans le core/organiseur ou dans autorite) +if (defined('_DIR_PLUGIN_ORGANISEUR')) + include_spip('organiseur_autoriser'); +if (!function_exists('autoriser_message_modifier_dist')) { + function autoriser_message_modifier_dist($faire, $type, $id, $qui, $opt) { + return false; + } +} +//compat 192 documents +if ($GLOBALS['spip_version_code'] < '1.93'){ + if (!function_exists('get_spip_doc')){ + function get_spip_doc($fichier) { + // fichier distant + if (preg_match(',^\w+://,', $fichier)) + return $fichier; + + // gestion d'erreurs, fichier='' + if (!strlen($fichier)) + return false; + + // fichier normal + return (strpos($fichier, _DIR_IMG) === false) + ? _DIR_IMG . $fichier + : $fichier; + } + } +} + +// Autoriser l'usage des crayons ? +function autoriser_crayonner_dist($faire, $type, $id, $qui, $opt) { + // Le type pouvant etre une table, verifier les autoriser('modifier') + // correspondant ; ils demandent le nom de l'objet: spip_articles => article + // ex: spip_articles => 'article' + $type = preg_replace(',^spip_(.*?)s?$,', '\1', $type); + if (strlen($GLOBALS['table_prefix'])) + $type = preg_replace(',^'.$GLOBALS['table_prefix'].'_(.*?)s?$,', '\1', $type); + + // Tables non SPIP ? Si elles sont interdites il faut regarder + // quelle table on appelle, et verifier si elle est "interne" + if (!_CRAYONS_TABLES_EXTERNES) { + include_spip('base/serial'); + include_spip('base/auxiliaires'); + include_spip('public/parametrer'); + if (!isset($GLOBALS['tables_principales']['spip_'.table_objet($type)]) + AND !isset($GLOBALS['tables_auxiliaires']['spip_'.table_objet($type)])) + return false; + } + + // Traduire le modele en liste de champs + if (isset($opt['modele'])) + $opt['champ'] = $opt['modele']; + + // Pour un auteur, si le champ est statut ou email, signaler l'option + // ad hoc (cf. inc/autoriser) + if ($type == 'auteur' + AND in_array($opt['champ'], array('statut', 'email'))) + $opt[$opt['champ']] = true; + + return ( + autoriser('modifier', $type, $id, $qui, $opt) + ); +} + +// Si un logo est demande, on renvoie la date dudit logo (permettra de gerer +// un "modifie par ailleurs" si la date a change, rien de plus) +function valeur_champ_logo($table, $id, $champ) { + $chercher_logo = charger_fonction('chercher_logo', 'inc'); + $on = $chercher_logo($id, id_table_objet($table), 'on'); + return $on ? filemtime($on[0]) : false; +} + +// Idem : si un doc est demande, on renvoie la date du doc +function valeur_champ_document($table, $id, $champ) { + $s = spip_query("SELECT date FROM spip_documents WHERE id_document="._q($id)); + if ($t = sql_fetch($s)) + return $t['date']; +} + +function valeur_champ_vignette($table, $id, $champ) { + $vignette = sql_getfetsel('id_vignette','spip_documents','id_document='.intval($id)); + if(is_numeric($vignette) && ($vignette > 0)){ + $date = sql_getfetsel('date','spip_documents','id_document='.intval($vignette)); + } + return $date ? $date : false; +} +// cette fonction de revision recoit le fichier upload a passer en logo +// en reference : le nom du widget, pour aller chercher d'autres donnees +// (ex: supprimer) +function logo_revision($id, $file, $type, $ref) { + $chercher_logo = charger_fonction('chercher_logo', 'inc'); + $_id_objet = id_table_objet($type); + + // Chargement d'un nouveau logo ? + if ($file['logo']) { + define('FILE_UPLOAD', true); // message pour crayons_json_export :( + + if (include_spip("action/editer_logo") + AND function_exists("logo_modifier")){ + logo_modifier($type, $id, "on", $file['logo']); + } + // compat SPIP < 3.1 + else { + // supprimer l'ancien logo + $on = $chercher_logo($id, $_id_objet, 'on'); + if ($on) @unlink($on[0]); + + // ajouter le nouveau + include_spip('action/iconifier'); + action_spip_image_ajouter_dist( + type_du_logo($_id_objet).'on'.$id, false, false + ); // beurk + } + } + + else { + // Suppression du logo ? + if ($wid = array_pop($ref) + AND $_POST['content_'.$wid.'_logo_supprimer'] == 'on') { + if (include_spip("action/editer_logo") + AND function_exists("logo_supprimer")){ + logo_supprimer($type, $id, "on"); + } + else { + if ($on = $chercher_logo($id, $_id_objet, 'on')) + @unlink($on[0]); + } + } + } + + // Reduire le logo ? + if (is_array($cfg = @unserialize($GLOBALS['meta']['crayons'])) + AND $max = intval($cfg['reduire_logo'])) { + $on = $chercher_logo($id, $_id_objet, 'on'); + include_spip('inc/filtres'); + @copy($on[0], $temp = _DIR_VAR.'tmp'.rand(0,999).'.'.$on[3]); + $img1 = filtrer('image_reduire', $temp, $max); + $img2 = preg_replace(',[?].*,', '', extraire_attribut($img1, 'src')); + if (@file_exists($img2) + AND $img2 != $temp) { + if (include_spip("action/editer_logo") + AND function_exists("logo_modifier")){ + logo_modifier($type, $id, "on", $img2); + } + else { + @unlink($on[0]); + $dest = $on[1].$on[2].'.' + .preg_replace(',^.*\.(gif|jpg|png)$,', '\1', $img2); + @rename($img2,$dest); + } + } + @unlink($temp); + } + + return true; +} + + +// cette fonction de revision recoit le fichier upload a passer en document +function document_fichier_revision($id, $data, $type, $ref) { + + $s = spip_query("SELECT * FROM spip_documents WHERE id_document=".intval($id)); + if (!$t = sql_fetch($s)) + return false; + + /* + // Envoi d'une URL de document distant ? + // TODO: verifier l'extension distante, sinon tout explose + if ($data['fichier'] + AND preg_match(',^(https?|ftp)://.+,', $data['fichier'])) { + include_spip('inc/modifier'); + modifier_contenu('document', $id, + array('champs' => array('fichier', 'distant')), + array('fichier' => $data['fichier'], 'distant' => 'oui') + ); + return true; + } + else + */ + + // Chargement d'un nouveau doc ? + if ($data['document']) { + + $arg = $data['document']; + + /** + * Méthode >= SPIP 3.0 + * ou SPIP 2.x + Mediathèque + */ + if($ajouter_documents = charger_fonction('ajouter_documents','action',true)){ + $actifs = $ajouter_documents($id,array($arg),'', 0,$t['mode']); + $x = reset($actifs); + if(is_numeric($x)) + return true; + else + return false; + } + /** + * Méthode SPIP < 3.0 + */ + else if($ajouter_documents = charger_fonction('ajouter_documents','inc',true)){ + check_upload_error($arg['error']); + $x = $ajouter_documents($arg['tmp_name'], $arg['name'], + 'article', 0, 'document', null, $actifs); + // $actifs contient l'id_document nouvellement cree + // on recopie les donnees interessantes dans l'ancien + $extension=", extension "; + //compat 192 + if ($GLOBALS['spip_version_code'] < '1.93') + $extension=""; + + if ($id_new = array_pop($actifs) + AND $s = spip_query("SELECT fichier, taille, largeur, hauteur $extension, distant FROM spip_documents + WHERE id_document="._q($id_new)) + AND $new = sql_fetch($s)) { + define('FILE_UPLOAD', true); // message pour crayons_json_export :( + + // Une vignette doit rester une image + if ($t['mode'] == 'vignette' + AND !in_array($new['extension'], array('jpg', 'gif', 'png'))) + return false; + + // Maintenant on est bon, on recopie les nouvelles donnees + // dans l'ancienne ligne spip_documents + include_spip('inc/modifier'); + modifier_contenu('document', $id, + # 'champs' inutile a partir de SPIP 11348 + array('champs' => array_keys($new)), + $new); + + // supprimer l'ancien document (sauf s'il etait distant) + if ($t['distant'] != 'oui' + AND file_exists(get_spip_doc($t['fichier']))) + supprimer_fichier(get_spip_doc($t['fichier'])); + + // Effacer la ligne temporaire de spip_document + spip_query("DELETE FROM spip_documents WHERE id_document="._q($id_new)); + + // oublier id_document temporaire (ca marche chez moi, sinon bof) + spip_query("ALTER TABLE spip_documents AUTO_INCREMENT="._q($id_new)); + + return true; + } + } + } +} + +// cette fonction de revision soit supprime la vignette d'un document, +// soit recoit le fichier upload a passer ou remplacer la vignette du document +function vignette_revision($id, $data, $type, $ref) { + $s = sql_fetsel("id_document,id_vignette","spip_documents","id_document=".intval($id)); + if (!is_array($s)) + return false; + + include_spip('inc/modifier'); + include_spip('inc/documents'); + include_spip('action/editer_document');//pour revision_document + // Chargement d'un nouveau doc ? + if ($data['vignette']) { + define('FILE_UPLOAD', true); + if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){ + spip_log('suppression de la vignette'); + // Suppression du document + $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette'])); + if (@file_exists($f = get_spip_doc($vignette))) { + spip_log("efface $f"); + supprimer_fichier($f); + } + sql_delete('spip_documents', 'id_document='.intval($s['id_vignette'])); + sql_delete('spip_documents_liens', 'id_document='.intval($s['id_vignette'])); + + pipeline('post_edition', + array( + 'args' => array( + 'operation' => 'supprimer_document', + 'table' => 'spip_documents', + 'id_objet' => $s['id_vignette'] + ), + 'data' => null + ) + ); + $id_vignette = 0; + } + + $arg = $data['vignette']; + check_upload_error($arg['error']); + // Ajout du document comme vignette + + /** + * Méthode >= SPIP 3.0 + * ou SPIP 2.x + Mediatheque + */ + if($ajouter_documents = charger_fonction('ajouter_documents','action',true)){ + $x = $ajouter_documents(null,array($arg),'', 0, 'vignette'); + $vignette = reset($x); + if(intval($vignette)) + document_modifier($id, array('id_vignette'=>$vignette)); + else if($id_vignette) + document_modifier($id, array('id_vignette'=>$id_vignette)); + } + /** + * Méthode < SPIP 3.0 + */ + else if($ajouter_documents = charger_fonction('ajouter_documents','inc',true)){ + // On remet l'id_vignette a 0 si on l'a supprimé + if($id_vignette) revision_document($s['id_document'], array('id_vignette'=>0)); + $x = $ajouter_documents($arg['tmp_name'], $arg['name'],'','', 'vignette', $id, $actifs); + } + + }else + // Suppression de la vignette ? + if ($wid = array_pop($ref) + AND $_POST['content_'.$wid.'_vignette_supprimer'] == 'on') { + if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){ + // Suppression du document + $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette'])); + if (@file_exists($f = get_spip_doc($vignette))) { + spip_log("efface $f"); + supprimer_fichier($f); + } + sql_delete('spip_documents', 'id_document='.intval($s['id_vignette'])); + sql_delete('spip_documents_liens', 'id_document='.intval($s['id_vignette'])); + + pipeline('post_edition', + array( + 'args' => array( + 'operation' => 'supprimer_document', + 'table' => 'spip_documents', + 'id_objet' => $s['id_vignette'] + ), + 'data' => null + ) + ); + + // On remet l'id_vignette a 0 + revision_document($s['id_document'], array('id_vignette'=>0)); + } + } + return true; +} + + +function colonne_table($type, $col) { + list($distant,$table) = distant_table($type); + $nom_table = ''; + if (!(($tabref = &crayons_get_table($table, $nom_table)) + && isset($tabref['field'][$col]) + && ($brut = $tabref['field'][$col]))) { + return false; + } + $ana = explode(' ', $brut); + $sta = 0; + $sep = ''; + $ret = array('brut' => $brut, + 'type' => '', 'notnull' => false, 'long' => 0, 'def' => ''); + foreach ($ana as $mot) { + switch ($sta) { + case 0: $ret['type'] = ($mot = strtolower($mot)); + case 1: if ($mot[strlen($mot) - 1] == ')') { + $pos = strpos($mot, '('); + $ret['type'] = strtolower(substr($mot, 0, $pos++)); + $vir = explode(',', substr($mot, $pos, -1)); + if ($ret['type'] == 'enum') { + $ret['enum'] = $vir; + } elseif (count($vir) > 1) { + $ret['long'] = $vir; + } else { + $ret['long'] = $vir[0]; + } + $sta = 1; + continue; + } + if (!$sta) { + $sta = 1; + continue; + } + case 2: switch (strtolower($mot)) { + case 'not': + $sta = 3; + continue; + case 'default': + $sta = 4; + continue; + } + continue; + case 3: $ret['notnull'] = strtolower($mot) == 'null'; + $sta = 2; + continue; + case 4: $df1 = strpos('"\'', $mot[0]) !== false? $mot[0] : ''; + $sta = 5; + case 5: $ret['def'] .= $sep . $mot; + if (!$df1) { + $sta = 2; + continue; + } + if ($df1 == $mot[strlen($mot) - 1]) { + $ret['def'] = substr($ret['def'], 1, -1); + $sta = 2; + } + $sep = ' '; + continue; + } + } + return $ret; +} + + +/** + * Obtient le nom de la table ainsi que sa ou ses clés primaires + * + * @param string $type + * Table sur laquelle s'applique le crayon. + * Ce type peut contenir le nom d'un connecteur distant tel que `{connect}__{table}` + * + * @return array|bool + * - false si on ne trouve pas de table ou de table ayant de clé primaire + * - liste : + * - - nom de la table sql + * - - tableau des noms de clés primaires +**/ +function crayons_get_table_name_and_primary($type) { + static $types = array(); + if (isset($types[$type])) { + return $types[$type]; + } + + $nom_table = ''; + if ($tabref = &crayons_get_table($type, $nom_table) + and ($tabid = explode(',', $tabref['key']['PRIMARY KEY']))) + { + return $types[$type] = array($nom_table, $tabid); + } + spip_log('crayons: table ' . $type . ' inconnue'); + return $types[$type] = false; +} + + +function table_where($type, $id, $where_en_tableau = false) { + + + if (!$infos = crayons_get_table_name_and_primary($type)) { + return array(false, false); + } + + list($nom_table, $tabid) = $infos; + + + if (is_scalar($id)) + $id = explode('-', $id); + // sortie tableau pour sql_updateq + if ($where_en_tableau) { + $where = array(); + foreach ($id as $idcol => $idval) { + $where[] = '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . sql_quote($idval); + } + // sinon sortie texte pour sql_query + } else { + + $where = $and = ''; + foreach ($id as $idcol => $idval) { + $where .= $and . '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . _q($idval); + $and = ' AND '; + } + } + return array($nom_table, $where); +} +// var_dump(colonne_table('forum', 'id_syndic')); die(); + +function valeur_colonne_table_dist($type, $col, $id) { + + // Table introuvable ou sans clé primaire + if (!$infos = crayons_get_table_name_and_primary($type)) { + return false; + } + $table = reset($infos); + + $r = array(); + + // valeurs non SQL + foreach ($col as $champ) { + if (function_exists($f = 'valeur_champ_'.$table.'_'.$champ) OR function_exists($f = 'valeur_champ_'.$champ)) { + $r[$champ] = $f($table, $id, $champ); + $col = array_diff($col, array($champ)); + } + } + + // valeurs SQL + if (count($col)) { + list($distant, $table) = distant_table($type); + list($nom_table, $where) = table_where($type, $id); + + if ($s = spip_query( + 'SELECT `' . implode($col, '`, `') . + '` FROM ' . $nom_table . ' WHERE ' . $where, $distant) + AND $t = sql_fetch($s)){ + $r = array_merge($r, $t); + } + } + + return $r; +} + +/** + * Extrait la valeur d'une ou plusieurs colonnes d'une table + * + * @param string $table + * Type d'objet de la table (article) + * @param string|array $col + * Nom de la ou des colonnes (ps) + * @param string $id + * Identifiant de l'objet + * @return array + * Couples Nom de la colonne => Contenu de la colonne +**/ +function valeur_colonne_table($table, $col, $id) { + if (!is_array($col)) + $col = array($col); + + if (function_exists($f = $table.'_valeur_colonne_table_dist') + OR function_exists($f = $table.'_valeur_colonne_table') + OR $f = 'valeur_colonne_table_dist') + return $f($table, $col, $id); +} + +/** + * Extrait la valeur d'une configuration en meta + * + * Pour ces données, il n'y a toujours qu'une colonne (valeur), + * mais on gère l'enregistrement et la lecture via lire_config ou ecrire_config + * dès que l'on demande des sous parties d'une configuration. + * + * On ne retourne alors ici dans 'valeur' que la sous-partie demandée si + * c'est le cas. + * + * @param string $table + * Nom de la table (meta) + * @param array $col + * Nom des colonnes (valeur) + * @param string $id + * Nom ou clé de configuration (descriptif_site ou demo__truc pour demo/truc) + * @return array + * Couple valeur => Contenu de la configuration +**/ +function meta_valeur_colonne_table_dist($table, $col, $id) { + // Certaines clés de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc}) + $id = str_replace('__', '/', $id); + + // Éviter de planter les vieux SPIP + if (false === strpos($id, '/')) { + $config = isset($GLOBALS['meta'][$id]) ? $GLOBALS['meta'][$id] : ''; + // SPIP 3 ou Bonux 2 ou CFG + } else { + include_spip('inc/config'); + $config = lire_config($id, ''); + } + return array('valeur' => $config); +} + + +function return_log($var) { + die(crayons_json_export(array('$erreur'=> var_export($var,true)))); +} + +function _U($texte, $params=array()) { + include_spip('inc/charsets'); + return unicode2charset(html2unicode(_T($texte, $params))); +} + +/** + * Obtenir la configuration des crayons + * + * @note wdgcfg = widget config :-) + * + * @return array + * Couples : attribut => valeur +**/ +function wdgcfg() { + $php = function_exists('crayons_config') ? crayons_config() : array(); + include_spip('inc/meta'); + lire_metas(); + global $meta; + $metacrayons = empty($meta['crayons']) ? array() : unserialize($meta['crayons']); + $wdgcfg = array(); + foreach (array( + 'msgNoChange' => false, + 'msgAbandon' => false, /* etait: true */ + 'filet' => false, + 'yellow_fade' => false, + 'clickhide' => false /* etait: true */ + ) + as $cfgi => $def) { + $wdgcfg[$cfgi] = isset($php[$cfgi]) ? $php[$cfgi] : + isset($metacrayons[$cfgi]) ? $metacrayons[$cfgi] : $def; + } + return $wdgcfg; +} + +function &crayons_get_table($type, &$nom_table) { + list($distant,$table) = distant_table($type); + static $return = array(); + static $noms = array(); + if (!isset($return[$table])) { + $try = array(table_objet_sql($table), 'spip_'.table_objet($table), 'spip_' . $table . 's', $table . 's', 'spip_' . $table, $table); + + // premiere possibilite (à partir de 1.9.3) : regarder directement la base + if (function_exists('sql_showtable')) { + foreach ($try as $nom) { + if ($q = sql_showtable($nom , !$distant , $distant)) { + $noms[$table] = $nom; + $return[$table] = $q; + break; + } + } + } + + // seconde, une heuristique 1.9.2 + if (!isset($return[$table])) { + include_spip('base/serial'); + include_spip('base/auxiliaires'); + include_spip('public/parametrer'); + foreach(array('tables_principales', 'tables_auxiliaires') as $categ) { + foreach ($try as $nom) { + if (isset($GLOBALS[$categ][$nom])) { + $noms[$table] = $nom; + $return[$table] = & $GLOBALS[$categ][$nom]; + break 2; + } + } + } + } + } + + $nom_table = $noms[$table]; + return $return[$table]; +} + +function distant_table($type) { + //separation $type en $distant $table + //separateur double underscore "__" + strstr($type,'__')? list($distant,$table) = explode('__',$type) : list($distant,$table) = array(False,$type); + return array($distant,$table); +} +?> diff --git a/www/plugins/crayons/js/crayons-fade.js b/www/plugins/crayons/js/crayons-fade.js new file mode 100644 index 0000000..47f5b88 --- /dev/null +++ b/www/plugins/crayons/js/crayons-fade.js @@ -0,0 +1,101 @@ + +// Gestion du Yellow Fade (fonctionnalite optionnelle) +function easeInOut(minValue,maxValue,totalSteps,actualStep,powr) { + var delta = maxValue - minValue; + var stepp = minValue+(Math.pow(((1 / totalSteps)*actualStep),powr)*delta); + return Math.ceil(stepp) +}; + +function doBGFade(elem,startRGB,endRGB,finalColor,steps,intervals,powr) { + if (elem.bgFadeInt) window.clearInterval(elem.bgFadeInt); + var actStep = 0; + elem.bgFadeInt = window.setInterval( + function() { + elem.style.backgroundColor = "rgb("+ + easeInOut(startRGB[0],endRGB[0],steps,actStep,powr)+","+ + easeInOut(startRGB[1],endRGB[1],steps,actStep,powr)+","+ + easeInOut(startRGB[2],endRGB[2],steps,actStep,powr)+")"; + actStep++; + if (actStep > steps) { + elem.style.backgroundColor = finalColor; + window.clearInterval(elem.bgFadeInt); + } + } + ,intervals) +}; + +function findPos(obj) { + var curleft = curtop = 0; + if (obj.offsetParent) { + curleft = obj.offsetLeft; + curtop = obj.offsetTop; + while (obj = obj.offsetParent) { + curleft += obj.offsetLeft; + curtop += obj.offsetTop; + } + } + return [curleft,curtop]; +}; + +// demarrage crayons-fade +jQuery(document).ready(function() { + if (configCrayons.cfg.yellow_fade) { + // Activer le Yellow Fade pour les elements editables + jQuery("div.crayon").hover(function(){doBGFade(this,[255,255,180],[255,255,255],'transparent',40,20,4);}, function(){}); + } + + if (configCrayons.cfg.filet) { + // on rajoute une div supplémentaire qui se cale avec la div courante + // C'est elle qui va s'afficher lors du hover + + // esthetique + jQuery('.crayon-icones img',this).css({ + 'padding':'2px', + 'border':'2px solid #999', + 'border-left':'0', + 'background-color':'#FFF' + }); + + var test=0; + + jQuery('.crayon-autorise').each( + function(){ + var contenu = jQuery(this).html(); + jQuery(this) + .css('height',this.offsetHeight + 'px') + .html('
'); + jQuery(this) + .find('div') + .html(contenu) + .css('position','absolute') + .css('width',this.offsetWidth + 'px'); + jQuery(this) + .prepend('
') + .find('.survol') + .css('border','1px solid red') + .css('display','none') + .css('position','absolute') + .css('height',(this.offsetHeight - 2) + 'px') + .css('width',(this.offsetWidth - 2) + 'px'); + if (jQuery.browser.msie) { + jQuery('#survol') + .css('width',this.offsetWidth + 'px') + .css('height',this.offsetHeight + 'px'); + } + } + ); + + jQuery('.crayon-autorise').hover( + function(){ + if (jQuery.browser.msie) jQuery(this).addClass('crayon-hover'); + jQuery('.survol', this).css('display','block'); + }, + function(){ + if (jQuery.browser.msie) jQuery(this).removeClass('crayon-hover'); + jQuery('.survol', this).css('display','none'); + } + ); + + } + +}); diff --git a/www/plugins/crayons/js/crayons.js b/www/plugins/crayons/js/crayons.js new file mode 100644 index 0000000..00300b5 --- /dev/null +++ b/www/plugins/crayons/js/crayons.js @@ -0,0 +1,575 @@ +(function($){ +/* + * crayons.js (c) Fil, toggg, 2006-2013 -- licence GPL + */ + +// le prototype configuration de Crayons +$.prototype.cfgCrayons = function (options) { + this.url_crayons_html = '?action=crayons_html'; + this.img = { + 'searching':{'txt':'En attente du serveur ...'}, + 'edit':{'txt':'Editer'}, + 'img-changed':{'txt':'Deja modifie'} + }; + this.txt = { + }; + for (opt in options) { + this[opt] = options[opt]; + } +}; + +$.prototype.cfgCrayons.prototype.mkimg = function(what, extra) { + var txt = this.img[what] ? this.img[what].txt : this.img['crayon'].txt; + return ''; +}; + +$.prototype.cfgCrayons.prototype.iconclick = function(c, type) { + + // le + qui passe en prive pour editer tout si classe type--id + var link = c.match(/\b(\w+)--(\d+)\b/); + link = link ? + '' + this.mkimg('edit', ' (' + link[1] + ' ' + link[2] + ')') + '' : ''; + + // on recherche une class du type type-champ-id + // comme article-texte-10 pour le texte de l'article 10 + // ou meta-valeur-meta + var cray = + c.match(/\b\w+-(\w+)-\d(?:-\w+)+\b/) // numeros_lien-type-2-3-article (table-champ-cles) + || c.match(/\b\w+-(\w+)-\d+\b/) // article-texte-10 (inclu dans le precedent, mais bon) + || c.match(/\b\meta-valeur-(\w+)\b/) // meta-valeur-xx + ; + + var boite = !cray ? '' : this.mkimg(type, ' (' + cray[1] + ')'); + + return "" + boite + + this.mkimg('img-changed', cray ? ' (' + cray[1] + ')': '') + + link +""; +}; + +function entity2unicode(txt) +{ + var reg = txt.split(/&#(\d+);/i); + for (var i = 1; i < reg.length; i+=2) { + reg[i] = String.fromCharCode(parseInt(reg[i])); + } + return reg.join(''); +}; + +function uniAlert(txt) +{ + alert(entity2unicode(txt)); +}; + +function uniConfirm(txt) +{ + return confirm(entity2unicode(txt)); +}; + +// donne le crayon d'un element +$.fn.crayon = function(){ + if (this.length) + return $( + $.map(this, function(a){ + return '#'+($(a).find('.crayon-icones').attr('rel')); + }) + .join(',')); + else + return $([]); +}; + +// ouvre un crayon +$.fn.opencrayon = function(evt, percent) { + if (evt && evt.stopPropagation) { + evt.stopPropagation(); + } + return this + .each(function(){ + // verifier que je suis un crayon + if (!$(this).is('.crayon')) + return; + + // voir si je dispose deja du crayon comme voisin + if ($(this).is('.crayon-has')) { + $(this) + .css('visibility','hidden') + .crayon() + .show(); + } + // sinon charger le formulaire + else { + // sauf si je suis deja en train de le charger (lock) + if ($(this).find("em.crayon-searching").length) { + return; + } + $(this) + .find('>span.crayon-icones span') + .append(configCrayons.mkimg('searching')); // icone d'attente + var me=this; + var offset = $(this).offset(); + var params = { + 'top': offset.top, + 'left': offset.left, + 'w': $(this).width(), + 'h': $(this).height(), + 'ww': (window.innerWidth ? window.innerWidth : (document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.offsetWidth)), + 'wh': (window.innerHeight ? window.innerHeight : (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.offsetHeight)), + 'em': $(this).px('fontSize'), // eviter un bug MSIE sur fontSize + 'class': me.className, + 'color': $(this).css('color'), + 'font-size': $(this).px('fontSize'), + 'font-family': $(this).css('fontFamily'), + 'font-weight': $(this).css('fontWeight'), + 'line-height': $(this).css('lineHeight'), + 'min-height': $(this).css('lineHeight'), + 'text-align': $(this).css('textAlign'), + 'background-color': $(this).css('backgroundColor'), + 'self': configCrayons.self + }; + if (me.type) params.type = me.type; + if (params['background-color'] == 'transparent' + || params['background-color'] == 'rgba(0, 0, 0, 0)') { + $(me).parents() + .each(function(){ + var bg = $(this).css('backgroundColor'); + if (bg != 'transparent' + && (params['background-color'] == 'transparent' + || params['background-color'] == 'rgba(0, 0, 0, 0)')) + params['background-color'] = bg; + }); + } + $.post(configCrayons.url_crayons_html, + params, + function (c) { + try { + c = $.parseJSON(c); + } catch(e) { + c = {'$erreur': 'erreur de communication :' + ' ' + e.message, '$html':''}; + } + $(me) + .find("em.crayon-searching") + .remove(); + if (c.$erreur) { + uniAlert(c.$erreur); + return false; + } + id_crayon++; + + var position = 'absolute'; + $(me).parents().each(function(){ + if($(this).css("position") == "fixed") + position = 'fixed'; + }); + + $(me) + .css('visibility','hidden') + .addClass('crayon-has') + .find('>.crayon-icones') + .attr('rel','crayon_'+id_crayon); + if ($.browser.msie) $(me).css({'zoom':1}); + var pos = $(me).offset(); + $('
') + .css({ + 'position':position, + 'top':pos['top']-1, + 'left':pos['left']-1 + }) + .appendTo('body') + .html(c.$html); + $(me) + .activatecrayon(percent); + // Si le crayon a une taille mini qui le fait deborder + // a droite de l'ecran, recadrer vers la gauche + var diff = $('#crayon_'+id_crayon).offset().left + $('#crayon_'+id_crayon).width() - $(window).width(); + if (diff>0) { + $('#crayon_'+id_crayon) + .css({'left': parseInt(pos['left'])-diff}); + } + } + ); + } + }); +}; + +// annule le crayon ouvert (fonction destructive) +$.fn.cancelcrayon = function() { + this + .filter('.crayon-has') + .css('visibility','visible') + .removeClass('crayon-has') + .removeClass('crayon-changed') + .crayon() + .remove(); + return this; +}; + +// masque le crayon ouvert +$.fn.hidecrayon = function() { + this + .filter('.crayon-has') + .css('visibility','visible') + .crayon() + .hide() + .removeClass('crayon-hover'); + return this; +}; + +// active un crayon qui vient d'etre charge +$.fn.activatecrayon = function(percent) { + var focus = false; + this + .crayon() + .click(function(e){ + e.stopPropagation(); + }); + this + .each(function(){ + var me = $(this); + var crayon = $(this).crayon(); + crayon + .find('form') + .append( + $('') + .attr('value',configCrayons.self) + ) + .ajaxForm({ + "dataType":"json", + "error": function(d) { + uniAlert('erreur de communication'); + crayon + .empty() + .append( + $('
') + .html(d.responseText || d.error || 'erreur inconnue') + ) + .css({ + background: 'white', + color: 'black', + width: '480px', + border: 'red solid 2px', + padding: '10px'} + ); + }, + "success": function(d) { + // parfois le JSON n'est pas renvoye sous forme d'objet + // mais d'une chaine encadree de
...
+ if (typeof d == "string") { + try { + d = $.parseJSON(d.replace(/^
/,'').replace(/<[/]pre>$/,''));
+					} catch(e) {
+						d = {'$erreur': 'erreur de communication :' + '  ' + e.message, '$html':''};
+					}
+				}
+				me
+				.find("em.crayon-searching")
+					.remove();
+
+				//Remise a zero des warnings invalides (unwrap)
+				crayon
+				.find("span.crayon-invalide p")
+					  .remove();
+				crayon
+				.find("span.crayon-invalide")
+					  .each(function(){
+					      $(this).replaceWith( this.childNodes );
+						}
+					    );
+
+				if(d.$invalides) {
+					for (invalide in d.$invalides) {
+						//Affichage des warnings invalides
+						d.$invalides[invalide]['retour']?retour=d.$invalides[invalide]['retour']:retour='';
+						d.$invalides[invalide]['msg']?msg=d.$invalides[invalide]['msg']:msg='';
+						crayon
+						    .find("*[name='content_"+invalide+"']")
+							.wrap("")
+						    .parent()
+						    .append("

" + + retour + + " " + + msg + + "

" + ); + } + + } + + if (d.$erreur > '') { + if (d.$annuler) { + if (d.$erreur > ' ') { + uniAlert(d.$erreur); + } + me + .cancelcrayon(); + } else { + uniAlert(d.$erreur+'\n'+configCrayons.txt.error); + } + } + + if (d.erreur > '' || d.$invalides) { + crayon + .find('form') + .css('opacity', 1.0) + .find(".crayon-boutons,.resizehandle") + .show() + .end() + .find('.crayon-searching') + .remove(); + return false; + } + // Desactive celui pour qui on vient de recevoir les nouvelles donnees + $(me) + .cancelcrayon(); + // Insere les donnees dans *tous* les elements ayant le meme code + var tous = $( + '.crayon.crayon-autorise.' + + me[0].className.match(/crayon ([^ ]+)/)[1] + ) + .html( + d[$('input.crayon-id', crayon).val()] + ) + .iconecrayon(); + // Declencher le onAjaxLoad normal de SPIP + if (typeof jQuery.spip == 'object' && typeof jQuery.spip.triggerAjaxLoad == 'function') { + jQuery.spip.triggerAjaxLoad(tous.get()); + } + // SPIP 2.x + else if (typeof triggerAjaxLoad == 'function') { + triggerAjaxLoad(tous.get()); + } + }}) + .bind('form-submit-validate',function(form,a, e, options, veto){ + if(!veto.veto) + crayon + .find('form') + .css('opacity', 0.5) + .after(configCrayons.mkimg('searching')) // icone d'attente + .find(".crayon-boutons,.resizehandle") + .hide(); + }) + // keyup pour les input et textarea ... + .keyup(function(e){ + crayon + .find(".crayon-boutons") + .show(); + me + .addClass('crayon-changed'); + e.cancelBubble = true; // ne pas remonter l'evenement vers la page + }) + // ... change pour les select : ici on submit direct, pourquoi pas + .change(function(e){ + crayon + .find(".crayon-boutons") + .show(); + me + .addClass('crayon-changed'); + e.cancelBubble = true; + }) + .keypress(function(e){ + e.cancelBubble = true; + }) + // focus par defaut (crayons sans textarea/text, mais uniquement menus ou fichiers) + .find('input:visible:not(:disabled):not([readonly]):first').focus().end() + .find("textarea.crayon-active,input.crayon-active[type=text]") + .each(function(n){ + // focus pour commencer a taper son texte directement dans le champ + // sur le premier textarea non readonly ni disabled + // on essaie de positionner la selection (la saisie) au niveau du clic + // ne pas le faire sur un input de [type=file] + if (n==0) { + if(!$(this).is(':disabled, [readonly]')){ + this.focus(); + focus = true; + } + // premiere approximation, en fonction de la hauteur du clic + var position = parseInt(percent * this.textLength); + this.selectionStart=position; + this.selectionEnd=position; + }else if(!focus && !$(this).is(':disabled, [readonly]')) + this.focus(); + }) + .end() + .keydown(function(e){ + if(!e.charCode && e.keyCode == 119 /* F8, windows */) { + crayon + .find("form.formulaire_crayon") + .submit(); + } + if (e.keyCode == 27) { /* esc */ + me + .cancelcrayon(); + } + }) + .keypress(function(e){ + // Clavier pour sauver + if ( + (e.ctrlKey && ( + /* ctrl-s ou ctrl-maj-S, firefox */ + ((e.charCode||e.keyCode) == 115) || ((e.charCode||e.keyCode) == 83)) + /* ctrl-s, safari */ + || (e.charCode==19 && e.keyCode==19) + ) || + ( + e.shiftKey && (e.keyCode == 13) /* shift-return */ + ) + ) { + crayon + .find("form.formulaire_crayon") + .submit(); + } + var maxh = this.className.match(/\bmaxheight(\d+)?\b/); + if (maxh) { + maxh = maxh[1] ? parseInt(maxh[1]) : 200; + maxh = this.scrollHeight < maxh ? this.scrollHeight : maxh; + if (maxh > this.clientHeight) { + $(this).css('height', maxh + 'px'); + } + } + }) + .find(".crayon-submit") + .click(function(e){ + e.stopPropagation(); + $(this) + .parents("form:eq(0)") + .submit(); + }) + .end() + .find(".crayon-cancel") + .click(function(e){ + e.stopPropagation(); + me + .cancelcrayon(); + }) + .end() + // decaler verticalement si la fenetre d'edition n'est pas visible + .each(function(){ + var offset = $(this).offset(); + var hauteur = parseInt($(this).css('height')); + var scrolltop = $(window).scrollTop(); + var h = $(window).height(); + if (offset['top'] - 5 <= scrolltop) + $(window).scrollTop(offset['top'] - 5); + else if (offset['top'] + hauteur - h + 20 > scrolltop) + $(window).scrollTop(offset['top'] + hauteur - h + 30); + // Si c'est textarea, on essaie de caler verticalement son contenu + // et on lui ajoute un resizehandle + $("textarea", this) + .each(function(){ + if (percent && this.scrollHeight > hauteur) { + this.scrollTop = this.scrollHeight * percent - hauteur; + } + }) + .resizehandle() + // decaler les boutons qui suivent un resizer de 16px vers le haut + .next('.resizehandle') + .next('.crayon-boutons') + .addClass('resizehandle_boutons'); + }) + .end(); + // Declencher le onAjaxLoad normal de SPIP + // (apres donc le chargement de la page de saisie (controleur)) + if (typeof jQuery.spip == 'object' && typeof jQuery.spip.triggerAjaxLoad == 'function') { + jQuery.spip.triggerAjaxLoad(crayon.get()); + } + // SPIP 2.x + else if (typeof triggerAjaxLoad == 'function') { + triggerAjaxLoad(crayon.get()); + } + }); +}; + +// insere les icones et le type de crayon (optionnel) dans l'element +$.fn.iconecrayon = function(){ + return this.each(function() { + var ctype = this.className.match(/\b[^-]type_(\w+)\b/); + type = (ctype) ? ctype[1] : 'crayon'; + if (ctype) this.type = type; // Affecte son type a l'objet crayon + $(this).prepend(configCrayons.iconclick(this.className, type)) + .find('.crayon-' + type + ', .crayon-img-changed') // le crayon a clicker lui-meme et sa memoire + .click(function(e){ + $(this).parents('.crayon:eq(0)').opencrayon(e); + }); + }); +}; + +// initialise les crayons +$.fn.initcrayon = function(){ + var editme = function(e){ + timeme=null; + $(this).opencrayon(e, + // calcul du "percent" du click par rapport a la hauteur totale du div + ((e.pageY ? e.pageY : e.clientY) - document.body.scrollTop - this.offsetTop) + / this.clientHeight); + }; + var timeme; + this + .addClass('crayon-autorise') + .dblclick(editme) + .bind("touchstart",function(e){var me=this;timeme=setTimeout(function(){editme.apply(me,[e]);},800);}) + .bind("touchend",function(e){if (timeme) {clearTimeout(timeme);timeme=null;}}) + .iconecrayon() + .hover( // :hover pour MSIE + function(){ + $(this) + .addClass('crayon-hover') + .find('>span.crayon-icones') + .find('>span>em.crayon-' + (this.type||'crayon') + ',>span>em.crayon-edit') + .show();//'visibility','visible'); + },function(){ + $(this) + .removeClass('crayon-hover') + .find('>span.crayon-icones') + .find('>span>em.crayon-' + (this.type||'crayon') + ',>span>em.crayon-edit') + .hide();//('visibility','hidden'); + } + ); + return this; +}; + +// demarrage +$.fn.crayonsstart = function() { + if (!configCrayons.droits) return; + id_crayon = 0; // global + + // sortie, demander pour sauvegarde si oubli + if (configCrayons.txt.sauvegarder) { + $(window).unload(function(e) { + var chg = $(".crayon-changed"); + if (chg.length && uniConfirm(configCrayons.txt.sauvegarder)) { + chg.crayon().find('form').submit(); + } + }); + } + + // demarrer les crayons + if ((typeof crayons_init_dynamique == 'undefined') || (crayons_init_dynamique==false)) { + + // compat jQuery 1.9 + if (typeof $.fn.live == 'undefined') { + $.fn.live = function( types, data, fn ) { + $( this.context ).on( types, this.selector, data, fn ); + return this; + }; + } + $('.crayon:not(.crayon-init)') + .live('mouseover touchstart', function(e) { + $(this) + .addClass('crayon-init') + .filter(configCrayons.droits) + .initcrayon() + .trigger('mouseover'); + if (e.type=='touchstart') + $(this).trigger('touchstart'); + }); + } + + // un clic en dehors ferme tous les crayons ouverts ? + if (configCrayons.cfg.clickhide) + $("html") + .click(function(){ + $('.crayon-has') + .hidecrayon(); + }); +}; + +})(jQuery); diff --git a/www/plugins/crayons/js/jquery.form.js b/www/plugins/crayons/js/jquery.form.js new file mode 100644 index 0000000..c0fba53 --- /dev/null +++ b/www/plugins/crayons/js/jquery.form.js @@ -0,0 +1,825 @@ +/*! + * jQuery Form Plugin + * version: 2.73 (03-MAY-2011) + * @requires jQuery v1.3.2 or later + * + * Examples and documentation at: http://malsup.com/jquery/form/ + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + */ +;(function($) { + +/* + Usage Note: + ----------- + Do not use both ajaxSubmit and ajaxForm on the same form. These + functions are intended to be exclusive. Use ajaxSubmit if you want + to bind your own submit handler to the form. For example, + + $(document).ready(function() { + $('#myForm').bind('submit', function(e) { + e.preventDefault(); // <-- important + $(this).ajaxSubmit({ + target: '#output' + }); + }); + }); + + Use ajaxForm when you want the plugin to manage all the event binding + for you. For example, + + $(document).ready(function() { + $('#myForm').ajaxForm({ + target: '#output' + }); + }); + + When using ajaxForm, the ajaxSubmit function will be invoked for you + at the appropriate time. +*/ + +/** + * ajaxSubmit() provides a mechanism for immediately submitting + * an HTML form using AJAX. + */ +$.fn.ajaxSubmit = function(options) { + // fast fail if nothing selected (http://dev.jquery.com/ticket/2752) + if (!this.length) { + log('ajaxSubmit: skipping submit process - no element selected'); + return this; + } + + if (typeof options == 'function') { + options = { success: options }; + } + + var action = this.attr('action'); + var url = (typeof action === 'string') ? $.trim(action) : ''; + if (url) { + // clean url (don't include hash vaue) + url = (url.match(/^([^#]+)/)||[])[1]; + } + url = url || window.location.href || ''; + + options = $.extend(true, { + url: url, + success: $.ajaxSettings.success, + type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57) + iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank' + }, options); + + // hook for manipulating the form data before it is extracted; + // convenient for use with rich editors like tinyMCE or FCKEditor + var veto = {}; + this.trigger('form-pre-serialize', [this, options, veto]); + if (veto.veto) { + log('ajaxSubmit: submit vetoed via form-pre-serialize trigger'); + return this; + } + + // provide opportunity to alter form data before it is serialized + if (options.beforeSerialize && options.beforeSerialize(this, options) === false) { + log('ajaxSubmit: submit aborted via beforeSerialize callback'); + return this; + } + + var n,v,a = this.formToArray(options.semantic); + if (options.data) { + options.extraData = options.data; + for (n in options.data) { + if(options.data[n] instanceof Array) { + for (var k in options.data[n]) { + a.push( { name: n, value: options.data[n][k] } ); + } + } + else { + v = options.data[n]; + v = $.isFunction(v) ? v() : v; // if value is fn, invoke it + a.push( { name: n, value: v } ); + } + } + } + + // give pre-submit callback an opportunity to abort the submit + if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) { + log('ajaxSubmit: submit aborted via beforeSubmit callback'); + return this; + } + + // fire vetoable 'validate' event + this.trigger('form-submit-validate', [a, this, options, veto]); + if (veto.veto) { + log('ajaxSubmit: submit vetoed via form-submit-validate trigger'); + return this; + } + + var q = $.param(a); + + if (options.type.toUpperCase() == 'GET') { + options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q; + options.data = null; // data is null for 'get' + } + else { + options.data = q; // data is the query string for 'post' + } + + var $form = this, callbacks = []; + if (options.resetForm) { + callbacks.push(function() { $form.resetForm(); }); + } + if (options.clearForm) { + callbacks.push(function() { $form.clearForm(); }); + } + + // perform a load on the target only if dataType is not provided + if (!options.dataType && options.target) { + var oldSuccess = options.success || function(){}; + callbacks.push(function(data) { + var fn = options.replaceTarget ? 'replaceWith' : 'html'; + $(options.target)[fn](data).each(oldSuccess, arguments); + }); + } + else if (options.success) { + callbacks.push(options.success); + } + + options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg + var context = options.context || options; // jQuery 1.4+ supports scope context + for (var i=0, max=callbacks.length; i < max; i++) { + callbacks[i].apply(context, [data, status, xhr || $form, $form]); + } + }; + + // are there files to upload? + var fileInputs = $('input:file', this).length > 0; + var mp = 'multipart/form-data'; + var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp); + + // options.iframe allows user to force iframe mode + // 06-NOV-09: now defaulting to iframe mode if file input is detected + if (options.iframe !== false && (fileInputs || options.iframe || multipart)) { + // hack to fix Safari hang (thanks to Tim Molendijk for this) + // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d + if (options.closeKeepAlive) { + $.get(options.closeKeepAlive, fileUpload); + } + else { + fileUpload(); + } + } + else { + $.ajax(options); + } + + // fire 'notify' event + this.trigger('form-submit-notify', [this, options]); + return this; + + + // private function for handling file uploads (hat tip to YAHOO!) + function fileUpload() { + var form = $form[0]; + + if ($(':input[name=submit],:input[id=submit]', form).length) { + // if there is an input with a name or id of 'submit' then we won't be + // able to invoke the submit fn on the form (at least not x-browser) + alert('Error: Form elements must not have name or id of "submit".'); + return; + } + + var s = $.extend(true, {}, $.ajaxSettings, options); + s.context = s.context || s; + var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id; + var $io = $('