[PLUGINS] +set de base
authorLudovic CHEVALIER <ludovic.chevalier@heureux-cyclage.org>
Tue, 25 Jun 2013 16:44:01 +0000 (18:44 +0200)
committerLudovic CHEVALIER <ludovic.chevalier@heureux-cyclage.org>
Tue, 25 Jun 2013 16:44:01 +0000 (18:44 +0200)
1424 files changed:
www/plugins/Menu_langue_lien/balise/menu_lang.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/fonds/cfg_menu_lang_liens.html [new file with mode: 0644]
www/plugins/Menu_langue_lien/formulaires/configurer_menu_lang_liens.html [new file with mode: 0644]
www/plugins/Menu_langue_lien/formulaires/menu_lang.html [new file with mode: 0644]
www/plugins/Menu_langue_lien/img_pack/world_link-16.png [new file with mode: 0755]
www/plugins/Menu_langue_lien/img_pack/world_link-24.png [new file with mode: 0644]
www/plugins/Menu_langue_lien/img_pack/world_link-32.png [new file with mode: 0755]
www/plugins/Menu_langue_lien/lang/mll.xml [new file with mode: 0644]
www/plugins/Menu_langue_lien/lang/mll_en.php [new file with mode: 0755]
www/plugins/Menu_langue_lien/lang/mll_es.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/lang/mll_fr.php [new file with mode: 0755]
www/plugins/Menu_langue_lien/lang/mll_sk.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/lang/paquet-mll.xml [new file with mode: 0644]
www/plugins/Menu_langue_lien/lang/paquet-mll_en.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/lang/paquet-mll_es.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/lang/paquet-mll_fr.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/lang/paquet-mll_sk.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/mll_options.php [new file with mode: 0644]
www/plugins/Menu_langue_lien/mll_pipelines.php [new file with mode: 0755]
www/plugins/Menu_langue_lien/mll_styles.css [new file with mode: 0755]
www/plugins/Menu_langue_lien/paquet.xml [new file with mode: 0644]
www/plugins/Menu_langue_lien/plugin.xml [new file with mode: 0644]
www/plugins/Menu_langue_lien/prive/squelettes/contenu/configurer_mll.html [new file with mode: 0644]
www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-16.png [new file with mode: 0755]
www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-24.png [new file with mode: 0644]
www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-32.png [new file with mode: 0755]
www/plugins/Menu_langue_lien/svn.revision [new file with mode: 0644]
www/plugins/abomailmans/abomailman_template.html [new file with mode: 0644]
www/plugins/abomailmans/abomailmans_administrations.php [new file with mode: 0644]
www/plugins/abomailmans/abomailmans_autoriser.php [new file with mode: 0755]
www/plugins/abomailmans/abomailmans_fonctions.php [new file with mode: 0755]
www/plugins/abomailmans/abomailmans_pipelines.php [new file with mode: 0755]
www/plugins/abomailmans/base/abomailmans_install.php [new file with mode: 0755]
www/plugins/abomailmans/content/newsletter.html [new file with mode: 0644]
www/plugins/abomailmans/contenu/page-newsletter.html [new file with mode: 0644]
www/plugins/abomailmans/controleurs/abomailman_descriptif.html [new file with mode: 0644]
www/plugins/abomailmans/controleurs/abomailman_titre.html [new file with mode: 0644]
www/plugins/abomailmans/formulaires/abomailman.html [new file with mode: 0644]
www/plugins/abomailmans/formulaires/abomailman.php [new file with mode: 0644]
www/plugins/abomailmans/formulaires/abomailman_envoi_liste.html [new file with mode: 0644]
www/plugins/abomailmans/formulaires/abomailman_envoi_liste.php [new file with mode: 0644]
www/plugins/abomailmans/formulaires/abomailman_mini_une_liste.html [new file with mode: 0644]
www/plugins/abomailmans/formulaires/abomailman_mini_une_liste.php [new file with mode: 0644]
www/plugins/abomailmans/formulaires/editer_abomailman.html [new file with mode: 0644]
www/plugins/abomailmans/formulaires/editer_abomailman.php [new file with mode: 0644]
www/plugins/abomailmans/formulaires/inc-previsu_mail.html [new file with mode: 0644]
www/plugins/abomailmans/genie/abomailmans_envois.php [new file with mode: 0755]
www/plugins/abomailmans/inc/abomailmans.php [new file with mode: 0755]
www/plugins/abomailmans/lang/abomailmans.xml [new file with mode: 0644]
www/plugins/abomailmans/lang/abomailmans_de.php [new file with mode: 0644]
www/plugins/abomailmans/lang/abomailmans_en.php [new file with mode: 0755]
www/plugins/abomailmans/lang/abomailmans_es.php [new file with mode: 0644]
www/plugins/abomailmans/lang/abomailmans_fr.php [new file with mode: 0755]
www/plugins/abomailmans/lang/abomailmans_sk.php [new file with mode: 0644]
www/plugins/abomailmans/lang/paquet-abomailmans.xml [new file with mode: 0644]
www/plugins/abomailmans/lang/paquet-abomailmans_de.php [new file with mode: 0644]
www/plugins/abomailmans/lang/paquet-abomailmans_en.php [new file with mode: 0644]
www/plugins/abomailmans/lang/paquet-abomailmans_es.php [new file with mode: 0644]
www/plugins/abomailmans/lang/paquet-abomailmans_fr.php [new file with mode: 0644]
www/plugins/abomailmans/lang/paquet-abomailmans_sk.php [new file with mode: 0644]
www/plugins/abomailmans/paquet.xml [new file with mode: 0644]
www/plugins/abomailmans/prive/listes/abomailman_mots.html [new file with mode: 0644]
www/plugins/abomailmans/prive/listes/abomailman_rubriques.html [new file with mode: 0644]
www/plugins/abomailmans/prive/listes/abomailman_templates.html [new file with mode: 0755]
www/plugins/abomailmans/prive/listes/listes_des_listes.html [new file with mode: 0644]
www/plugins/abomailmans/prive/objets/contenu/abomailman.html [new file with mode: 0644]
www/plugins/abomailmans/prive/objets/infos/abomailman.html [new file with mode: 0644]
www/plugins/abomailmans/prive/squelettes/contenu/abomailman.html [new file with mode: 0644]
www/plugins/abomailmans/prive/squelettes/contenu/abomailman_edit.html [new file with mode: 0644]
www/plugins/abomailmans/prive/squelettes/contenu/abomailman_envoyer.html [new file with mode: 0644]
www/plugins/abomailmans/prive/squelettes/contenu/abomailmans.html [new file with mode: 0644]
www/plugins/abomailmans/prive/squelettes/navigation/abomailman.html [new file with mode: 0644]
www/plugins/abomailmans/prive/squelettes/navigation/abomailmans.html [new file with mode: 0644]
www/plugins/abomailmans/prive/style_prive_plugin_abomailmans.html [new file with mode: 0644]
www/plugins/abomailmans/prive/themes/spip/images/abomailmans-16.png [new file with mode: 0755]
www/plugins/abomailmans/prive/themes/spip/images/abomailmans-24.png [new file with mode: 0644]
www/plugins/abomailmans/prive/themes/spip/images/abomailmans-32.png [new file with mode: 0644]
www/plugins/abomailmans/prive/themes/spip/images/abomailmans-envoyer-24.png [new file with mode: 0644]
www/plugins/abomailmans/prive/themes/spip/images/abomailmans-new-16.png [new file with mode: 0644]
www/plugins/abomailmans/svn.revision [new file with mode: 0644]
www/plugins/abomailmans/templates/nouveautes.html [new file with mode: 0755]
www/plugins/abomailmans/templates/nouveautes.txt.html [new file with mode: 0644]
www/plugins/abomailmans/templates/nouveautes_fr_en.html [new file with mode: 0644]
www/plugins/abomailmans/templates/nouveautes_fr_en.txt.html [new file with mode: 0644]
www/plugins/compositions_v3/composition-vide.html [new file with mode: 0644]
www/plugins/compositions_v3/compositions_administrations.php [new file with mode: 0644]
www/plugins/compositions_v3/compositions_fonctions.php [new file with mode: 0644]
www/plugins/compositions_v3/compositions_ieconfig.php [new file with mode: 0644]
www/plugins/compositions_v3/compositions_pipeline.php [new file with mode: 0644]
www/plugins/compositions_v3/formulaires/configurer_compositions.html [new file with mode: 0644]
www/plugins/compositions_v3/formulaires/configurer_compositions_fonctions.php [new file with mode: 0644]
www/plugins/compositions_v3/formulaires/editer_composition_objet.html [new file with mode: 0644]
www/plugins/compositions_v3/formulaires/editer_composition_objet.php [new file with mode: 0644]
www/plugins/compositions_v3/formulaires/inc-informeur_composition.html [new file with mode: 0644]
www/plugins/compositions_v3/formulaires/inc-selecteur_composition.html [new file with mode: 0644]
www/plugins/compositions_v3/images/composition-cours.png [new file with mode: 0644]
www/plugins/compositions_v3/images/composition-tableau.png [new file with mode: 0755]
www/plugins/compositions_v3/images/composition-test.png [new file with mode: 0644]
www/plugins/compositions_v3/images/objet-liste-contenus-dates.png [new file with mode: 0644]
www/plugins/compositions_v3/images/objet-liste-contenus.png [new file with mode: 0644]
www/plugins/compositions_v3/images/objet-simple.png [new file with mode: 0644]
www/plugins/compositions_v3/inc/compositions.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/compositions.xml [new file with mode: 0644]
www/plugins/compositions_v3/lang/compositions_en.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/compositions_es.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/compositions_fr.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/compositions_ru.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/compositions_sk.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/paquet-compositions.xml [new file with mode: 0644]
www/plugins/compositions_v3/lang/paquet-compositions_en.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/paquet-compositions_es.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/paquet-compositions_fr.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/paquet-compositions_ru.php [new file with mode: 0644]
www/plugins/compositions_v3/lang/paquet-compositions_sk.php [new file with mode: 0644]
www/plugins/compositions_v3/paquet.xml [new file with mode: 0644]
www/plugins/compositions_v3/prive/editer/compositions.html [new file with mode: 0644]
www/plugins/compositions_v3/prive/squelettes/contenu/compositions.html [new file with mode: 0644]
www/plugins/compositions_v3/prive/squelettes/contenu/configurer_compositions.html [new file with mode: 0644]
www/plugins/compositions_v3/prive/style_prive_plugin_compositions.html [new file with mode: 0644]
www/plugins/compositions_v3/prive/themes/spip/images/composition-16.png [new file with mode: 0644]
www/plugins/compositions_v3/prive/themes/spip/images/composition-24.png [new file with mode: 0644]
www/plugins/compositions_v3/prive/themes/spip/images/composition-32.png [new file with mode: 0644]
www/plugins/compositions_v3/prive/themes/spip2/images/composition-16.png [new file with mode: 0644]
www/plugins/compositions_v3/prive/themes/spip2/images/composition-24.png [new file with mode: 0644]
www/plugins/compositions_v3/prive/themes/spip2/images/composition-32.png [new file with mode: 0644]
www/plugins/compositions_v3/saisies/composition.html [new file with mode: 0644]
www/plugins/compositions_v3/saisies/composition_fonctions.php [new file with mode: 0644]
www/plugins/compositions_v3/svn.revision [new file with mode: 0644]
www/plugins/crayons/action/crayons.php [new file with mode: 0644]
www/plugins/crayons/action/crayons_html.php [new file with mode: 0644]
www/plugins/crayons/action/crayons_store.php [new file with mode: 0644]
www/plugins/crayons/action/crayons_upload.php [new file with mode: 0644]
www/plugins/crayons/controleurs/article_intro.html [new file with mode: 0644]
www/plugins/crayons/controleurs/article_intro2.html [new file with mode: 0644]
www/plugins/crayons/controleurs/article_intro3.php [new file with mode: 0644]
www/plugins/crayons/controleurs/article_introduction.html [new file with mode: 0644]
www/plugins/crayons/controleurs/article_introduction.php [new file with mode: 0644]
www/plugins/crayons/controleurs/article_texte.html [new file with mode: 0644]
www/plugins/crayons/controleurs/auteur_email.html [new file with mode: 0644]
www/plugins/crayons/controleurs/auteur_nom.html [new file with mode: 0644]
www/plugins/crayons/controleurs/auteur_qui.html [new file with mode: 0644]
www/plugins/crayons/controleurs/breve_hyperlien.html [new file with mode: 0644]
www/plugins/crayons/controleurs/document_fichier.html [new file with mode: 0644]
www/plugins/crayons/controleurs/extra.html [new file with mode: 0644]
www/plugins/crayons/controleurs/extra_fonctions.php [new file with mode: 0644]
www/plugins/crayons/controleurs/forum_email.html [new file with mode: 0644]
www/plugins/crayons/controleurs/forum_id_article.html [new file with mode: 0644]
www/plugins/crayons/controleurs/forum_nom.html [new file with mode: 0644]
www/plugins/crayons/controleurs/forum_qui.html [new file with mode: 0644]
www/plugins/crayons/controleurs/hyperlien.html [new file with mode: 0644]
www/plugins/crayons/controleurs/id_parent.html [new file with mode: 0644]
www/plugins/crayons/controleurs/logo.html [new file with mode: 0644]
www/plugins/crayons/controleurs/mots_article_brut.html [new file with mode: 0644]
www/plugins/crayons/controleurs/portfolio.php [new file with mode: 0644]
www/plugins/crayons/controleurs/signature_email.html [new file with mode: 0644]
www/plugins/crayons/controleurs/signature_nom.html [new file with mode: 0644]
www/plugins/crayons/controleurs/signature_qui.html [new file with mode: 0644]
www/plugins/crayons/controleurs/statut.html [new file with mode: 0644]
www/plugins/crayons/controleurs/syndic_article_hyperlien.html [new file with mode: 0644]
www/plugins/crayons/controleurs/vignette.html [new file with mode: 0644]
www/plugins/crayons/crayons.css [new file with mode: 0644]
www/plugins/crayons/crayons.js.html [new file with mode: 0644]
www/plugins/crayons/crayons.js_fonctions.php [new file with mode: 0644]
www/plugins/crayons/crayons_fonctions.php [new file with mode: 0644]
www/plugins/crayons/fonds/cfg_crayons.html [new file with mode: 0644]
www/plugins/crayons/formulaires/configurer_crayons.html [new file with mode: 0644]
www/plugins/crayons/images/annuler-16.png [new file with mode: 0644]
www/plugins/crayons/images/changed.png [new file with mode: 0644]
www/plugins/crayons/images/crayon-128.png [new file with mode: 0644]
www/plugins/crayons/images/crayon-24.png [new file with mode: 0644]
www/plugins/crayons/images/crayon-32.png [new file with mode: 0644]
www/plugins/crayons/images/crayon.png [new file with mode: 0644]
www/plugins/crayons/images/crayon20.png [new file with mode: 0644]
www/plugins/crayons/images/edit.png [new file with mode: 0644]
www/plugins/crayons/images/ok-16.png [new file with mode: 0755]
www/plugins/crayons/images/pencil.png [new file with mode: 0644]
www/plugins/crayons/images/resizer.png [new file with mode: 0644]
www/plugins/crayons/images/searching.gif [new file with mode: 0644]
www/plugins/crayons/inc/compat_crayons.php [new file with mode: 0644]
www/plugins/crayons/inc/crayons-json.php [new file with mode: 0644]
www/plugins/crayons/inc/crayons.php [new file with mode: 0644]
www/plugins/crayons/js/crayons-fade.js [new file with mode: 0644]
www/plugins/crayons/js/crayons.js [new file with mode: 0644]
www/plugins/crayons/js/jquery.form.js [new file with mode: 0644]
www/plugins/crayons/js/jquery.html5uploader.min.js [new file with mode: 0644]
www/plugins/crayons/js/jquery.js [new file with mode: 0644]
www/plugins/crayons/js/jquery.px.js [new file with mode: 0644]
www/plugins/crayons/js/resizehandle.js [new file with mode: 0644]
www/plugins/crayons/js/uploader.js.html [new file with mode: 0644]
www/plugins/crayons/lang/crayons.xml [new file with mode: 0644]
www/plugins/crayons/lang/crayons_ar.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_ast.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_br.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_ca.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_de.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_en.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_eo.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_es.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_eu.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_fa.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_fr.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_fr_tu.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_gl.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_it.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_it_fem.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_km.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_lb.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_nl.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_oc_lnc.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_pt_br.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_ro.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_ru.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_sk.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_sv.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_tr.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_tw.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_zh.php [new file with mode: 0644]
www/plugins/crayons/lang/crayons_zh_tw.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons.xml [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_ar.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_de.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_en.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_es.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_fr.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_it.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_nl.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_ru.php [new file with mode: 0644]
www/plugins/crayons/lang/paquet-crayons_sk.php [new file with mode: 0644]
www/plugins/crayons/lib/JavaScriptPacker/class.JavaScriptPacker.php [new file with mode: 0644]
www/plugins/crayons/modeles/uploader_item.html [new file with mode: 0644]
www/plugins/crayons/modeles/uploader_liste.html [new file with mode: 0644]
www/plugins/crayons/paquet.xml [new file with mode: 0644]
www/plugins/crayons/plugin.xml [new file with mode: 0644]
www/plugins/crayons/prive/squelettes/contenu/configurer_crayons.html [new file with mode: 0644]
www/plugins/crayons/svn.revision [new file with mode: 0644]
www/plugins/crayons/tetecrayons.php [new file with mode: 0644]
www/plugins/crayons/vues/article_intro.html [new file with mode: 0644]
www/plugins/crayons/vues/article_intro2.html [new file with mode: 0644]
www/plugins/crayons/vues/article_intro3.html [new file with mode: 0644]
www/plugins/crayons/vues/article_introduction.html [new file with mode: 0644]
www/plugins/crayons/vues/article_texte.html [new file with mode: 0644]
www/plugins/crayons/vues/document_fichier.html [new file with mode: 0644]
www/plugins/crayons/vues/extra.html [new file with mode: 0644]
www/plugins/crayons/vues/extra_fonctions.php [new file with mode: 0644]
www/plugins/crayons/vues/hyperlien.html [new file with mode: 0644]
www/plugins/crayons/vues/id_parent.html [new file with mode: 0644]
www/plugins/crayons/vues/logo.html [new file with mode: 0644]
www/plugins/crayons/vues/mots_article_brut.html [new file with mode: 0644]
www/plugins/crayons/vues/qui.html [new file with mode: 0644]
www/plugins/crayons/vues/rubrique_id_parent.html [new file with mode: 0644]
www/plugins/crayons/vues/vignette.html [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/css/enluminurestypo.css [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/css/enluminurestypo_prive.css [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/inserer_colonne.gif [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/inserer_ligne.gif [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/supprimer_ligne.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/table.css [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/table.js [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/table_rtl.css [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/table_rtl.js [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/editeur/tableau_edit.html [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/enluminures_typo_pipelines.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/exec/tableau_edit.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/fonds/cfg_bte.html [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/formulaires/configurer_typoenluminee.html [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/avances.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/barre-tableau.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/barre-wiki.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/cadretexte.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/center.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/eacute-maj.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/exposant.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/indice.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/intertitre2.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/intertitre3.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/left.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/listenum.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/listepuces.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence2.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/oelig-maj.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/oelig.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code_red.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/petitescapitales.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/poesie.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/right.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/tag.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/icones_barre/text_strikethrough.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/img_pack/e.gif [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/img_pack/moinecopiste.gif [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/lang/enlumtypo_ar.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/lang/enlumtypo_en.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/lang/enlumtypo_es.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/lang/enlumtypo_fr.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/lang/enlumtypo_it.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/lang/paquet-typoenluminee_fr.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/paquet.xml [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/plugin.xml [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/prive/squelettes/contenu/configurer_typoenluminee.html [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-16.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-32.png [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/svn.revision [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/typoenluminee.php [new file with mode: 0644]
www/plugins/enluminures_typographiques_v3/typoenluminee_pipelines.php [new file with mode: 0644]
www/plugins/facteur/classes/facteur.php [new file with mode: 0755]
www/plugins/facteur/emails/css.html [new file with mode: 0755]
www/plugins/facteur/emails/inc-bas.html [new file with mode: 0755]
www/plugins/facteur/emails/inc-button.html [new file with mode: 0644]
www/plugins/facteur/emails/inc-haut.html [new file with mode: 0755]
www/plugins/facteur/emails/test_email_html.html [new file with mode: 0755]
www/plugins/facteur/emails/test_email_texte.html [new file with mode: 0755]
www/plugins/facteur/emails/texte.html [new file with mode: 0644]
www/plugins/facteur/erreurs et exceptions.txt [new file with mode: 0644]
www/plugins/facteur/facteur_administrations.php [new file with mode: 0755]
www/plugins/facteur/facteur_fonctions.php [new file with mode: 0755]
www/plugins/facteur/facteur_ieconfig_metas.php [new file with mode: 0644]
www/plugins/facteur/formulaires/configurer_facteur.html [new file with mode: 0644]
www/plugins/facteur/formulaires/configurer_facteur.php [new file with mode: 0644]
www/plugins/facteur/inc/envoyer_mail.php [new file with mode: 0644]
www/plugins/facteur/inc/facteur_classes.php [new file with mode: 0644]
www/plugins/facteur/lang/facteur.xml [new file with mode: 0644]
www/plugins/facteur/lang/facteur_de.php [new file with mode: 0644]
www/plugins/facteur/lang/facteur_en.php [new file with mode: 0755]
www/plugins/facteur/lang/facteur_es.php [new file with mode: 0644]
www/plugins/facteur/lang/facteur_fr.php [new file with mode: 0755]
www/plugins/facteur/lang/facteur_sk.php [new file with mode: 0644]
www/plugins/facteur/lang/paquet-facteur.xml [new file with mode: 0644]
www/plugins/facteur/lang/paquet-facteur_en.php [new file with mode: 0644]
www/plugins/facteur/lang/paquet-facteur_es.php [new file with mode: 0644]
www/plugins/facteur/lang/paquet-facteur_fr.php [new file with mode: 0644]
www/plugins/facteur/lang/paquet-facteur_sk.php [new file with mode: 0644]
www/plugins/facteur/paquet.xml [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/LICENSE [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/README [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/class.phpmailer.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/class.pop3.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/class.smtp.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ar.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-br.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ca.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ch.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-cz.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-de.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-dk.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-en.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-es.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-et.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fi.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fo.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fr.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-hu.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-it.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ja.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-nl.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-no.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-pl.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ro.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ru.php [new file with mode: 0644]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-se.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-tr.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-zh.php [new file with mode: 0755]
www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-zh_cn.php [new file with mode: 0755]
www/plugins/facteur/prive/squelettes/contenu/configurer_facteur.html [new file with mode: 0644]
www/plugins/facteur/prive/themes/spip/images/facteur-16.png [new file with mode: 0644]
www/plugins/facteur/prive/themes/spip/images/facteur-24.png [new file with mode: 0644]
www/plugins/facteur/prive/themes/spip/images/facteur-32.png [new file with mode: 0644]
www/plugins/facteur/svn.revision [new file with mode: 0644]
www/plugins/formidable_1_0/action/dupliquer_formulaire.php [new file with mode: 0644]
www/plugins/formidable_1_0/action/editer_formulaire.php [new file with mode: 0644]
www/plugins/formidable_1_0/action/exporter_analyse_reponses.php [new file with mode: 0755]
www/plugins/formidable_1_0/action/exporter_formulaire.php [new file with mode: 0644]
www/plugins/formidable_1_0/action/exporter_formulaires_reponses.php [new file with mode: 0644]
www/plugins/formidable_1_0/action/instituer_formulaires_reponse.php [new file with mode: 0644]
www/plugins/formidable_1_0/action/supprimer_formulaire.php [new file with mode: 0644]
www/plugins/formidable_1_0/action/supprimer_formulaires_reponse.php [new file with mode: 0644]
www/plugins/formidable_1_0/base/formidable_tables.php [new file with mode: 0644]
www/plugins/formidable_1_0/css/formidable_analyse.css.html [new file with mode: 0644]
www/plugins/formidable_1_0/echanger/formulaire/forms.php [new file with mode: 0644]
www/plugins/formidable_1_0/echanger/formulaire/wcs.php [new file with mode: 0644]
www/plugins/formidable_1_0/echanger/formulaire/yaml.php [new file with mode: 0644]
www/plugins/formidable_1_0/exec/puce_statut_formulaires.php [new file with mode: 0644]
www/plugins/formidable_1_0/formidable_administrations.php [new file with mode: 0644]
www/plugins/formidable_1_0/formidable_autorisations.php [new file with mode: 0644]
www/plugins/formidable_1_0/formidable_fonctions.php [new file with mode: 0644]
www/plugins/formidable_1_0/formidable_options.php [new file with mode: 0644]
www/plugins/formidable_1_0/formidable_pipelines.php [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/configurer_formidable_analyse.html [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/editer_formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/editer_formulaire.php [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/editer_formulaire_champs.html [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/editer_formulaire_champs.php [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/editer_formulaire_traitements.html [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/editer_formulaire_traitements.php [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/formidable.html [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/formidable.php [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/importer_formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/formulaires/importer_formulaire.php [new file with mode: 0644]
www/plugins/formidable_1_0/icones_barre/formulaire.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formidable-128.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formidable-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formidable-64.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formidable.svg [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-action-ajouter.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-analyse-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-config-auteurs-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-config-champs-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-config-traitements-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-dupliquer-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-editer-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-exporter-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-nouveau-48.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-reponse-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-reponse-supprimer-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-reponses-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-reponses-exporter-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/images/formulaire-supprimer-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/inc/formidable.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formidable.xml [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formidable_de.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formidable_en.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formidable_es.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formidable_fr.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formidable_it.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formidable_sk.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formulaire_fr.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/formulaires_reponse_fr.php [new file with mode: 0644]
www/plugins/formidable_1_0/lang/paquet-formidable_fr.php [new file with mode: 0644]
www/plugins/formidable_1_0/modeles/formulaire_aide_memoire.html [new file with mode: 0644]
www/plugins/formidable_1_0/modeles/formulaire_analyse.html [new file with mode: 0644]
www/plugins/formidable_1_0/modeles/formulaire_formidable.yaml [new file with mode: 0644]
www/plugins/formidable_1_0/modeles/formulaires_reponse.html [new file with mode: 0644]
www/plugins/formidable_1_0/noisettes/formulaire_formidable.html [new file with mode: 0644]
www/plugins/formidable_1_0/noisettes/formulaire_formidable.yaml [new file with mode: 0644]
www/plugins/formidable_1_0/notifications/formulaire_accuse.html [new file with mode: 0644]
www/plugins/formidable_1_0/notifications/formulaire_email.html [new file with mode: 0644]
www/plugins/formidable_1_0/paquet.xml [new file with mode: 0644]
www/plugins/formidable_1_0/prive/objets/contenu/formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/objets/contenu/formulaires_reponse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/objets/infos/formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/objets/infos/formulaires_reponse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/objets/liste/formulaires.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/objets/liste/formulaires_reponses.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/contenu/configurer_formidable.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/contenu/formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/contenu/formulaire_edit.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_analyse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_reponse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_reponses.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/extra/formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/extra/formulaire_edit.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/extra/formulaires_analyse.html [new file with mode: 0755]
www/plugins/formidable_1_0/prive/squelettes/extra/formulaires_reponses.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaire_edit.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_analyse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_reponse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_reponses.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/navigation/formulaire.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/navigation/formulaire_edit.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_analyse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_reponse.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_reponses.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/style_prive_plugin_formidable.html [new file with mode: 0644]
www/plugins/formidable_1_0/prive/themes/basic/images/formulaire-16.png [new file with mode: 0644]
www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-16.png [new file with mode: 0644]
www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/prive/themes/spip/images/formulaires_reponse-24.png [new file with mode: 0644]
www/plugins/formidable_1_0/public/formidable_criteres.php [new file with mode: 0644]
www/plugins/formidable_1_0/puce_statut/formulaires_reponse.php [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/_base.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/case.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/checkbox.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/destinataires.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/explication.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/oui_non.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/radio.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/selecteur_article.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/selecteur_rubrique.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/selecteur_rubrique_article.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/selection.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-analyses/selection_multiple.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-vues/formulaire_formidable.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies-vues/formulaire_formidable_multiple.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies/champ.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies/formulaire_formidable.html [new file with mode: 0644]
www/plugins/formidable_1_0/saisies/formulaire_formidable_multiple.html [new file with mode: 0644]
www/plugins/formidable_1_0/svn.revision [new file with mode: 0644]
www/plugins/formidable_1_0/todo.txt [new file with mode: 0644]
www/plugins/formidable_1_0/traiter/email.php [new file with mode: 0644]
www/plugins/formidable_1_0/traiter/email.yaml [new file with mode: 0644]
www/plugins/formidable_1_0/traiter/enregistrement.php [new file with mode: 0644]
www/plugins/formidable_1_0/traiter/enregistrement.yaml [new file with mode: 0644]
www/plugins/gis/TODO.txt [new file with mode: 0644]
www/plugins/gis/action/editer_gis.php [new file with mode: 0644]
www/plugins/gis/action/editer_lien_gis.php [new file with mode: 0644]
www/plugins/gis/action/kml_infos.php [new file with mode: 0644]
www/plugins/gis/action/supprimer_gis.php [new file with mode: 0644]
www/plugins/gis/base/gis.php [new file with mode: 0644]
www/plugins/gis/crud/gis.php [new file with mode: 0644]
www/plugins/gis/embed/kml.html [new file with mode: 0644]
www/plugins/gis/embed/kml_fonctions.php [new file with mode: 0644]
www/plugins/gis/formulaires/configurer_gis.html [new file with mode: 0755]
www/plugins/gis/formulaires/configurer_gis.php [new file with mode: 0644]
www/plugins/gis/formulaires/editer_gis.html [new file with mode: 0755]
www/plugins/gis/formulaires/editer_gis.php [new file with mode: 0644]
www/plugins/gis/formulaires/gis_inserer_modeles_traiter.php [new file with mode: 0644]
www/plugins/gis/formulaires/rechercher_gis.html [new file with mode: 0755]
www/plugins/gis/formulaires/rechercher_gis.php [new file with mode: 0755]
www/plugins/gis/genie/gis_nettoyer_base.php [new file with mode: 0644]
www/plugins/gis/gis_administrations.php [new file with mode: 0644]
www/plugins/gis/gis_autoriser.php [new file with mode: 0644]
www/plugins/gis/gis_download.html [new file with mode: 0644]
www/plugins/gis/gis_fonctions.php [new file with mode: 0755]
www/plugins/gis/gis_json.html [new file with mode: 0644]
www/plugins/gis/gis_kml.html [new file with mode: 0755]
www/plugins/gis/gis_options.php [new file with mode: 0755]
www/plugins/gis/gis_pipelines.php [new file with mode: 0755]
www/plugins/gis/icones_barre/gis.png [new file with mode: 0644]
www/plugins/gis/images/gis-16.png [new file with mode: 0644]
www/plugins/gis/images/gis-24.png [new file with mode: 0755]
www/plugins/gis/images/gis.png [new file with mode: 0755]
www/plugins/gis/images/marker.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/blank.gif [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/cloud-popup-relative.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/east-mini.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/layer-switcher-maximize.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/layer-switcher-minimize.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/north-mini.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/slider.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/south-mini.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/west-mini.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/zoom-minus-mini.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/zoom-panel.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/zoom-plus-mini.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/zoom-world-mini.png [new file with mode: 0644]
www/plugins/gis/images/openlayers/dark/zoombar.png [new file with mode: 0644]
www/plugins/gis/inc/gis_xmlrpc.php [new file with mode: 0644]
www/plugins/gis/inc/iptc.php [new file with mode: 0644]
www/plugins/gis/inc/kml_infos.php [new file with mode: 0644]
www/plugins/gis/inclure/download_gpx.html [new file with mode: 0644]
www/plugins/gis/inclure/download_kml.html [new file with mode: 0644]
www/plugins/gis/inclure/gpx-item.html [new file with mode: 0755]
www/plugins/gis/inclure/kml-item.html [new file with mode: 0755]
www/plugins/gis/javascript/gis.js.html [new file with mode: 0644]
www/plugins/gis/javascript/gis_geocoder.js [new file with mode: 0644]
www/plugins/gis/javascript/gis_init_map.js [new file with mode: 0644]
www/plugins/gis/javascript/gis_utils.js [new file with mode: 0644]
www/plugins/gis/json/gis.html [new file with mode: 0644]
www/plugins/gis/json/gis_articles.html [new file with mode: 0644]
www/plugins/gis/json/gis_articles_branche.html [new file with mode: 0644]
www/plugins/gis/json/gis_articles_plus_sites.html [new file with mode: 0644]
www/plugins/gis/json/gis_auteurs.html [new file with mode: 0644]
www/plugins/gis/json/gis_documents.html [new file with mode: 0644]
www/plugins/gis/json/gis_evenements.html [new file with mode: 0644]
www/plugins/gis/json/gis_mots.html [new file with mode: 0644]
www/plugins/gis/json/gis_point_libre.html [new file with mode: 0644]
www/plugins/gis/json/gis_rubriques.html [new file with mode: 0644]
www/plugins/gis/json/gis_sites.html [new file with mode: 0644]
www/plugins/gis/json/gis_tous_avec_liens_espace_prive.html [new file with mode: 0644]
www/plugins/gis/lang/gis.xml [new file with mode: 0644]
www/plugins/gis/lang/gis_en.php [new file with mode: 0644]
www/plugins/gis/lang/gis_es.php [new file with mode: 0644]
www/plugins/gis/lang/gis_fr.php [new file with mode: 0644]
www/plugins/gis/lang/gis_ru.php [new file with mode: 0644]
www/plugins/gis/lang/gis_sk.php [new file with mode: 0644]
www/plugins/gis/lang/paquet-gis.xml [new file with mode: 0644]
www/plugins/gis/lang/paquet-gis_en.php [new file with mode: 0644]
www/plugins/gis/lang/paquet-gis_es.php [new file with mode: 0644]
www/plugins/gis/lang/paquet-gis_fr.php [new file with mode: 0644]
www/plugins/gis/lang/paquet-gis_ru.php [new file with mode: 0644]
www/plugins/gis/lang/paquet-gis_sk.php [new file with mode: 0644]
www/plugins/gis/modeles/carte_gis.html [new file with mode: 0644]
www/plugins/gis/modeles/carte_gis.yaml [new file with mode: 0644]
www/plugins/gis/modeles/carte_gis_preview.html [new file with mode: 0755]
www/plugins/gis/paquet.xml [new file with mode: 0644]
www/plugins/gis/prive/contenu/gis_objet.html [new file with mode: 0644]
www/plugins/gis/prive/inclure/gis_objet_formulaires.html [new file with mode: 0644]
www/plugins/gis/prive/objets/contenu/gis.html [new file with mode: 0644]
www/plugins/gis/prive/objets/infos/gis.html [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/gis.html [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/gis_associer.html [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/gis_associer_fonctions.php [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/gis_lies.html [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/gis_lies_fonctions.php [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/gis_tous.html [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/objets_gis.html [new file with mode: 0644]
www/plugins/gis/prive/objets/liste/objets_gis_simple.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/contenu/configurer_gis.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/contenu/gis.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/contenu/gis_edit.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/contenu/gis_tous.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/extra/gis.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/hierarchie/gis.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/hierarchie/gis_edit.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/navigation/gis_edit.html [new file with mode: 0644]
www/plugins/gis/prive/squelettes/navigation/gis_tous.html [new file with mode: 0644]
www/plugins/gis/prive/style_prive_plugin_gis.html [new file with mode: 0644]
www/plugins/gis/prive/themes/spip/images/gis-16.png [new file with mode: 0644]
www/plugins/gis/prive/themes/spip/images/gis-24.png [new file with mode: 0755]
www/plugins/gis/prive/themes/spip/images/gis-new-16.png [new file with mode: 0644]
www/plugins/gis/saisies/carte.html [new file with mode: 0644]
www/plugins/gis/svn.revision [new file with mode: 0644]
www/plugins/gis/tests/gis_connect_sql.php [new file with mode: 0644]
www/plugins/menus_1/action/editer_menu.php [new file with mode: 0644]
www/plugins/menus_1/action/editer_menus_entree.php [new file with mode: 0644]
www/plugins/menus_1/action/exporter_menu.php [new file with mode: 0644]
www/plugins/menus_1/action/supprimer_menu.php [new file with mode: 0644]
www/plugins/menus_1/balise/menus_afficher_entree.php [new file with mode: 0644]
www/plugins/menus_1/base/menus_tables.php [new file with mode: 0644]
www/plugins/menus_1/css/menuspip.css [new file with mode: 0644]
www/plugins/menus_1/formulaires/configurer_menus.html [new file with mode: 0644]
www/plugins/menus_1/formulaires/configurer_menus.php [new file with mode: 0644]
www/plugins/menus_1/formulaires/editer_menu.html [new file with mode: 0644]
www/plugins/menus_1/formulaires/editer_menu.php [new file with mode: 0644]
www/plugins/menus_1/formulaires/editer_menus_entree.html [new file with mode: 0644]
www/plugins/menus_1/formulaires/editer_menus_entree.php [new file with mode: 0644]
www/plugins/menus_1/formulaires/inc-menus_entrees.html [new file with mode: 0644]
www/plugins/menus_1/formulaires/inc-menus_entrees_inexistantes.html [new file with mode: 0644]
www/plugins/menus_1/formulaires/inc-nouvelle_entree-1.html [new file with mode: 0644]
www/plugins/menus_1/formulaires/inc-nouvelle_entree-2.html [new file with mode: 0644]
www/plugins/menus_1/images/export.png [new file with mode: 0644]
www/plugins/menus_1/images/menus-16.png [new file with mode: 0644]
www/plugins/menus_1/images/menus-24.png [new file with mode: 0644]
www/plugins/menus_1/images/menus-48.png [new file with mode: 0644]
www/plugins/menus_1/images/menus-nouveau-24.png [new file with mode: 0644]
www/plugins/menus_1/images/menus-nouveau-48.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_accueil.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_action_ajouter.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_action_bas.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_action_haut.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_action_modifier.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_action_supprimer.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_articles_rubrique.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_groupes_mots.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_lien.png [new file with mode: 0755]
www/plugins/menus_1/images/menus_logout.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_mapage.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_mots.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_objet.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_page_speciale.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_rubriques.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_secteurlangue.png [new file with mode: 0644]
www/plugins/menus_1/images/menus_texte_libre.png [new file with mode: 0644]
www/plugins/menus_1/inc/menus.php [new file with mode: 0644]
www/plugins/menus_1/inc/menus_autoriser.php [new file with mode: 0644]
www/plugins/menus_1/inclure/barre-nav.html [new file with mode: 0644]
www/plugins/menus_1/inclure/menu.html [new file with mode: 0644]
www/plugins/menus_1/inclure/nav.html [new file with mode: 0644]
www/plugins/menus_1/lang/menus.xml [new file with mode: 0644]
www/plugins/menus_1/lang/menus_ar.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_ca.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_de.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_en.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_es.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_fa.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_fr.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_it.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_ru.php [new file with mode: 0644]
www/plugins/menus_1/lang/menus_sk.php [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus.xml [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus_ar.php [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus_de.php [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus_en.php [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus_es.php [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus_fr.php [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus_it.php [new file with mode: 0644]
www/plugins/menus_1/lang/paquet-menus_sk.php [new file with mode: 0644]
www/plugins/menus_1/menu.html [new file with mode: 0644]
www/plugins/menus_1/menus/accueil.html [new file with mode: 0644]
www/plugins/menus_1/menus/accueil.xml [new file with mode: 0644]
www/plugins/menus_1/menus/articles_rubrique.html [new file with mode: 0644]
www/plugins/menus_1/menus/articles_rubrique.xml [new file with mode: 0644]
www/plugins/menus_1/menus/deconnecter.html [new file with mode: 0644]
www/plugins/menus_1/menus/deconnecter.xml [new file with mode: 0644]
www/plugins/menus_1/menus/espace_prive.html [new file with mode: 0644]
www/plugins/menus_1/menus/espace_prive.xml [new file with mode: 0644]
www/plugins/menus_1/menus/groupe_mots.html [new file with mode: 0644]
www/plugins/menus_1/menus/groupe_mots.xml [new file with mode: 0644]
www/plugins/menus_1/menus/lien.html [new file with mode: 0644]
www/plugins/menus_1/menus/lien.xml [new file with mode: 0644]
www/plugins/menus_1/menus/mapage.html [new file with mode: 0644]
www/plugins/menus_1/menus/mapage.xml [new file with mode: 0644]
www/plugins/menus_1/menus/mots.html [new file with mode: 0644]
www/plugins/menus_1/menus/mots.xml [new file with mode: 0644]
www/plugins/menus_1/menus/objet.html [new file with mode: 0644]
www/plugins/menus_1/menus/objet.xml [new file with mode: 0644]
www/plugins/menus_1/menus/page_speciale.html [new file with mode: 0644]
www/plugins/menus_1/menus/page_speciale.xml [new file with mode: 0644]
www/plugins/menus_1/menus/page_speciale_zajax.html [new file with mode: 0644]
www/plugins/menus_1/menus/page_speciale_zajax.xml [new file with mode: 0644]
www/plugins/menus_1/menus/rubriques_completes.html [new file with mode: 0644]
www/plugins/menus_1/menus/rubriques_completes.xml [new file with mode: 0644]
www/plugins/menus_1/menus/secteurlangue.html [new file with mode: 0644]
www/plugins/menus_1/menus/secteurlangue.xml [new file with mode: 0644]
www/plugins/menus_1/menus/texte_libre.html [new file with mode: 0644]
www/plugins/menus_1/menus/texte_libre.xml [new file with mode: 0644]
www/plugins/menus_1/menus_administrations.php [new file with mode: 0644]
www/plugins/menus_1/menus_fonctions.php [new file with mode: 0644]
www/plugins/menus_1/menus_ieconfig.php [new file with mode: 0644]
www/plugins/menus_1/menus_pipelines.php [new file with mode: 0644]
www/plugins/menus_1/noisettes/menu-preview.html [new file with mode: 0644]
www/plugins/menus_1/noisettes/menu.html [new file with mode: 0644]
www/plugins/menus_1/noisettes/menu.yaml [new file with mode: 0644]
www/plugins/menus_1/paquet.xml [new file with mode: 0644]
www/plugins/menus_1/prive/squelettes/contenu/configurer_menus.html [new file with mode: 0644]
www/plugins/menus_1/prive/squelettes/contenu/menus_editer.html [new file with mode: 0644]
www/plugins/menus_1/prive/squelettes/contenu/menus_tous.html [new file with mode: 0644]
www/plugins/menus_1/prive/squelettes/navigation/menus_editer.html [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-16.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-24.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-32.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-add-16.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-add-24.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-add-32.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-del-16.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-del-24.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-del-32.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-export-24.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menu-exporter-24.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menus-16.png [new file with mode: 0644]
www/plugins/menus_1/prive/themes/spip/images/menus-24.png [new file with mode: 0644]
www/plugins/menus_1/saisies-vues/menu.html [new file with mode: 0644]
www/plugins/menus_1/saisies-vues/menus_multiple.html [new file with mode: 0644]
www/plugins/menus_1/saisies/menu.html [new file with mode: 0644]
www/plugins/menus_1/saisies/menus_multiple.html [new file with mode: 0644]
www/plugins/menus_1/svn.revision [new file with mode: 0644]
www/plugins/multilang/alire.txt [new file with mode: 0644]
www/plugins/multilang/formulaires/configurer_multilang.html [new file with mode: 0644]
www/plugins/multilang/formulaires/configurer_multilang_fonctions.php [new file with mode: 0644]
www/plugins/multilang/images/background.png [new file with mode: 0644]
www/plugins/multilang/images/multi_forbidden.png [new file with mode: 0644]
www/plugins/multilang/images/multi_undefined.png [new file with mode: 0644]
www/plugins/multilang/images/multilang-16.png [new file with mode: 0644]
www/plugins/multilang/images/multilang-24.png [new file with mode: 0644]
www/plugins/multilang/images/multilang-32.png [new file with mode: 0644]
www/plugins/multilang/images/multilang-48.png [new file with mode: 0644]
www/plugins/multilang/javascript/multilang.js [new file with mode: 0644]
www/plugins/multilang/javascript/multilang_init.js.html [new file with mode: 0644]
www/plugins/multilang/javascript/multilang_init.js_fonctions.php [new file with mode: 0644]
www/plugins/multilang/javascript/multilang_lang.js.html [new file with mode: 0644]
www/plugins/multilang/lang/multilang.xml [new file with mode: 0644]
www/plugins/multilang/lang/multilang_en.php [new file with mode: 0644]
www/plugins/multilang/lang/multilang_es.php [new file with mode: 0644]
www/plugins/multilang/lang/multilang_fa.php [new file with mode: 0644]
www/plugins/multilang/lang/multilang_fr.php [new file with mode: 0644]
www/plugins/multilang/lang/multilang_sk.php [new file with mode: 0644]
www/plugins/multilang/lang/paquet-multilang.xml [new file with mode: 0644]
www/plugins/multilang/lang/paquet-multilang_en.php [new file with mode: 0644]
www/plugins/multilang/lang/paquet-multilang_es.php [new file with mode: 0644]
www/plugins/multilang/lang/paquet-multilang_fr.php [new file with mode: 0644]
www/plugins/multilang/lang/paquet-multilang_it.php [new file with mode: 0644]
www/plugins/multilang/lang/paquet-multilang_ru.php [new file with mode: 0644]
www/plugins/multilang/lang/paquet-multilang_sk.php [new file with mode: 0644]
www/plugins/multilang/multilang.css.html [new file with mode: 0644]
www/plugins/multilang/multilang.js.html [new file with mode: 0644]
www/plugins/multilang/multilang_administrations.php [new file with mode: 0644]
www/plugins/multilang/multilang_pipelines.php [new file with mode: 0644]
www/plugins/multilang/paquet.xml [new file with mode: 0644]
www/plugins/multilang/prive/squelettes/contenu/configurer_multilang.html [new file with mode: 0644]
www/plugins/multilang/prive/squelettes/contenu/configurer_multilangue.html [new file with mode: 0644]
www/plugins/multilang/prive/style_prive_plugin_multilang.html [new file with mode: 0644]
www/plugins/multilang/prive/themes/spip/images/multilang-16.png [new file with mode: 0644]
www/plugins/multilang/prive/themes/spip/images/multilang-24.png [new file with mode: 0644]
www/plugins/multilang/svn.revision [new file with mode: 0644]
www/plugins/nospam/images/nospam-32.png [new file with mode: 0644]
www/plugins/nospam/images/nospam.gif [new file with mode: 0644]
www/plugins/nospam/images/nospam.png [new file with mode: 0644]
www/plugins/nospam/inc/detecter_langue.php [new file with mode: 0644]
www/plugins/nospam/inc/nospam.php [new file with mode: 0644]
www/plugins/nospam/inclure/nobot.html [new file with mode: 0644]
www/plugins/nospam/lang/nospam.xml [new file with mode: 0644]
www/plugins/nospam/lang/nospam_ar.php [new file with mode: 0644]
www/plugins/nospam/lang/nospam_en.php [new file with mode: 0644]
www/plugins/nospam/lang/nospam_es.php [new file with mode: 0644]
www/plugins/nospam/lang/nospam_fa.php [new file with mode: 0644]
www/plugins/nospam/lang/nospam_fr.php [new file with mode: 0644]
www/plugins/nospam/lang/nospam_sk.php [new file with mode: 0644]
www/plugins/nospam/lang/paquet-nospam.xml [new file with mode: 0644]
www/plugins/nospam/lang/paquet-nospam_ar.php [new file with mode: 0644]
www/plugins/nospam/lang/paquet-nospam_de.php [new file with mode: 0644]
www/plugins/nospam/lang/paquet-nospam_en.php [new file with mode: 0644]
www/plugins/nospam/lang/paquet-nospam_es.php [new file with mode: 0644]
www/plugins/nospam/lang/paquet-nospam_fr.php [new file with mode: 0644]
www/plugins/nospam/nospam/verifier_formulaire_ecrire_auteur.php [new file with mode: 0644]
www/plugins/nospam/nospam/verifier_formulaire_forum.php [new file with mode: 0644]
www/plugins/nospam/nospam/verifier_formulaire_signature.php [new file with mode: 0644]
www/plugins/nospam/nospam_pipelines.php [new file with mode: 0644]
www/plugins/nospam/paquet.xml [new file with mode: 0644]
www/plugins/nospam/plugin.xml [new file with mode: 0644]
www/plugins/nospam/svn.revision [new file with mode: 0644]
www/plugins/notifications2/action/instituer_forum_paremail.php [new file with mode: 0644]
www/plugins/notifications2/content/inc-suivi_forums_date.html [new file with mode: 0644]
www/plugins/notifications2/content/notifications.html [new file with mode: 0644]
www/plugins/notifications2/formulaires/abonner_notifications.html [new file with mode: 0644]
www/plugins/notifications2/formulaires/abonner_notifications.php [new file with mode: 0644]
www/plugins/notifications2/formulaires/configurer_notifications.html [new file with mode: 0644]
www/plugins/notifications2/genie/notifications.php [new file with mode: 0644]
www/plugins/notifications2/lang/abonnernotifications_fr.php [new file with mode: 0644]
www/plugins/notifications2/lang/notifications.xml [new file with mode: 0644]
www/plugins/notifications2/lang/notifications_en.php [new file with mode: 0644]
www/plugins/notifications2/lang/notifications_es.php [new file with mode: 0644]
www/plugins/notifications2/lang/notifications_fa.php [new file with mode: 0644]
www/plugins/notifications2/lang/notifications_fr.php [new file with mode: 0644]
www/plugins/notifications2/lang/notifications_sk.php [new file with mode: 0644]
www/plugins/notifications2/lang/paquet-notifications.xml [new file with mode: 0644]
www/plugins/notifications2/lang/paquet-notifications_en.php [new file with mode: 0644]
www/plugins/notifications2/lang/paquet-notifications_es.php [new file with mode: 0644]
www/plugins/notifications2/lang/paquet-notifications_fa.php [new file with mode: 0644]
www/plugins/notifications2/lang/paquet-notifications_fr.php [new file with mode: 0644]
www/plugins/notifications2/lang/paquet-notifications_sk.php [new file with mode: 0644]
www/plugins/notifications2/modeles/mail_inscription.html [new file with mode: 0644]
www/plugins/notifications2/modeles/mail_oubli.html [new file with mode: 0644]
www/plugins/notifications2/notifications-24.png [new file with mode: 0644]
www/plugins/notifications2/notifications-32.png [new file with mode: 0644]
www/plugins/notifications2/notifications.png [new file with mode: 0644]
www/plugins/notifications2/notifications/article_propose.html [new file with mode: 0644]
www/plugins/notifications2/notifications/article_publie.html [new file with mode: 0644]
www/plugins/notifications2/notifications/article_valide.html [new file with mode: 0644]
www/plugins/notifications2/notifications/breve_propose.html [new file with mode: 0644]
www/plugins/notifications2/notifications/breve_publie.html [new file with mode: 0644]
www/plugins/notifications2/notifications/forum_poste.html [new file with mode: 0644]
www/plugins/notifications2/notifications/forumposte.php [new file with mode: 0644]
www/plugins/notifications2/notifications/forumprive.php [new file with mode: 0644]
www/plugins/notifications2/notifications/forumvalide.php [new file with mode: 0644]
www/plugins/notifications2/notifications/inc-article.html [new file with mode: 0644]
www/plugins/notifications2/notifications/inc-breve.html [new file with mode: 0644]
www/plugins/notifications2/notifications/inscription.html [new file with mode: 0644]
www/plugins/notifications2/notifications/inscription.php [new file with mode: 0644]
www/plugins/notifications2/notifications/instituerarticle.php [new file with mode: 0644]
www/plugins/notifications2/notifications/instituerbreve.php [new file with mode: 0644]
www/plugins/notifications2/notifications/petition_signee.html [new file with mode: 0644]
www/plugins/notifications2/notifications/petitionsignee.php [new file with mode: 0644]
www/plugins/notifications2/notifications_administrations.php [new file with mode: 0644]
www/plugins/notifications2/notifications_pipelines.php [new file with mode: 0644]
www/plugins/notifications2/nouveautes.html [new file with mode: 0644]
www/plugins/notifications2/paquet.xml [new file with mode: 0644]
www/plugins/notifications2/prive/squelettes/contenu/configurer_notifications.html [new file with mode: 0644]
www/plugins/notifications2/svn.revision [new file with mode: 0644]
www/plugins/odt2spip_30/action/odt2spip_importe.php [new file with mode: 0644]
www/plugins/odt2spip_30/formulaires/odt2spip.html [new file with mode: 0644]
www/plugins/odt2spip_30/inc/odt2spip.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/inc/odt2spip_generer_sortie.php [new file with mode: 0644]
www/plugins/odt2spip_30/inc/odt2spip_retailler_img.php [new file with mode: 0644]
www/plugins/odt2spip_30/inc/odt2spip_traiter_mathml.php [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/README [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/cmarkup.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/entities.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/glayout.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/mmltex.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/scripts.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/tables.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/inc/xsltml/tokens.xsl [new file with mode: 0644]
www/plugins/odt2spip_30/lang/odtspip_de.php [new file with mode: 0644]
www/plugins/odt2spip_30/lang/odtspip_en.php [new file with mode: 0644]
www/plugins/odt2spip_30/lang/odtspip_fr.php [new file with mode: 0644]
www/plugins/odt2spip_30/lang/odtspip_it.php [new file with mode: 0644]
www/plugins/odt2spip_30/lang/odtspip_ro.php [new file with mode: 0644]
www/plugins/odt2spip_30/lang/paquet-odt2spip_en.php [new file with mode: 0644]
www/plugins/odt2spip_30/lang/paquet-odt2spip_fr.php [new file with mode: 0644]
www/plugins/odt2spip_30/odt2spip-24.png [new file with mode: 0644]
www/plugins/odt2spip_30/odt2spip-64.png [new file with mode: 0644]
www/plugins/odt2spip_30/odt2spip_pipelines.php [new file with mode: 0644]
www/plugins/odt2spip_30/paquet.xml [new file with mode: 0644]
www/plugins/odt2spip_30/svn.revision [new file with mode: 0644]
www/plugins/odt2spip_30/tests/content_math_objet1.xml [new file with mode: 0644]
www/plugins/odt2spip_30/tests/content_math_objet2.xml [new file with mode: 0644]
www/plugins/odt2spip_30/tests/content_math_objet3.xml [new file with mode: 0644]
www/plugins/odt2spip_30/tests/content_test_complet.xml [new file with mode: 0644]
www/plugins/odt2spip_30/tests/content_test_complet_indente.xml [new file with mode: 0644]
www/plugins/odt2spip_30/tests/test_complet.odt [new file with mode: 0644]
www/plugins/rss_article_3_0/base/rssarticle.php [new file with mode: 0644]
www/plugins/rss_article_3_0/exec/rss_article.php [new file with mode: 0644]
www/plugins/rss_article_3_0/formulaires/configurer_rssarticle.html [new file with mode: 0644]
www/plugins/rss_article_3_0/formulaires/editer_rssarticle.html [new file with mode: 0644]
www/plugins/rss_article_3_0/formulaires/editer_rssarticle.php [new file with mode: 0644]
www/plugins/rss_article_3_0/genie/rssarticle_copie.php [new file with mode: 0644]
www/plugins/rss_article_3_0/lang/paquet-rssarticle_fr.php [new file with mode: 0644]
www/plugins/rss_article_3_0/lang/rssarticle_ar.php [new file with mode: 0644]
www/plugins/rss_article_3_0/lang/rssarticle_fr.php [new file with mode: 0644]
www/plugins/rss_article_3_0/paquet.xml [new file with mode: 0644]
www/plugins/rss_article_3_0/prive/contenu/rssarticle.html [new file with mode: 0644]
www/plugins/rss_article_3_0/prive/squelettes/contenu/configurer_rssarticle.html [new file with mode: 0644]
www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-128.png [new file with mode: 0644]
www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-16.png [new file with mode: 0644]
www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-32.png [new file with mode: 0644]
www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-64.png [new file with mode: 0644]
www/plugins/rss_article_3_0/rssarticle_administrations.php [new file with mode: 0644]
www/plugins/rss_article_3_0/rssarticle_pipelines.php [new file with mode: 0644]
www/plugins/rss_article_3_0/svn.revision [new file with mode: 0644]
www/plugins/saisies/action/deplacer_saisie.php [new file with mode: 0644]
www/plugins/saisies/aide/saisies.html [new file with mode: 0644]
www/plugins/saisies/balise/configurer_saisie.php [new file with mode: 0644]
www/plugins/saisies/balise/generer_saisies.php [new file with mode: 0644]
www/plugins/saisies/balise/saisie.php [new file with mode: 0644]
www/plugins/saisies/balise/voir_saisie.php [new file with mode: 0644]
www/plugins/saisies/balise/voir_saisies.php [new file with mode: 0644]
www/plugins/saisies/contenu/page-saisies_cvt.html [new file with mode: 0644]
www/plugins/saisies/css/formulaires_constructeur.css [new file with mode: 0644]
www/plugins/saisies/extra-vues/pays.html [new file with mode: 0644]
www/plugins/saisies/formulaires/construire_formulaire.html [new file with mode: 0644]
www/plugins/saisies/formulaires/construire_formulaire.php [new file with mode: 0644]
www/plugins/saisies/formulaires/inc-construire_formulaire-actions.html [new file with mode: 0644]
www/plugins/saisies/formulaires/inc-generer_saisies_configurables.html [new file with mode: 0644]
www/plugins/saisies/formulaires/inc-saisies-cvt.html [new file with mode: 0644]
www/plugins/saisies/formulaires/saisies_cvt.html [new file with mode: 0644]
www/plugins/saisies/formulaires/saisies_cvt.php [new file with mode: 0644]
www/plugins/saisies/images/formulaire-annuler-16.png [new file with mode: 0644]
www/plugins/saisies/images/formulaire-configurer-16.png [new file with mode: 0644]
www/plugins/saisies/images/formulaire-deplacer-16.png [new file with mode: 0644]
www/plugins/saisies/images/formulaire-dupliquer-16.png [new file with mode: 0644]
www/plugins/saisies/images/formulaire-enregistrer-16.png [new file with mode: 0644]
www/plugins/saisies/images/formulaire-reinitialiser-24.png [new file with mode: 0644]
www/plugins/saisies/images/formulaire-saisie-defaut.png [new file with mode: 0644]
www/plugins/saisies/images/formulaire-supprimer-16.png [new file with mode: 0644]
www/plugins/saisies/images/logo_saisie_48.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_auteurs.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_case.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_checkbox.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_date.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_explication.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_fieldset.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_hidden.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_input.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_oui_non.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_radio.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_selecteur_article.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_selecteur_rubrique.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_selecteur_rubrique_article.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_selection.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_selection_multiple.png [new file with mode: 0644]
www/plugins/saisies/images/saisies_textarea.png [new file with mode: 0644]
www/plugins/saisies/inc/saisies.php [new file with mode: 0644]
www/plugins/saisies/inc/saisies_afficher.php [new file with mode: 0644]
www/plugins/saisies/inc/saisies_lister.php [new file with mode: 0644]
www/plugins/saisies/inc/saisies_manipuler.php [new file with mode: 0644]
www/plugins/saisies/inclure/configurer_saisie.html [new file with mode: 0644]
www/plugins/saisies/inclure/configurer_saisie_fonctions.php [new file with mode: 0644]
www/plugins/saisies/inclure/generer_saisies.html [new file with mode: 0644]
www/plugins/saisies/inclure/js_afficher_si.html [new file with mode: 0644]
www/plugins/saisies/inclure/saisies_aide.html [new file with mode: 0644]
www/plugins/saisies/inclure/voir_saisies.html [new file with mode: 0644]
www/plugins/saisies/javascript/saisies.js [new file with mode: 0644]
www/plugins/saisies/lang/paquet-saisies.xml [new file with mode: 0644]
www/plugins/saisies/lang/paquet-saisies_de.php [new file with mode: 0644]
www/plugins/saisies/lang/paquet-saisies_en.php [new file with mode: 0644]
www/plugins/saisies/lang/paquet-saisies_es.php [new file with mode: 0644]
www/plugins/saisies/lang/paquet-saisies_fr.php [new file with mode: 0644]
www/plugins/saisies/lang/paquet-saisies_ru.php [new file with mode: 0644]
www/plugins/saisies/lang/paquet-saisies_sk.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies.xml [new file with mode: 0644]
www/plugins/saisies/lang/saisies_ca.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_de.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_en.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_es.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_fa.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_fr.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_fr_tu.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_it.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_ru.php [new file with mode: 0644]
www/plugins/saisies/lang/saisies_sk.php [new file with mode: 0644]
www/plugins/saisies/paquet.xml [new file with mode: 0644]
www/plugins/saisies/plugin.xml [new file with mode: 0644]
www/plugins/saisies/prive/exec/construire_formulaire.html [new file with mode: 0644]
www/plugins/saisies/prive/listes/articles_originaux_recursifs.html [new file with mode: 0644]
www/plugins/saisies/prive/listes/rubriques_recursives.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/_base.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/auteurs.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/case.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/checkbox.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/date.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/destinataires.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/explication.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/fieldset.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/groupe_mots.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/oui_non.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/radio.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/secteur.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selecteur.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selecteur_article.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selecteur_article_fonctions.php [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selecteur_document.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selecteur_rubrique.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selecteur_rubrique_article.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selecteur_site.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selection.html [new file with mode: 0644]
www/plugins/saisies/saisies-vues/selection_multiple.html [new file with mode: 0644]
www/plugins/saisies/saisies.css.html [new file with mode: 0644]
www/plugins/saisies/saisies/_base.html [new file with mode: 0644]
www/plugins/saisies/saisies/articles_originaux.html [new file with mode: 0644]
www/plugins/saisies/saisies/auteurs.html [new file with mode: 0644]
www/plugins/saisies/saisies/auteurs.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/case.html [new file with mode: 0644]
www/plugins/saisies/saisies/case.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/checkbox.html [new file with mode: 0644]
www/plugins/saisies/saisies/checkbox.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/choisir_objet.html [new file with mode: 0644]
www/plugins/saisies/saisies/choisir_objets.html [new file with mode: 0644]
www/plugins/saisies/saisies/couleur.html [new file with mode: 0644]
www/plugins/saisies/saisies/date.html [new file with mode: 0644]
www/plugins/saisies/saisies/date.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/date_jour_mois_annee.html [new file with mode: 0644]
www/plugins/saisies/saisies/destinataires.html [new file with mode: 0644]
www/plugins/saisies/saisies/destinataires.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/email.html [new file with mode: 0644]
www/plugins/saisies/saisies/explication.html [new file with mode: 0644]
www/plugins/saisies/saisies/explication.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/fieldset.html [new file with mode: 0644]
www/plugins/saisies/saisies/fieldset.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/groupe_mots.html [new file with mode: 0644]
www/plugins/saisies/saisies/hidden.html [new file with mode: 0644]
www/plugins/saisies/saisies/hidden.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/input.html [new file with mode: 0644]
www/plugins/saisies/saisies/input.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/mot.html [new file with mode: 0644]
www/plugins/saisies/saisies/oui_non.html [new file with mode: 0644]
www/plugins/saisies/saisies/oui_non.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/pays.html [new file with mode: 0644]
www/plugins/saisies/saisies/police.html [new file with mode: 0644]
www/plugins/saisies/saisies/position_construire_formulaire.html [new file with mode: 0644]
www/plugins/saisies/saisies/radio.html [new file with mode: 0644]
www/plugins/saisies/saisies/radio.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/recherche.html [new file with mode: 0644]
www/plugins/saisies/saisies/secteur.html [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur.html [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_article.html [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_article.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_document.html [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_langue.html [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_rubrique.html [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_rubrique.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_rubrique_article.html [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_rubrique_article.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/selecteur_site.html [new file with mode: 0644]
www/plugins/saisies/saisies/selection.html [new file with mode: 0644]
www/plugins/saisies/saisies/selection.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/selection_multiple.html [new file with mode: 0755]
www/plugins/saisies/saisies/selection_multiple.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/selection_par_groupe.html [new file with mode: 0644]
www/plugins/saisies/saisies/statuts_auteurs.html [new file with mode: 0644]
www/plugins/saisies/saisies/telephone.html [new file with mode: 0644]
www/plugins/saisies/saisies/textarea.html [new file with mode: 0644]
www/plugins/saisies/saisies/textarea.yaml [new file with mode: 0644]
www/plugins/saisies/saisies/true_false.html [new file with mode: 0644]
www/plugins/saisies/saisies/url.html [new file with mode: 0644]
www/plugins/saisies/saisies_fonctions.php [new file with mode: 0644]
www/plugins/saisies/saisies_options.php [new file with mode: 0644]
www/plugins/saisies/saisies_pipelines.php [new file with mode: 0644]
www/plugins/saisies/svn.revision [new file with mode: 0644]
www/plugins/saisies/test/configurer_saisie.html [new file with mode: 0644]
www/plugins/saisies/test/generer_saisies.html [new file with mode: 0644]
www/plugins/saisies/test/saisie.html [new file with mode: 0644]
www/plugins/saisies/test/voir_saisie.html [new file with mode: 0644]
www/plugins/saisies/test/voir_saisies.html [new file with mode: 0644]
www/plugins/seo-v1/action/editer_seo.php [new file with mode: 0644]
www/plugins/seo-v1/base/seo_tables.php [new file with mode: 0644]
www/plugins/seo-v1/exec/seo_config.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_alexa.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_alexa.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_bing.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_bing.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_ganalytics.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_ganalytics.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_insert_head.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_insert_head.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_metas.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_metas.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_urls_canoniques.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_urls_canoniques.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_webmaster_tools.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/configurer_seo_webmaster_tools.php [new file with mode: 0644]
www/plugins/seo-v1/formulaires/editer_seo.html [new file with mode: 0644]
www/plugins/seo-v1/formulaires/editer_seo.php [new file with mode: 0644]
www/plugins/seo-v1/img_pack/alexa-24.png [new file with mode: 0644]
www/plugins/seo-v1/img_pack/bing-24.png [new file with mode: 0644]
www/plugins/seo-v1/img_pack/canonical_url-24.png [new file with mode: 0644]
www/plugins/seo-v1/img_pack/google_analytics-24.png [new file with mode: 0644]
www/plugins/seo-v1/img_pack/google_webmaster-24.png [new file with mode: 0644]
www/plugins/seo-v1/img_pack/meta_tags-24.png [new file with mode: 0644]
www/plugins/seo-v1/img_pack/seo-24.png [new file with mode: 0644]
www/plugins/seo-v1/lang/paquet-seo.xml [new file with mode: 0644]
www/plugins/seo-v1/lang/paquet-seo_en.php [new file with mode: 0644]
www/plugins/seo-v1/lang/paquet-seo_fr.php [new file with mode: 0644]
www/plugins/seo-v1/lang/paquet-seo_ru.php [new file with mode: 0644]
www/plugins/seo-v1/lang/paquet-seo_sk.php [new file with mode: 0644]
www/plugins/seo-v1/lang/seo.xml [new file with mode: 0644]
www/plugins/seo-v1/lang/seo_en.php [new file with mode: 0644]
www/plugins/seo-v1/lang/seo_fr.php [new file with mode: 0644]
www/plugins/seo-v1/lang/seo_ru.php [new file with mode: 0644]
www/plugins/seo-v1/lang/seo_sk.php [new file with mode: 0644]
www/plugins/seo-v1/paquet.xml [new file with mode: 0644]
www/plugins/seo-v1/pipelines/seo_affichage_final.php [new file with mode: 0644]
www/plugins/seo-v1/pipelines/seo_affiche_milieu.php [new file with mode: 0644]
www/plugins/seo-v1/pipelines/seo_ajouter_onglets.php [new file with mode: 0644]
www/plugins/seo-v1/pipelines/seo_autoriser.php [new file with mode: 0644]
www/plugins/seo-v1/pipelines/seo_insert_head.php [new file with mode: 0644]
www/plugins/seo-v1/plugin.xml [new file with mode: 0644]
www/plugins/seo-v1/prive/configurer_seo.html [new file with mode: 0644]
www/plugins/seo-v1/prive/squelettes/contenu/configurer_seo.html [new file with mode: 0644]
www/plugins/seo-v1/prive/squelettes/inclure/seo_metas.html [new file with mode: 0644]
www/plugins/seo-v1/prive/style_prive_plugin_seo.html [new file with mode: 0644]
www/plugins/seo-v1/prive/themes/spip/images/seo-16.png [new file with mode: 0644]
www/plugins/seo-v1/prive/themes/spip/images/seo-24.png [new file with mode: 0644]
www/plugins/seo-v1/seo.png [new file with mode: 0644]
www/plugins/seo-v1/seo_administrations.php [new file with mode: 0644]
www/plugins/seo-v1/seo_fonctions.php [new file with mode: 0644]
www/plugins/seo-v1/svn.revision [new file with mode: 0644]
www/plugins/spip-bonux-3/demo/boucle_et_saut.html [new file with mode: 0644]
www/plugins/spip-bonux-3/demo/boucles_iterations.html [new file with mode: 0644]
www/plugins/spip-bonux-3/demo/noeud.html [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/annuler-recherche.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/article-12.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/deplier-droite.gif [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/deplier-droite.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/frame-close.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/item-add.gif [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/item-add.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/item-remove.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/logo-bonux.gif [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/message_erreur-24.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/message_notice-24.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/message_ok-24.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/spip-bonux.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/tri_asc-12.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/tri_asc-16.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/tri_asc-24.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/tri_asc.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/tri_desc-12.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/tri_desc-16.png [new file with mode: 0644]
www/plugins/spip-bonux-3/img_pack/tri_desc-24.png [new file with mode: 0644]
www/plugins/spip-bonux-3/inc/date_gestion.php [new file with mode: 0644]
www/plugins/spip-bonux-3/inc/exporter_csv.php [new file with mode: 0644]
www/plugins/spip-bonux-3/inc/importer_csv.php [new file with mode: 0644]
www/plugins/spip-bonux-3/javascript/jquery.qtip-1.0.0-rc3.js [new file with mode: 0644]
www/plugins/spip-bonux-3/javascript/jquery.qtip.activate.js [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/paquet-spip_bonux.xml [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/paquet-spip_bonux_ar.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/paquet-spip_bonux_en.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/paquet-spip_bonux_es.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/paquet-spip_bonux_fr.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/paquet-spip_bonux_ru.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/paquet-spip_bonux_sk.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/spip_bonux.xml [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/spip_bonux_ar.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/spip_bonux_en.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/spip_bonux_es.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/spip_bonux_fr.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/spip_bonux_ru.php [new file with mode: 0644]
www/plugins/spip-bonux-3/lang/spip_bonux_sk.php [new file with mode: 0644]
www/plugins/spip-bonux-3/modeles/pagination_noancre.html [new file with mode: 0644]
www/plugins/spip-bonux-3/paquet.xml [new file with mode: 0644]
www/plugins/spip-bonux-3/public/spip_bonux_balises.php [new file with mode: 0644]
www/plugins/spip-bonux-3/public/spip_bonux_criteres.php [new file with mode: 0644]
www/plugins/spip-bonux-3/spip_bonux_fonctions.php [new file with mode: 0644]
www/plugins/spip-bonux-3/spip_bonux_options.php [new file with mode: 0644]
www/plugins/spip-bonux-3/svn.revision [new file with mode: 0644]
www/plugins/spip-bonux-3/tests/balises/set_merge.html [new file with mode: 0644]
www/plugins/spip-bonux-3/tests/balises/set_push.html [new file with mode: 0644]
www/plugins/spip_piwik_2_0/action/piwik_creer_site.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/action/piwik_recuperer_liste.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/balise/piwik.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/fonds/cfg_piwik.html [new file with mode: 0644]
www/plugins/spip_piwik_2_0/formulaires/configurer_piwik.html [new file with mode: 0644]
www/plugins/spip_piwik_2_0/formulaires/configurer_piwik_fonctions.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/images/piwik-22.png [new file with mode: 0644]
www/plugins/spip_piwik_2_0/images/piwik.png [new file with mode: 0644]
www/plugins/spip_piwik_2_0/inc/piwik_recuperer_data.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/paquet-piwik.xml [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/paquet-piwik_en.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/paquet-piwik_es.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/paquet-piwik_fa.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/paquet-piwik_fr.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/paquet-piwik_ru.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/paquet-piwik_sk.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik.xml [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_ca.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_de.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_en.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_es.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_fa.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_fr.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_fr_tu.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/lang/piwik_sk.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/paquet.xml [new file with mode: 0644]
www/plugins/spip_piwik_2_0/piwik.png [new file with mode: 0644]
www/plugins/spip_piwik_2_0/piwik_administrations.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/piwik_pipelines.php [new file with mode: 0644]
www/plugins/spip_piwik_2_0/plugin.xml [new file with mode: 0644]
www/plugins/spip_piwik_2_0/prive/piwik.html [new file with mode: 0644]
www/plugins/spip_piwik_2_0/prive/squelettes/contenu/configurer_piwik.html [new file with mode: 0644]
www/plugins/spip_piwik_2_0/saisies/sites_piwik.html [new file with mode: 0644]
www/plugins/spip_piwik_2_0/svn.revision [new file with mode: 0644]
www/plugins/verifier/aide/verifier.html [new file with mode: 0644]
www/plugins/verifier/aide/verifier_fonctions.php [new file with mode: 0644]
www/plugins/verifier/images/icones-infos.txt [new file with mode: 0644]
www/plugins/verifier/images/verifier-128.png [new file with mode: 0644]
www/plugins/verifier/inc/is_email.php [new file with mode: 0644]
www/plugins/verifier/inc/verifier.php [new file with mode: 0644]
www/plugins/verifier/lang/paquet-verifier.xml [new file with mode: 0644]
www/plugins/verifier/lang/paquet-verifier_de.php [new file with mode: 0644]
www/plugins/verifier/lang/paquet-verifier_en.php [new file with mode: 0644]
www/plugins/verifier/lang/paquet-verifier_es.php [new file with mode: 0644]
www/plugins/verifier/lang/paquet-verifier_fr.php [new file with mode: 0644]
www/plugins/verifier/lang/paquet-verifier_ru.php [new file with mode: 0644]
www/plugins/verifier/lang/paquet-verifier_sk.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier.xml [new file with mode: 0644]
www/plugins/verifier/lang/verifier_ca.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_de.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_en.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_es.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_fa.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_fr.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_fr_tu.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_it.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_pt_br.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_ru.php [new file with mode: 0644]
www/plugins/verifier/lang/verifier_sk.php [new file with mode: 0644]
www/plugins/verifier/paquet.xml [new file with mode: 0644]
www/plugins/verifier/plugin.xml [new file with mode: 0644]
www/plugins/verifier/svn.revision [new file with mode: 0644]
www/plugins/verifier/test/verifier.html [new file with mode: 0644]
www/plugins/verifier/verifier/code_postal.php [new file with mode: 0644]
www/plugins/verifier/verifier/comparaison_champ.php [new file with mode: 0644]
www/plugins/verifier/verifier/couleur.php [new file with mode: 0644]
www/plugins/verifier/verifier/couleur.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/date.php [new file with mode: 0644]
www/plugins/verifier/verifier/date.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/decimal.php [new file with mode: 0644]
www/plugins/verifier/verifier/decimal.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/email.php [new file with mode: 0644]
www/plugins/verifier/verifier/email.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/entier.php [new file with mode: 0644]
www/plugins/verifier/verifier/entier.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/id_document.php [new file with mode: 0644]
www/plugins/verifier/verifier/isbn.php [new file with mode: 0644]
www/plugins/verifier/verifier/regex.php [new file with mode: 0644]
www/plugins/verifier/verifier/regex.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/siren_siret.php [new file with mode: 0644]
www/plugins/verifier/verifier/siren_siret.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/taille.php [new file with mode: 0644]
www/plugins/verifier/verifier/taille.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/telephone.php [new file with mode: 0644]
www/plugins/verifier/verifier/telephone.yaml [new file with mode: 0644]
www/plugins/verifier/verifier/url.php [new file with mode: 0644]
www/plugins/verifier/verifier/url.yaml [new file with mode: 0644]
www/plugins/yaml/demo/iter_data_yaml.html [new file with mode: 0644]
www/plugins/yaml/experimental/README [new file with mode: 0644]
www/plugins/yaml/experimental/yaml.html [new file with mode: 0644]
www/plugins/yaml/experimental/yaml_fonctions.php [new file with mode: 0644]
www/plugins/yaml/inc/yaml.php [new file with mode: 0644]
www/plugins/yaml/inc/yaml_sfyaml.php [new file with mode: 0644]
www/plugins/yaml/inc/yaml_to_array.php [new file with mode: 0644]
www/plugins/yaml/lang/paquet-yaml.xml [new file with mode: 0644]
www/plugins/yaml/lang/paquet-yaml_en.php [new file with mode: 0644]
www/plugins/yaml/lang/paquet-yaml_es.php [new file with mode: 0644]
www/plugins/yaml/lang/paquet-yaml_fa.php [new file with mode: 0644]
www/plugins/yaml/lang/paquet-yaml_fr.php [new file with mode: 0644]
www/plugins/yaml/lang/paquet-yaml_ru.php [new file with mode: 0644]
www/plugins/yaml/lang/paquet-yaml_sk.php [new file with mode: 0644]
www/plugins/yaml/paquet.xml [new file with mode: 0644]
www/plugins/yaml/plugin.xml [new file with mode: 0644]
www/plugins/yaml/sfyaml/sfYaml.php [new file with mode: 0755]
www/plugins/yaml/sfyaml/sfYamlDumper.php [new file with mode: 0755]
www/plugins/yaml/sfyaml/sfYamlInline.php [new file with mode: 0755]
www/plugins/yaml/sfyaml/sfYamlParser.php [new file with mode: 0755]
www/plugins/yaml/spyc/spyc-php4.php [new file with mode: 0644]
www/plugins/yaml/spyc/spyc.php [new file with mode: 0644]
www/plugins/yaml/svn.revision [new file with mode: 0644]
www/plugins/yaml/yaml.png [new file with mode: 0644]
www/plugins/yaml/yaml_fonctions.php [new file with mode: 0644]
www/plugins/zen-garden-2/action/zengarden_activer_switcher.php [new file with mode: 0644]
www/plugins/zen-garden-2/action/zengarden_activer_theme.php [new file with mode: 0644]
www/plugins/zen-garden-2/images/themes-128.png [new file with mode: 0644]
www/plugins/zen-garden-2/images/themes-32.png [new file with mode: 0644]
www/plugins/zen-garden-2/images/themes-64.png [new file with mode: 0644]
www/plugins/zen-garden-2/inc/zengarden.php [new file with mode: 0644]
www/plugins/zen-garden-2/inclure/zengarden_switcher.css [new file with mode: 0644]
www/plugins/zen-garden-2/inclure/zengarden_switcher.html [new file with mode: 0644]
www/plugins/zen-garden-2/inclure/zengarden_switcher.js [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden.xml [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden_en.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden_es.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden_fa.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden_fr.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden_nl.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden_ru.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/paquet-zengarden_sk.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/zengarden.xml [new file with mode: 0644]
www/plugins/zen-garden-2/lang/zengarden_de.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/zengarden_en.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/zengarden_es.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/zengarden_fa.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/zengarden_fr.php [new file with mode: 0644]
www/plugins/zen-garden-2/lang/zengarden_sk.php [new file with mode: 0644]
www/plugins/zen-garden-2/paquet.xml [new file with mode: 0644]
www/plugins/zen-garden-2/prive/squelettes/contenu/zengarden.html [new file with mode: 0644]
www/plugins/zen-garden-2/prive/squelettes/inclure/zengarden_theme.html [new file with mode: 0644]
www/plugins/zen-garden-2/prive/squelettes/inclure/zengarden_theme_actif.html [new file with mode: 0644]
www/plugins/zen-garden-2/prive/squelettes/navigation/zengarden.html [new file with mode: 0644]
www/plugins/zen-garden-2/prive/style_prive_plugin_zengarden.html [new file with mode: 0644]
www/plugins/zen-garden-2/prive/themes/spip/images/themes-16.png [new file with mode: 0644]
www/plugins/zen-garden-2/svn.revision [new file with mode: 0644]
www/plugins/zen-garden-2/zengarden_fonctions.php [new file with mode: 0644]
www/plugins/zen-garden-2/zengarden_options.php [new file with mode: 0644]
www/plugins/zen-garden-2/zengarden_pipelines.php [new file with mode: 0644]
www/plugins/zpip_v1/404.html [new file with mode: 0644]
www/plugins/zpip_v1/article.html [new file with mode: 0644]
www/plugins/zpip_v1/auteur.html [new file with mode: 0644]
www/plugins/zpip_v1/backend.html [new file with mode: 0644]
www/plugins/zpip_v1/body.html [new file with mode: 0644]
www/plugins/zpip_v1/breve.html [new file with mode: 0644]
www/plugins/zpip_v1/contact.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/article.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/auteur.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/breve.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/mot.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-401.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-404.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-forum.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-login.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-plan.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-recherche.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-sommaire.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page-spip_pass.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/page.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/rubrique.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/site.html [new file with mode: 0644]
www/plugins/zpip_v1/contenu/z_apl.html [new file with mode: 0644]
www/plugins/zpip_v1/conventions.txt [new file with mode: 0644]
www/plugins/zpip_v1/extra/article.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/auteur.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/breve.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/dist.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/mot.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/page-sommaire.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/page.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/rubrique.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/site.html [new file with mode: 0644]
www/plugins/zpip_v1/extra/z_apl.html [new file with mode: 0644]
www/plugins/zpip_v1/feed.png [new file with mode: 0644]
www/plugins/zpip_v1/forum.html [new file with mode: 0644]
www/plugins/zpip_v1/habillage.css [new file with mode: 0755]
www/plugins/zpip_v1/head/article.html [new file with mode: 0644]
www/plugins/zpip_v1/head/auteur.html [new file with mode: 0644]
www/plugins/zpip_v1/head/breve.html [new file with mode: 0644]
www/plugins/zpip_v1/head/dist.html [new file with mode: 0644]
www/plugins/zpip_v1/head/mot.html [new file with mode: 0644]
www/plugins/zpip_v1/head/page-404.html [new file with mode: 0644]
www/plugins/zpip_v1/head/page-plan.html [new file with mode: 0644]
www/plugins/zpip_v1/head/page-recherche.html [new file with mode: 0644]
www/plugins/zpip_v1/head/page-sommaire.html [new file with mode: 0644]
www/plugins/zpip_v1/head/page.html [new file with mode: 0644]
www/plugins/zpip_v1/head/rubrique.html [new file with mode: 0644]
www/plugins/zpip_v1/head/site.html [new file with mode: 0644]
www/plugins/zpip_v1/img/out.gif [new file with mode: 0644]
www/plugins/zpip_v1/img/zpip-128.png [new file with mode: 0644]
www/plugins/zpip_v1/img/zpip-16.png [new file with mode: 0644]
www/plugins/zpip_v1/img/zpip-32.png [new file with mode: 0644]
www/plugins/zpip_v1/img/zpip-48.png [new file with mode: 0644]
www/plugins/zpip_v1/img/zpip-64.png [new file with mode: 0644]
www/plugins/zpip_v1/inclure/ajax_parallel_load.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/article-resume.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/barre-nav-secteurs.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/barre-nav.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/documents.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/entete.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/forum.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/head.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/petition.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/pied.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/rss-item.html [new file with mode: 0644]
www/plugins/zpip_v1/inclure/rubriques.html [new file with mode: 0644]
www/plugins/zpip_v1/lang/zpip_de.php [new file with mode: 0644]
www/plugins/zpip_v1/lang/zpip_en.php [new file with mode: 0644]
www/plugins/zpip_v1/lang/zpip_es.php [new file with mode: 0644]
www/plugins/zpip_v1/lang/zpip_fr.php [new file with mode: 0644]
www/plugins/zpip_v1/lang/zpip_nl.php [new file with mode: 0644]
www/plugins/zpip_v1/lang/zpip_pt.php [new file with mode: 0644]
www/plugins/zpip_v1/lang/zpip_sv.php [new file with mode: 0644]
www/plugins/zpip_v1/login.html [new file with mode: 0644]
www/plugins/zpip_v1/mot.html [new file with mode: 0644]
www/plugins/zpip_v1/navigation/dist.html [new file with mode: 0644]
www/plugins/zpip_v1/navigation/page.html [new file with mode: 0644]
www/plugins/zpip_v1/navigation/z_apl.html [new file with mode: 0644]
www/plugins/zpip_v1/objet.html [new file with mode: 0644]
www/plugins/zpip_v1/page.html [new file with mode: 0644]
www/plugins/zpip_v1/plan.html [new file with mode: 0644]
www/plugins/zpip_v1/plugin.xml [new file with mode: 0644]
www/plugins/zpip_v1/recherche.html [new file with mode: 0644]
www/plugins/zpip_v1/rechercher.gif [new file with mode: 0644]
www/plugins/zpip_v1/rubrique.html [new file with mode: 0644]
www/plugins/zpip_v1/site.html [new file with mode: 0644]
www/plugins/zpip_v1/sommaire.html [new file with mode: 0644]
www/plugins/zpip_v1/spip.png [new file with mode: 0644]
www/plugins/zpip_v1/spip_formulaires.css [new file with mode: 0644]
www/plugins/zpip_v1/spip_pass.html [new file with mode: 0644]
www/plugins/zpip_v1/spip_style.css [new file with mode: 0644]
www/plugins/zpip_v1/structure.html [new file with mode: 0644]
www/plugins/zpip_v1/svn.revision [new file with mode: 0644]
www/plugins/zpip_v1/tests/z_scaffoldable.php [new file with mode: 0644]
www/plugins/zpip_v1/z_options.php [new file with mode: 0644]
www/plugins/zpip_v1/z_pipelines.php [new file with mode: 0644]
www/themes/theme_Outdoor1-0/body.html [new file with mode: 0644]
www/themes/theme_Outdoor1-0/habillage.css [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/Outdoor.css [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/bg.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/bullet.gif [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/content-bg.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/header-bg.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/header-photo.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/image-sample.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/nav-current.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/nav-hover.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/nav.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/quote.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/img/wrap-bg.jpg [new file with mode: 0644]
www/themes/theme_Outdoor1-0/inc-theme-copyleft.html [new file with mode: 0644]
www/themes/theme_Outdoor1-0/plugin.xml [new file with mode: 0644]
www/themes/theme_Outdoor1-0/svn.revision [new file with mode: 0644]
www/themes/theme_Outdoor1-0/vignette.jpg [new file with mode: 0644]

diff --git a/www/plugins/Menu_langue_lien/balise/menu_lang.php b/www/plugins/Menu_langue_lien/balise/menu_lang.php
new file mode 100644 (file)
index 0000000..7816784
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;   #securite
+
+// #MENU_LANG affiche le menu des langues de l'espace public
+// et preselectionne celle la globale $lang
+// ou de l'argument fourni: #MENU_LANG{#ENV{malangue}} 
+
+// http://doc.spip.org/@balise_MENU_LANG
+function balise_MENU_LANG ($p) {
+       $i_boucle = $p->nom_boucle ? $p->nom_boucle : ($p->id_boucle ? $p->id_boucle :'');
+       if($i_boucle){
+       $_id_objet = $p->boucles[$i_boucle]->primary;
+       }
+       
+       return calculer_balise_dynamique(
+               $p,
+               'MENU_LANG',
+               array(
+                       'LANG_TYPE_BOUCLE', // demande du type d'objet
+                       $_id_objet
+               )
+       );
+}
+
+// s'il n'y a qu'une langue eviter definitivement la balise ?php 
+// http://doc.spip.org/@balise_MENU_LANG_stat
+function balise_MENU_LANG_stat ($args, $context_compil) {
+       if (strpos($GLOBALS['meta']['langues_multilingue'],',') === false) return '';
+       $objet = $args[0];
+       $id_objet = $args[1];
+       if ($objet == 'balise_hors_boucle') {
+               $objet = '';
+               $id_objet = '';
+               $id_table_objet ='';
+       }else{
+               $objet = table_objet($objet);
+               $id_table_objet = id_table_objet($objet);
+       }
+       return array($objet, $id_objet,$id_table_objet);
+}
+
+// normalement $opt sera toujours non vide suite au test ci-dessus
+// http://doc.spip.org/@balise_MENU_LANG_dyn
+function balise_MENU_LANG_dyn($objet,$id_objet,$id_table_objet) {
+       include_spip('inc/lang');
+       # lien a partir de /
+       $cible = parametre_url(self(), 'lang' , '', '&');
+       $post = generer_url_action('converser', 'redirect='. rawurlencode($cible), '&');
+
+       return array('formulaires/menu_lang',
+               3600,
+               array(
+                       //'nom' => $nom,
+                       'lang' => $GLOBALS['spip_lang'],
+                       'url' => $post,
+                       $id_table_objet => $id_objet
+               )
+       );
+}
+
+// balise type_boucle de Rastapopoulos dans le plugin etiquettes
+// present aussi dans plugin ajaxforms...
+// bref, a integrer dans le core ? :p
+function balise_LANG_TYPE_BOUCLE($p) {
+       $type = $p->boucles[$p->id_boucle]->id_table;
+       $p->code = $type ? $type : "balise_hors_boucle";
+       return $p;
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/fonds/cfg_menu_lang_liens.html b/www/plugins/Menu_langue_lien/fonds/cfg_menu_lang_liens.html
new file mode 100644 (file)
index 0000000..c4f5082
--- /dev/null
@@ -0,0 +1,9 @@
+<!-- titre=<:mll:cfg_titre_mll:> -->
+<!-- icone=img_pack/world_link-16.png -->
+<!-- autoriser=webmestre -->
+<!-- refus=<:cfg:refus_configuration_webmestre:> -->
+
+#CACHE{0}
+<div class="ajax">
+#FORMULAIRE_CONFIGURER_MENU_LANG_LIENS
+</div>
diff --git a/www/plugins/Menu_langue_lien/formulaires/configurer_menu_lang_liens.html b/www/plugins/Menu_langue_lien/formulaires/configurer_menu_lang_liens.html
new file mode 100644 (file)
index 0000000..dc8600a
--- /dev/null
@@ -0,0 +1,47 @@
+<!-- autoriser=webmestre -->\r
+<!-- refus=<:cfg:refus_configuration_webmestre:> -->\r
+<!-- nom=menu_lang_liens -->\r
+\r
+<div class="formulaire_spip formulaire_configurer formulaire_configurer_mll">\r
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+<form method="post" action="#ENV{action}"><div>\r
+       #ACTION_FORMULAIRE{#ENV{action}}\r
+       <ul>\r
+               <li class="editer_mll_langues_invisibles[ (#ENV**{erreurs}|table_valeur{licence_defaut}|oui)erreur]">\r
+                       <label for="langues_invisibles"><:mll:label_langues_invisibles:></label>\r
+                       <p class="explication"><:mll:explication_langues_invisibles:></p>\r
+                       <select name="langues_invisibles[]" id="langues_invisibles" multiple="oui">\r
+                               <BOUCLE_langues(POUR){tableau #CONFIG{langues_multilingue}|explode{','}}>\r
+                               <option value="#VALEUR"[(#VALEUR|in_array{#ENV{langues_invisibles,#ARRAY}}|oui)selected="selected"]>[(#VALEUR|traduire_nom_langue)]</option>\r
+                               </BOUCLE_langues>\r
+                       </select>\r
+               </li>\r
+               <li class="editer_mll_langues_supprimer[ (#ENV**{erreurs}|table_valeur{licence_defaut}|oui)erreur]">\r
+                       <label for="format"><:mll:label_format:></label>\r
+                       <div class="choix">\r
+                       <input type="radio" name="format" id="abrege" value="abrege" [(#ENV{format,abrege}|=={'abrege'}|?{' ',''})checked]/> \r
+                       <label for="abrege"><:mll:label_format_abrege:></label>\r
+                       </div>\r
+                       <div class="choix">\r
+                               <input type="radio" name="format" id="complet" value="complet" [(#ENV{format,abrege}|=={'complet'}|?{' ',''})checked]/> \r
+                               <label for="complet"><:mll:label_format_complet:></label>\r
+                       </div>            \r
+               </li>\r
+               <li class="editer_mll_langues_supprimer[ (#ENV**{erreurs}|table_valeur{licence_defaut}|oui)erreur]">\r
+                       <label for="formatliste"><:mll:label_format_liste:></label>\r
+                       <div class="choix">\r
+                               <input type="radio" name="formatliste" id="bloc" value="bloc" [(#ENV{formatliste,bloc}|=={'bloc'}|?{' ',''})checked]/> \r
+                               <label for="bloc"><:mll:label_format_liste_bloc:></label>\r
+                       </div>            \r
+                       <div class="choix">\r
+                               <input type="radio" name="formatliste" id="liste" value="liste" [(#ENV{formatliste,bloc}|=={'liste'}|?{' ',''})checked]/> \r
+                               <label for="liste"><:mll:label_format_liste_liste:></label>\r
+                       </div>\r
+               </li>\r
+       </ul>\r
+       <p class="boutons">\r
+               <input type="submit" name="_cfg_ok" class="submit" value="<:bouton_enregistrer:>" />\r
+       </p>\r
+</div></form>\r
+</div>
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/formulaires/menu_lang.html b/www/plugins/Menu_langue_lien/formulaires/menu_lang.html
new file mode 100644 (file)
index 0000000..648967c
--- /dev/null
@@ -0,0 +1,70 @@
+[(#REM) 
+Stocker les traductions eventuelles de l'article en cours
+]
+<BOUCLE_article(ARTICLES){id_article}>
+#SET{ListeTraductions, #ARRAY{}}
+<BOUCLE_TraductionArticleCourant(ARTICLES){traduction}{lang !IN #CONFIG{menu_lang_liens/langues_invisibles,#ARRAY}}>
+       #SET_MERGE{ListeTraductions,#GET{ListeTraductions},#ARRAY{#LANG,#URL_ARTICLE}}
+</BOUCLE_TraductionArticleCourant>
+</BOUCLE_article>
+
+[(#REM) 
+Stocker les traductions eventuelles de la rubrique en cours si le plugin Tradrub est installe (permet l'utilisation du
+critere traduction sur les rubriques)
+]
+<BOUCLE_tradrub(CONDITION){si #PLUGIN{tradrub}}>
+    <BOUCLE_rubrique(RUBRIQUES){id_rubrique}>
+        #SET{ListeTraductions, #ARRAY{}}
+        <BOUCLE_TraductionRubriqueCourante(RUBRIQUES){traduction}{lang !IN #CONFIG{menu_lang_liens/langues_invisibles,#ARRAY}}>
+            #SET_MERGE{ListeTraductions,#GET{ListeTraductions},#ARRAY{#LANG,#URL_RUBRIQUE}}
+        </BOUCLE_TraductionRubriqueCourante>
+    </BOUCLE_rubrique>
+</BOUCLE_tradrub>
+
+[(#REM) 
+Y-a-t'il plus d'une langue reellement utilisee dans le site (moins les langues "invisibles") ?
+Si oui, on affiche le menu de langue
+Si non, rien
+
+Les langues "invisibles" sont les langues que le webmestre peut choisir de ne pas afficher dans le menu, 
+a partir du formulaire de configuration du plugin.
+
+Note : 'explode' est une fonction PHP : http://php.net/manual/fr/function.explode.php, utilisee ici pour renvoyer un tableau contenant 
+les langues utilisees, a partir de la variable meta 'langues_utilisees'. Ce tableau est compare avec le tableau des langues invisibles
+avec la fonction PHP 'array_diff' http://www.php.net/manual/fr/function.array-diff.php qui renvoie elle-meme un tableau. 
+
+]
+
+[(#SET{langues_a_afficher,[(#CONFIG{langues_utilisees}|explode{","}|array_diff{#CONFIG{menu_lang_liens/langues_invisibles, #ARRAY}})]})]
+
+<BOUCLE_PlusieursLanguesUtilisees(POUR){tableau #GET{langues_a_afficher}}{1,1}>
+<[(#CONFIG{menu_lang_liens/formatliste,bloc}|=={'bloc'}|?{div,ul})] id="menu_lang">
+[(#REM)
+On liste les langues utilisees dans le site
+]
+       <BOUCLE_ListeLangues(POUR){tableau #GET{langues_a_afficher}}>
+       [(#CONFIG{menu_lang_liens/formatliste,bloc}|=={'liste'}|oui)<li [(#COMPTEUR_BOUCLE|=={1}|oui)class="first"] [(#COMPTEUR_BOUCLE|=={#TOTAL_BOUCLE}|oui)class="last"]>]
+               [(#REM)
+               Si la langue n'est pas celle en cours, on fait un lien qui fait 2 actions :
+               - fixer le cookie de langue sur la langue demandee
+               - rediriger sur l'article dans la langue demandee si opportun
+                 sinon, revenir sur la page en cours
+               ]
+        [(#CONFIG{menu_lang_liens/format,abrege}|=={'complet'}|oui)[(#SET{nom_langue,[(#VALEUR|traduire_nom_langue)]})]]   
+        [(#CONFIG{menu_lang_liens/format,abrege}|=={'abrege'}|oui)[(#SET{nom_langue,[(#VALEUR)]})]]
+               [(#VALEUR|=={#ENV{lang}}|non)
+                       [(#REM)
+                               url_absolue pour éviter des problèmes en urls arbo
+                       ] 
+                       [<a href="[(#SELF|parametre_url{action,converser}|parametre_url{var_lang,#VALEUR}|parametre_url{redirect,#GET{ListeTraductions}|table_valeur{#VALEUR}|sinon{#SELF}|url_absolue})]" rel="alternate" lang="#VALEUR"[(#CONFIG{menu_lang_liens/format,abrege}|=={'abrege'}|oui) title="[(#VALEUR|traduire_nom_langue|ucfirst|attribut_html)]"] class="langue_#VALEUR">(#GET{nom_langue}|ucfirst)</a>]
+               ]
+               [(#REM)
+               Si la langue est celle en cours, afficher celle-ci en gras, sans lien
+               ]
+               [(#VALEUR|=={#ENV{lang}}|oui)
+                       [<strong class="langue_#VALEUR" title="[(#VALEUR|traduire_nom_langue|ucfirst|attribut_html)]">(#GET{nom_langue}|ucfirst)</strong>]
+               ]
+        [(#CONFIG{menu_lang_liens/formatliste,bloc}|=={'liste'}|oui)</li>]
+       </BOUCLE_ListeLangues>
+</[(#CONFIG{menu_lang_liens/formatliste,bloc}|=={'bloc'}|?{div,ul})]>
+</BOUCLE_PlusieursLanguesUtilisees>
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/img_pack/world_link-16.png b/www/plugins/Menu_langue_lien/img_pack/world_link-16.png
new file mode 100755 (executable)
index 0000000..e737026
Binary files /dev/null and b/www/plugins/Menu_langue_lien/img_pack/world_link-16.png differ
diff --git a/www/plugins/Menu_langue_lien/img_pack/world_link-24.png b/www/plugins/Menu_langue_lien/img_pack/world_link-24.png
new file mode 100644 (file)
index 0000000..fcd0d5f
Binary files /dev/null and b/www/plugins/Menu_langue_lien/img_pack/world_link-24.png differ
diff --git a/www/plugins/Menu_langue_lien/img_pack/world_link-32.png b/www/plugins/Menu_langue_lien/img_pack/world_link-32.png
new file mode 100755 (executable)
index 0000000..5c1384a
Binary files /dev/null and b/www/plugins/Menu_langue_lien/img_pack/world_link-32.png differ
diff --git a/www/plugins/Menu_langue_lien/lang/mll.xml b/www/plugins/Menu_langue_lien/lang/mll.xml
new file mode 100644 (file)
index 0000000..aecfbcb
--- /dev/null
@@ -0,0 +1,10 @@
+<traduction module="mll" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/menu_langues_liens/lang/" reference="fr">
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/mll?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/mll?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/Menu_langue_lien/lang/mll_en.php b/www/plugins/Menu_langue_lien/lang/mll_en.php
new file mode 100755 (executable)
index 0000000..6e08135
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/mll?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_titre_mll' => 'Language menu as links',
+
+       // E
+       'explication_langues_invisibles' => 'Allows to remove some languages ​​from the menu',
+
+       // L
+       'label_format' => 'Languages display format',
+       'label_format_abrege' => 'Shortened (for instance, Fr)',
+       'label_format_complet' => 'Complete (for instance, Français)',
+       'label_format_liste' => 'Languages list display format',
+       'label_format_liste_bloc' => 'A block divided by spaces',
+       'label_format_liste_liste' => 'A bulleted list',
+       'label_langues_invisibles' => 'Invisible languages in the​​ menu'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/lang/mll_es.php b/www/plugins/Menu_langue_lien/lang/mll_es.php
new file mode 100644 (file)
index 0000000..7264cf4
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/mll?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_titre_mll' => 'Menú de idiomas en forma de enlaces',
+
+       // E
+       'explication_langues_invisibles' => 'Permite quitar algunos idiomas del menú',
+
+       // L
+       'label_format' => 'Formato de visualización de los idiomas',
+       'label_format_abrege' => 'Abreviado (por ejemplo, Es)',
+       'label_format_complet' => 'Completo (por ejemplo, Español)',
+       'label_format_liste' => 'Formato de la lista de idiomas',
+       'label_format_liste_bloc' => 'Bloque separado por espacios',
+       'label_format_liste_liste' => 'Lista por viñetas',
+       'label_langues_invisibles' => 'Idiomas invisibles del menú'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/lang/mll_fr.php b/www/plugins/Menu_langue_lien/lang/mll_fr.php
new file mode 100755 (executable)
index 0000000..e981ffe
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/menu_langues_liens/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_titre_mll' => 'Menu de langues sous forme de liens',
+
+       // E
+       'explication_langues_invisibles' => 'Permet d\'enlever certaines langues du menu',
+
+       // L
+       'label_format' => 'Format d\'affichage des langues',
+       'label_format_abrege' => 'Abrégé (par exemple, Fr)',
+       'label_format_complet' => 'Complet (par exemple, Français)',
+       'label_format_liste' => 'Format de la liste des langues',
+       'label_format_liste_bloc' => 'Un bloc séparé par des espaces',
+       'label_format_liste_liste' => 'Une liste à puces',
+       'label_langues_invisibles' => 'Langues invisibles du menu'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/lang/mll_sk.php b/www/plugins/Menu_langue_lien/lang/mll_sk.php
new file mode 100644 (file)
index 0000000..59b56c4
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/mll?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_titre_mll' => 'Jazykové menu vo forme odkazov',
+
+       // E
+       'explication_langues_invisibles' => 'Umožňuje odstrániť z menu niektoré jazyky',
+
+       // L
+       'label_format' => 'Formát zobrazenia jazykov',
+       'label_format_abrege' => 'Skrátený (napríklad Sk)',
+       'label_format_complet' => 'Úplný (napríklad Slovenčina)',
+       'label_format_liste' => 'Formát zoznamu jazykov',
+       'label_format_liste_bloc' => 'Blok oddelený medzerami',
+       'label_format_liste_liste' => 'Zoznam s odrážkami',
+       'label_langues_invisibles' => 'Jazyky, ktoré nebudú zobrazené v menu'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/lang/paquet-mll.xml b/www/plugins/Menu_langue_lien/lang/paquet-mll.xml
new file mode 100644 (file)
index 0000000..4bd03eb
--- /dev/null
@@ -0,0 +1,10 @@
+<traduction module="paquet-mll" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/menu_langues_liens/lang/" reference="fr">
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-mll?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-mll?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/Menu_langue_lien/lang/paquet-mll_en.php b/www/plugins/Menu_langue_lien/lang/paquet-mll_en.php
new file mode 100644 (file)
index 0000000..b31b6df
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-mll?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'mll_description' => 'Replace the original language menu by a clickable menu. This menu is displayed only if at least two languages are ​​actually used on the site.',
+       'mll_nom' => 'Language menu as links',
+       'mll_slogan' => 'View languages ​​as clickable links'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/lang/paquet-mll_es.php b/www/plugins/Menu_langue_lien/lang/paquet-mll_es.php
new file mode 100644 (file)
index 0000000..15d889a
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-mll?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'mll_description' => 'Remplaza al menú desplegable de idiomas por un menú en el que hacer click. Este menú no se muestra salvo si hay al menos 2 idiomas verdaderamente utilizados en el sitio.',
+       'mll_nom' => 'Menú de idiomas con enlaces',
+       'mll_slogan' => 'Mostrar los idiomas bajo la forma de enlaces en los que hacer click'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/lang/paquet-mll_fr.php b/www/plugins/Menu_langue_lien/lang/paquet-mll_fr.php
new file mode 100644 (file)
index 0000000..ad4808f
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/menu_langues_liens/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'mll_description' => 'Remplace le menu déroulant de langues par un menu cliquable. Ce menu n\'est affiché que s\'il y a au moins 2 langues vraiment utilisées dans le site.',
+       'mll_nom' => 'Menu de langues avec liens',
+       'mll_slogan' => 'Afficher les langues sous forme de liens cliquables'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/lang/paquet-mll_sk.php b/www/plugins/Menu_langue_lien/lang/paquet-mll_sk.php
new file mode 100644 (file)
index 0000000..f7117e7
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-mll?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'mll_description' => 'Rozbaľovacie menu s jazykmi nahradí klikateľným. Toto menu sa nezobrazí, ak sa na stránke naozaj nepoužívajú aspoň 2 jazyky.',
+       'mll_nom' => 'Jazykové menu s odkazmi',
+       'mll_slogan' => 'Zobraziť jazyky vo forme klikateľných odkazov'
+);
+
+?>
diff --git a/www/plugins/Menu_langue_lien/mll_options.php b/www/plugins/Menu_langue_lien/mll_options.php
new file mode 100644 (file)
index 0000000..a5a023a
--- /dev/null
@@ -0,0 +1,4 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return; \r
+$GLOBALS['forcer_lang'] = true;\r
+?>
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/mll_pipelines.php b/www/plugins/Menu_langue_lien/mll_pipelines.php
new file mode 100755 (executable)
index 0000000..7e88b7b
--- /dev/null
@@ -0,0 +1,12 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return; \r
+\r
+function mll_insert_head_css($flux){\r
+       // Insertion de la feuille de styles du menu de langues\r
+       $css_mll = find_in_path('mll_styles.css');\r
+       $flux .='<link rel="stylesheet" type="text/css" media="screen" href="'.$css_mll.'" />';\r
+\r
+       return $flux;\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/mll_styles.css b/www/plugins/Menu_langue_lien/mll_styles.css
new file mode 100755 (executable)
index 0000000..66e9f0c
--- /dev/null
@@ -0,0 +1,28 @@
+#menu_lang {\r
+    list-style: none outside none;    \r
+}\r
+\r
+#menu_lang li {\r
+    float: left;\r
+}\r
+\r
+#menu_lang li a, #menu_lang li span, #menu_lang li strong {\r
+    border-left: 1px solid;\r
+}\r
+\r
+#menu_lang li a, #menu_lang li span, #menu_lang li strong {\r
+    padding: 0 5px;\r
+    font-size: 11px;\r
+}\r
+\r
+#menu_lang li.first a, #menu_lang li.first span, #menu_lang li.first strong {\r
+    border: none;\r
+}\r
+\r
+#menu_lang li.last a, #menu_lang li.last span, #menu_lang li.last strong {\r
+    padding-right: 0;\r
+}\r
+\r
+#menu_lang li a:hover {\r
+    text-decoration: underline;\r
+}
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/paquet.xml b/www/plugins/Menu_langue_lien/paquet.xml
new file mode 100644 (file)
index 0000000..19a5c6b
--- /dev/null
@@ -0,0 +1,23 @@
+<paquet
+       prefix="mll"
+       categorie="navigation"
+       version="1.1.9"
+       etat="test"
+       compatibilite="[2.0.10;3.0.*]"
+       logo="prive/themes/spip/images/world_link-32.png"
+       documentation="http://www.spip-contrib.net/Menu-de-langues-sous-forme-de-liens"
+       >       
+       <nom>Menu de langues avec liens</nom>
+       <!-- Afficher les langues sous forme de liens cliquables -->
+       <auteur lien="http://www.spip-contrib.net/_Jacques-PYRAT_">Jacques</auteur>
+       <auteur>Jean-Baptiste Pressac</auteur>
+       <auteur lien="http://www.kent1.info">kent1</auteur>
+       <auteur>Cédric Morin</auteur>
+       <credit lien="http://www.fatcow.com/free-icons">icône par FatCow</credit>
+       <copyright>2009-2012</copyright>
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>
+       <pipeline nom="insert_head_css" inclure="mll_pipelines.php" />
+       <necessite nom="spip_bonux" compatibilite="[3.0.0-dev;[" />
+       <utilise nom="tradrub" compatibilite="[2.1.1;[" />
+       <menu nom="config_mll" titre="mll:cfg_titre_mll" parent="menu_squelette" icone="images/world_link-16.png" action="configurer_mll"/>
+</paquet>
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/plugin.xml b/www/plugins/Menu_langue_lien/plugin.xml
new file mode 100644 (file)
index 0000000..46eb697
--- /dev/null
@@ -0,0 +1,53 @@
+<plugin>\r
+       <nom>\r
+               <multi>\r
+                       [fr]Menu de langues avec liens\r
+                       [en]Language menu as links\r
+               </multi>\r
+       </nom>\r
+       <slogan>\r
+               <multi>\r
+               [fr]Afficher les langues sous forme de liens cliquables\r
+               [en]View languages ​​as clickable links\r
+               </multi>\r
+       </slogan>\r
+       <auteur>[Jacques->http://www.spip-contrib.net/_Jacques-PYRAT_] - Jean-Baptiste Pressac - Quentin Drouet - Cedric Morin</auteur>\r
+       <licence>&#169; 2009-2012 GNU/GPL</licence>\r
+       <lien>http://www.spip-contrib.net/Menu-de-langues-sous-forme-de-liens</lien>\r
+       <version>1.1.9</version>\r
+       <etat>test</etat>\r
+       <description>\r
+               <multi>\r
+[fr]Remplace le menu d&#233;roulant de langues par un menu cliquable. Ce menu n'est affich&#233; que s'il y a au moins 2 langues vraiment utilis&#233;es dans le site.\r
+\r
+Icone par [FatCow->http://www.fatcow.com/free-icons]\r
+[en]Replace the original language menu by a clickable menu. This menu is displayed only if at least two languages are ​​actually used on the site.\r
+       \r
+Icon by [FatCow->http://www.fatcow.com/free-icons]\r
+               </multi>\r
+       </description>\r
+       <prefix>mll</prefix>\r
+       <icon>img_pack/world_link-32.png</icon>\r
+       <options>mll_options.php</options>\r
+       <pipeline>\r
+               <nom>insert_head_css</nom>\r
+               <inclure>mll_pipelines.php</inclure>\r
+       </pipeline>\r
+       <necessite id="SPIP" version="[2.0.10;2.1.99]" />\r
+       <necessite id='spip_bonux' version='[1.9.1;]' src="http://files.spip.org/spip-zone/spip-bonux.zip" />\r
+       <utilise id='tradrub' version='[2.1.1;]' src="http://files.spip.org/spip-zone/tradrub_dev.zip" />               \r
+       <utilise id='cfg' version='[1.3.6;]' src="http://files.spip.org/spip-zone/cfg.zip" />                                   \r
+       <categorie>navigation</categorie>\r
+       <bouton id="config_mll" parent="configuration">\r
+       <icone>img_pack/world_link-24.png</icone>\r
+       <titre>mll:cfg_titre_mll</titre>   \r
+       <url>cfg</url>   \r
+       <args>cfg=menu_lang_liens</args>\r
+       </bouton>\r
+       <bouton id="bando_config_mll" parent="bando_configuration">\r
+       <icone>img_pack/world_link-16.png</icone>\r
+       <titre>mll:cfg_titre_mll</titre>   \r
+       <url>cfg</url>   \r
+       <args>cfg=menu_lang_liens</args>\r
+       </bouton>       \r
+</plugin>
\ No newline at end of file
diff --git a/www/plugins/Menu_langue_lien/prive/squelettes/contenu/configurer_mll.html b/www/plugins/Menu_langue_lien/prive/squelettes/contenu/configurer_mll.html
new file mode 100644 (file)
index 0000000..4cf4e9f
--- /dev/null
@@ -0,0 +1,5 @@
+[(#AUTORISER{webmestre}|sinon_interdire_acces)]
+<h1 class="grostitre"><:mll:cfg_titre_mll:></h1>
+<div class="ajax">
+       #FORMULAIRE_CONFIGURER_MENU_LANG_LIENS
+</div>
diff --git a/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-16.png b/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-16.png
new file mode 100755 (executable)
index 0000000..e737026
Binary files /dev/null and b/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-16.png differ
diff --git a/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-24.png b/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-24.png
new file mode 100644 (file)
index 0000000..fcd0d5f
Binary files /dev/null and b/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-24.png differ
diff --git a/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-32.png b/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-32.png
new file mode 100755 (executable)
index 0000000..5c1384a
Binary files /dev/null and b/www/plugins/Menu_langue_lien/prive/themes/spip/images/world_link-32.png differ
diff --git a/www/plugins/Menu_langue_lien/svn.revision b/www/plugins/Menu_langue_lien/svn.revision
new file mode 100644 (file)
index 0000000..3d836e7
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/menu_langues_liens
+Revision: 71303
+Dernier commit: 2013-03-30 04:01:43 +0100 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/menu_langues_liens</origine>
+<revision>71303</revision>
+<commit>2013-03-30 04:01:43 +0100 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/abomailman_template.html b/www/plugins/abomailmans/abomailman_template.html
new file mode 100644 (file)
index 0000000..fa40a36
--- /dev/null
@@ -0,0 +1,6 @@
+#CACHE{0}\r
+[(#ENV{envoi_txt}|non)\r
+       <INCLURE{fond=templates/#ENV{template},env}>]\r
+[(#ENV{envoi_txt}|oui|et{#CHEMIN{templates/#ENV{template}.txt.html}|oui})\r
+       <INCLURE{fond=templates/#ENV{template}.txt,env}>\r
+]
\ No newline at end of file
diff --git a/www/plugins/abomailmans/abomailmans_administrations.php b/www/plugins/abomailmans/abomailmans_administrations.php
new file mode 100644 (file)
index 0000000..86fa3cf
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function abomailmans_upgrade($nom_meta_base_version,$version_cible){
+       
+       $maj = array();
+       
+       $maj['create'] = array(
+               array('creer_base'),
+       );
+       
+       $maj['0.30'] = array(array('maj_tables',array('spip_abomailmans')));
+       $maj['0.31'] = array(array('maj_tables',array('spip_abomailmans')));
+       $maj['0.32'] = array(array('maj_tables',array('spip_abomailmans')));
+       $maj['0.33'] = array(array('maj_tables',array('spip_abomailmans')));
+       $maj['0.34'] = array(array('maj_tables',array('spip_abomailmans')));
+       include_spip('base/upgrade');
+       maj_plugin($nom_meta_base_version, $version_cible, $maj);
+}
+
+function abomailmans_vider_tables($nom_meta_base_version) {
+       include_spip('base/abstract_sql');
+       sql_drop_table("spip_abomailmans");
+       effacer_meta($nom_meta_base_version);
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/abomailmans_autoriser.php b/www/plugins/abomailmans/abomailmans_autoriser.php
new file mode 100755 (executable)
index 0000000..ec860f9
--- /dev/null
@@ -0,0 +1,32 @@
+<?php\r
+/**\r
+ * Abomailmans\r
+ * MaZiaR - NetAktiv\r
+ * tech@netaktiv.com\r
+ * © 2007 - 2012\r
+ */\r
+\r
+/**\r
+ * Fonction pour le pipeline, n'a rien a effectuer\r
+ *\r
+*/\r
+function abomailmans_autoriser(){}\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+// autorisation des boutons\r
+function autoriser_abomailman_bouton_dist($faire, $type, $id, $qui, $opt) {\r
+       spip_log('bouton autoriser','test');\r
+       return autoriser('modifier', $type, $id, $qui, $opt);\r
+}\r
+\r
+function autoriser_abomailman_creer_dist($faire, $type, $id, $qui, $opt){\r
+       spip_log('creer autoriser','test');\r
+       return autoriser('modifier', $type, $id, $qui, $opt);\r
+}\r
+\r
+function autoriser_abomailman_modifier_dist($faire, $type, $id, $qui, $opt){\r
+       return ($qui['statut']=='0minirezo')  AND !$qui['restreint'];\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/abomailmans_fonctions.php b/www/plugins/abomailmans/abomailmans_fonctions.php
new file mode 100755 (executable)
index 0000000..3b8aa9a
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/*
+ * Abomailmans
+ * MaZiaR - NetAktiv
+ * tech@netaktiv.com
+ * Printemps 2007 - 2012
+ * $Id: abomailmans_fonctions.php 58718 2012-02-20 13:00:39Z root $
+*/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function nettoie_chemin($chemin){
+       $liste = explode ("/", $chemin);
+       $dernier=count($liste)-1;
+       $chemin = str_replace('.html','',$liste[$dernier]);
+       $liste2 = explode('&',$chemin);
+       $chemin = $liste2[0];
+       return $chemin;
+}
+
+function noextension($chemin){
+       return str_replace('.html','',$chemin);
+}
+
+function recup_param($chemin){
+       $a = explode('&', $chemin);
+       $i = 1;
+       while ($i < count($a)) { 
+           $retour.= "&".htmlspecialchars(urldecode($a[$i]));
+           $i++;
+       }       
+       return $retour;
+}
+
+function array_param($params){
+       parse_str($params,$output);
+       return $output; 
+}
+
+function moins30($date) {
+       $moins30 = date('Y-m-d h:m:s', time()-24*3600*30);  
+       return $moins30;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/abomailmans_pipelines.php b/www/plugins/abomailmans/abomailmans_pipelines.php
new file mode 100755 (executable)
index 0000000..4ab2a0d
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+/*
+ * Abomailmans
+ * MaZiaR - NetAktiv
+ * tech@netaktiv.com
+ * Printemps 2007 - 2012
+ * $Id: abomailmans_interface.php 31752 2009-09-23 00:09:48Z kent1@arscenic.info $
+*/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * 
+ * Declarer la tache cron de abomailman lente (messagerie de l'espace prive)
+ * @param array $taches_generales
+ * @return array 
+ */
+function abomailmans_taches_generales_cron($taches_generales){
+       $taches_generales['abomailmans_envois'] = 60 * 10; // toutes les 10 minutes
+       return $taches_generales;
+}
+
+
+// Initialise les reglages sous forme de tableau
+function abomailmans_go($x) {
+       if (!is_array($GLOBALS['abomailmans']   = @unserialize($GLOBALS['meta']['abomailmans'])))
+               $GLOBALS['abomailmans'] = array();
+       return $x;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/base/abomailmans_install.php b/www/plugins/abomailmans/base/abomailmans_install.php
new file mode 100755 (executable)
index 0000000..390d9b0
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+/*
+ * Abomailmans
+ * MaZiaR - NetAktiv
+ * tech@netaktiv.com
+ * © 2007 - 2012
+ * $Id: abomailmans_install.php 60007 2012-04-02 13:00:22Z root $
+*/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function abomailmans_declarer_tables_interfaces($interface){
+       $interface['table_des_tables']['abomailmans'] = 'abomailmans';
+       return $interface;
+}
+
+function abomailmans_declarer_tables_objets_sql($tables){
+       $tables['spip_abomailmans'] = array(
+               'page' => 'abomailman',
+               'url_edit' => 'abomailman_edit',
+               'editable' => 'oui',
+               'texte_retour' => 'abomailmans:icone_retour_abomailman',
+               'texte_objet' => 'abomailmans:abomailman',
+               'texte_objets' => 'abomailmans:abomailmans',
+               'texte_modifier' => 'abomailmans:icone_modifier_abomailman',
+               'texte_creer' => 'abomailmans:nouveau_abomailman',
+               'info_aucun_objet'=> 'abomailmans:info_abomailman_aucun',
+               'info_1_objet' => 'abomailmans:info_abomailmans_1',
+               'info_nb_objets' => 'abomailmans:info_abomailmans_nb',
+               'icone_objet' => 'abomailmans-24',
+               'titre' => "titre, '' AS lang",
+               'principale' => 'oui',
+               'champs_editables' => array('titre','descriptif','abo_type','email','email_sympa','email_subscribe','email_unsubscribe','modele_defaut','periodicite','lang','desactive'),
+               'field'=> array(
+                       "id_abomailman" => "bigint(21) NOT NULL",
+                       "titre"         => "varchar(255) NOT NULL",
+                       "descriptif"    => "text",
+                       "abo_type" => "varchar(255) DEFAULT 'news' NOT NULL",
+                       "email"         => "varchar(255)",
+                       "email_sympa"   => "varchar(255) DEFAULT '' NOT NULL",
+                       "email_subscribe"   => "varchar(255)",
+                       "email_unsubscribe" => "varchar(255)",
+                       "modele_defaut" => "varchar(255) DEFAULT '' NOT NULL",
+                       "periodicite" => "varchar(255) DEFAULT '' NOT NULL",
+                       "maj"           => "TIMESTAMP",
+                       "date_envoi"    => "TIMESTAMP",
+                       "lang"          => "VARCHAR(10) DEFAULT '' NOT NULL",
+                       "desactive"     => "tinyint(4) NOT NULL default '0'"
+               ),
+               'key' => array(
+                       "PRIMARY KEY"   => "id_abomailman"
+               ),
+               'rechercher_champs' => array(
+                       'titre' => 8,
+                       'descriptif' => 8
+               ),
+               'champs_versionnes' => array('titre', 'descriptif', 'email', 'email_sympa', 'email_subscribe', 'email_unsubscribe', 'modele_defaut','periodicite','lang','desactive')
+       );
+       return $tables;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/content/newsletter.html b/www/plugins/abomailmans/content/newsletter.html
new file mode 100644 (file)
index 0000000..49cb394
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a><span class="sep"> &gt; </span><strong class="on"><:abomailmans:bouton_listes_diffusion:></strong></p>
+
+<div class="contenu-principal">
+       <div class="cartouche">
+    </div>
+    <div class="formulaire_abomailman ajax">\r
+        #FORMULAIRE_ABOMAILMAN\r
+    </div>
+</div>
diff --git a/www/plugins/abomailmans/contenu/page-newsletter.html b/www/plugins/abomailmans/contenu/page-newsletter.html
new file mode 100644 (file)
index 0000000..49cb394
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a><span class="sep"> &gt; </span><strong class="on"><:abomailmans:bouton_listes_diffusion:></strong></p>
+
+<div class="contenu-principal">
+       <div class="cartouche">
+    </div>
+    <div class="formulaire_abomailman ajax">\r
+        #FORMULAIRE_ABOMAILMAN\r
+    </div>
+</div>
diff --git a/www/plugins/abomailmans/controleurs/abomailman_descriptif.html b/www/plugins/abomailmans/controleurs/abomailman_descriptif.html
new file mode 100644 (file)
index 0000000..0a8dbaf
--- /dev/null
@@ -0,0 +1,13 @@
+[(#REM)
+
+       Controleur pour le crayon 'abomailman_descriptif' , uniquement html
+       
+       Permet de bénéficier du plugin multilang
+
+]
+#CACHE{0}
+<BOUCLE_a(ABOMAILMANS){id_abomailman}>
+<textarea class="crayon-active multilang" name="#ENV{name_descriptif}"
+ style="width:#ENV{largeur}px; height:#ENV{hauteur}px;#ENV{style}">
+[(#DESCRIPTIF**|entites_html)]</textarea>
+</BOUCLE_a>
diff --git a/www/plugins/abomailmans/controleurs/abomailman_titre.html b/www/plugins/abomailmans/controleurs/abomailman_titre.html
new file mode 100644 (file)
index 0000000..037d064
--- /dev/null
@@ -0,0 +1,13 @@
+[(#REM)
+
+       Controleur pour le crayon 'abomailman_titre', uniquement html
+
+       Permet de bénéficier du plugin multilang
+       
+]
+#CACHE{0}
+
+<BOUCLE_a(ABOMAILMANS){id_abomailman}>
+<input class="crayon-active multilang" name="#ENV{name_titre}"
+ style="width:#ENV{largeur}px;#ENV{style}" value="[(#TITRE**)]" />
+</BOUCLE_a>
diff --git a/www/plugins/abomailmans/formulaires/abomailman.html b/www/plugins/abomailmans/formulaires/abomailman.html
new file mode 100644 (file)
index 0000000..112a8cc
--- /dev/null
@@ -0,0 +1,72 @@
+<div class="formulaire_spip formulaire_#FORM" id="formulaire_#FORM">
+       [<div class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</div>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       <BOUCLE_editable(CONDITION){si #ENV{editable}|oui}>
+       <B_listes>
+       #SET{abo_types,#ARRAY}
+       <BOUCLE_types(ABOMAILMANS){id_abomailman?}{desactive=0}{fusion abo_type}>
+       [(#SET{abo_types,[(#GET{abo_types}|push{#ABO_TYPE})]})]
+       </BOUCLE_types>
+       [(#GET{abo_types}|count|>{1}|oui)
+               [(#SET{legende,<:abomailmans:inscription_lettres_legende:>})]
+       ]
+       [(#GET{abo_types}|count|=={1}|oui)
+               [(#GRAND_TOTAL|>{1}|oui)
+                       [(#SET{legende,[(#VAL{abomailmans:legende_inscriptions_}|concat{#GET{abo_types}|table_valeur{0}}|_T)]})]
+               ]
+               [(#GRAND_TOTAL|>{1}|non)
+                       [(#SET{legende,[(#VAL{abomailmans:legende_inscription_}|concat{#GET{abo_types}|table_valeur{0}}|_T)]})]
+               ]
+       ]
+       <form method='post' action='#ENV{action}' enctype='multipart/form-data' id='abomailmansListes'>
+               <div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <fieldset>
+                       <legend>#GET{legende}</legend>
+                               <ul>
+                                       <li class="editer abomailman_nom[ (#ENV**{erreurs}|table_valeur{nom}|oui)erreur]">
+                                               <label for="nom"><:abomailmans:nom:></label>
+                                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{nom})</span>]
+                                               <input name="nom" id="nom" type="text" class="text" value="#ENV{nom}" />
+                                       </li>
+                                       <li class="editer obligatoire abomailman_email[ (#ENV**{erreurs}|table_valeur{email}|oui)erreur]">
+                                               <label for="email_listes"><:abomailmans:email_abonnement:></label>
+                                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{email})</span>]
+                                               <input name="email" id="email_listes" type="text" class="text" value="#ENV{email}" />
+                                       </li>
+                                       
+                                       <li class="editer abomailman_listes[ (#ENV**{erreurs}|table_valeur{listes}|oui)erreur]">
+                                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{listes})</span>]
+                                               <ul>
+                                                       <li class="editer editer_listes">
+                                                       <BOUCLE_listes(ABOMAILMANS){id_abomailman ?}{desactive=0}{par num titre,titre}>
+                                                       <div class="choix">
+                                                               [<p class="explication #EDIT{descriptif}">
+                                                               (#DESCRIPTIF|PtoBR)
+                                                               </p>]
+                                                               <input name="listes[]" type="checkbox" id="liste_#ID_ABOMAILMAN" value="#ID_ABOMAILMAN"[(#GRAND_TOTAL|=={1}|oui) checked="checked"] />
+                                                               <label for="liste_#ID_ABOMAILMAN" class="#EDIT{titre}} #LANG" lang="#LANG"[ title="(#LANG|traduire_nom_langue)"]>#TITRE</label>
+                                                       </div>
+                                                       </BOUCLE_listes>
+                                                       </li>
+                                               </ul>
+                                       </li>
+                                               
+                               </ul>
+                               [(#REM) Piege a robots spammeurs, du moins on essaie]
+                               <p style="display:none;">
+                                       <label for="nobot_abomailman"><:antispam_champ_vide:></label>
+                                       <input type="text" class="text" name="nobot" id="nobot_abomailman" value="#ENV{nobot}" size="10" />
+                               </p>
+                               <p class="boutons">
+                       <input name="abonnement" type="submit" value="<:abomailmans:btn_abonnement:>" class="submit" />
+                                       <input name="desabonnement" type="submit" value="<:abomailmans:btn_desabonnement:>" class="submit" />
+                </p>
+               </fieldset>
+               </div>
+       </form>
+       </B_listes>
+       </BOUCLE_editable>
+</div>
diff --git a/www/plugins/abomailmans/formulaires/abomailman.php b/www/plugins/abomailmans/formulaires/abomailman.php
new file mode 100644 (file)
index 0000000..9b20930
--- /dev/null
@@ -0,0 +1,151 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('base/abstract_sql');
+
+// chargement des valeurs par defaut des champs du formulaire
+//une seule liste = [(#FORMULAIRE_ABOMAILMAN{1})]
+function formulaires_abomailman_charger_dist($id_abomailman = ""){
+       global $visiteur_session;
+
+       //initialise les variables d'environnement pas défaut
+       $valeurs = array();
+
+       // Si le visiteur est logue au site on utilise ses informations de connexion par défaut
+       $valeurs['email'] = _request('email') ? _request('email') : $visiteur_session['email'];
+       $valeurs['nom'] = _request('nom') ? _request('nom') : $visiteur_session['nom'];
+
+       //si id_abomailman est renseigne, on envoie qu'une liste
+       if(intval($id_abomailman)){
+               $valeurs['id_abomailman'] = $id_abomailman;
+               $ok=sql_getfetsel('id_abomailman','spip_abomailmans','id_abomailman ='.intval($id_abomailman).' AND desactive = 0');
+       }
+       else {
+               $valeurs['listes'] = _request('listes');
+               // on verifie s'il existe des listes disponibles
+               $ok=sql_count(sql_select('id_abomailman','spip_abomailmans'));
+       }
+       $valeurs['nobot'] = _request('nobot');
+       if ($ok)
+       return $valeurs;
+}
+
+
+function formulaires_abomailman_verifier_dist($id_abomailman = ""){
+
+       //initialise le tableau des erreurs
+       $erreurs = array();
+
+       // recuperation des valeurs du formulaire
+       $nom = _request('nom');
+       $email = _request('email');
+       $listes = _request('listes', true);
+       $abonnement = _request('abonnement');
+       $desabonnement = _request('desabonnement');
+
+       // Faire une fonction de verif sur le mail pour validite
+
+       if($email == ''){
+               $erreurs['email'] = _T("abomailmans:email_oublie");
+       }
+       else{
+               include_spip('inc/filtres'); # pour email_valide()
+               if (!email_valide($email)){
+                       $erreurs['email'] = _T("form_email_non_valide");
+               }
+               else{
+                       spip_log("Email = $email;","abomailmans");
+                       //TODO
+                       // stocker l'email dans un fichier ou la session, histoire de ne pas se presenter 2 fois
+               }
+       }
+
+       if(empty($listes)){
+               $erreurs['listes'] = _T("abomailmans:choisir_liste");
+       }
+
+    //message d'erreur generalise
+    if (count($erreurs)) {
+        $erreurs['message_erreur'] .= _T('abomailmans:verifier_formulaire');
+    }
+
+    return $erreurs; // si c'est vide, traiter sera appele, sinon le formulaire sera ressoumis
+}
+
+function formulaires_abomailman_traiter_dist($id_abomailman = ""){
+       // Pour l'envoi de l'email
+       include_spip('inc/abomailmans');
+
+       // Antispam basique :
+       // si l'input invisible a ete renseigne, ca ne peut etre qu'un bot
+       if (strlen(_request('nobot'))){
+               return array('message_erreur'=>_T('abomailmans:erreur_nobot'));
+       }
+
+       $nom = _request('nom');
+       $email = _request('email');
+       $listes = _request('listes', true);
+       $abonnement = _request('abonnement');
+       $desabonnement = _request('desabonnement');
+
+       $message = null;
+
+       $message_listes = "<ul>";
+
+       $nb_listes = 0;
+       foreach($listes as $id_abomailman) {
+               $nb_listes++;
+
+               //on initialise l'envoi
+               // on traite chaque liste via une fonction reutilisable ailleurs
+               $traiter=abomailman_traiter_abonnement($id_abomailman,$abonnement);
+               $titre = $traiter[0];
+               $proprio_email=$traiter[1];
+               $liste_email=$traiter[2];
+               $sujet=$traiter[3];
+               $body= array( 
+                       'texte' => $traiter[4], 
+                       'nom_envoyeur' => $nom 
+               ); 
+               $headers=$traiter[5];
+
+               // si on veut ajouter un mail de notification ou de test
+               /*
+               $liste_email = array(
+                       $liste_email,"verif@exemple.com"
+               );
+               */
+               if (abomailman_mail($nom, $email, $proprio_email,$liste_email, $sujet, $body,'',$headers)){
+                       $message_listes  .= "<li><strong>$titre</strong></li>";
+               }else{
+                       $message_listes .= "<li><strong>". _T('pass_erreur_probleme_technique')."</strong></li>";
+                       $probleme=true;
+               }
+       }
+
+       $message_listes .= "</ul><br class='nettoyeur' />";
+
+       if($abonnement){
+               if($nb_listes>1){
+                       $message .= _T("abomailmans:message_confirmation_a");
+               }else{
+                       $message .= _T("abomailmans:message_confirmation_unique_a");
+               }
+       } else{
+               if($nb_listes>1){
+                       $message .= _T("abomailmans:message_confirmation_d");
+               }else{
+                       $message .= _T("abomailmans:message_confirmation_unique_d");
+               }
+       }
+
+       $message .= $message_listes;
+       $message .= "<p>" . _T("abomailmans:message_confirm_suite") . "</p>";
+
+       if ($probleme==false)
+               return $message;
+       else
+               return $message_listes;
+}
+?>
diff --git a/www/plugins/abomailmans/formulaires/abomailman_envoi_liste.html b/www/plugins/abomailmans/formulaires/abomailman_envoi_liste.html
new file mode 100644 (file)
index 0000000..1860427
--- /dev/null
@@ -0,0 +1,72 @@
+<div class="formulaire_spip formulaire_abomailman_envoi_liste ajax" id="formulaire_abomailman_envoi_liste">\r
+[(#REM) pour IE qui sinon se perd dans l'ajax !, ne pas retirer]<br class='bugajaxie' />\r
+\r
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+       [(#ENV{editable})\r
+       [(#REM)\r
+               Bloc de previsualisation\r
+       \r
+               Si on valide la previsu, on n'envoie pas en ajax \r
+       \r
+       ][<form action="#ENV{action}#formulaire_abomailman_envoi_liste" method="post" class="noajax">\r
+               <div>\r
+               [(#ACTION_FORMULAIRE{#ENV{action}})]\r
+               <input type="hidden" name="template" value="#ENV*{template}" />\r
+               <input type="hidden" name="sujet" value="#ENV*{sujet}" />\r
+               <input type="hidden" name="message" value="#ENV*{message}" />\r
+               <input type="hidden" name="date" value="#ENV*{date}" />\r
+               <input type="hidden" name="id_rubrique" value="#ENV*{id_rubrique}" />\r
+               <input type="hidden" name="id_mot" value="#ENV*{id_mot}" />\r
+               (#ENV*{erreurs}|table_valeur{previsu})\r
+               </div>\r
+       </form>]\r
+       <form action="#ENV{action}#formulaire_abomailman_envoi_liste" method="post" enctype='multipart/form-data'><div>\r
+               [(#ACTION_FORMULAIRE{#ENV{action}})]\r
+               <ul>\r
+                       <li class="choisir_template[ (#ENV**{erreurs}|table_valeur{template}|oui)erreur]">\r
+                               <label for="template"><:abomailmans:template:></label>\r
+                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{template})</span>]\r
+                               <select name="template" id="template">\r
+                                       <INCLURE{fond=prive/listes/abomailman_templates}{id_abomailman}{erreurs}{env}>\r
+                               </select>\r
+                       </li>\r
+                       <li class="editer_date choisir_date[ (#ENV**{erreurs}|table_valeur{date}|oui)erreur]" style="overflow:visible">\r
+                               <label for="date"><:abomailmans:contenu_date:></label>\r
+                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{date})</span>]\r
+                               <input name="date" id="date" class="text date" value="[(#ENV{date}|affdate{'d/m/Y'})]"/>\r
+                               #INCLURE{fond=formulaires/dateur/inc-dateur}\r
+                       </li>\r
+                       <li class="choisir_rubrique[ (#ENV**{erreurs}|table_valeur{id_rubrique}|oui)erreur]">\r
+                               <label for="id_rubrique"><:abomailmans:rubrique:></label>\r
+                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{id_rubrique})</span>]\r
+                               <select name="id_rubrique" id="id_rubrique">\r
+                                       <option value=""></option>\r
+                                       [(#INCLURE{fond=prive/listes/abomailman_rubriques}{id_rubrique_env=#ENV{id_rubrique}})]\r
+                               </select>\r
+                       </li>\r
+                       <li class="choisir_mot[ (#ENV**{erreurs}|table_valeur{id_mot}|oui)erreur]">\r
+                               <label for="id_mot"><:abomailmans:mot:></label>\r
+                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{id_mot})</span>]\r
+                               <select name="id_mot" id="id_mot">\r
+                                       <option value=""></option>\r
+                                       [(#INCLURE{fond=prive/listes/abomailman_mots}{id_mot=#ENV{id_mot}})]\r
+                               </select>\r
+                       </li>\r
+                       <li class="obligatoire choisir_sujet [ (#ENV**{erreurs}|table_valeur{sujet}|oui)erreur]">\r
+                               <label for='sujet'><:abomailmans:sujet:> <:info_obligatoire_02:></label>\r
+                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{sujet})</span>]\r
+                               <input type='text' name='sujet' id='sujet' class="text multilang" value="#ENV*{sujet}" size='40' />\r
+                       </li>\r
+                       <li class="choisir_message[ (#ENV**{erreurs}|table_valeur{message}|oui)erreur]">\r
+                               <label for="message"><:abomailmans:message:></label>\r
+                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{message})</span>]\r
+                               <textarea id="message" name="message" class="text porte_plume_partout multilang" rows="5" cols="40">#ENV*{message}</textarea>\r
+                       </li>\r
+               </ul>\r
+               <p class="boutons">\r
+                       <input type='submit' name='previsu_abomailman' value='<:abomailmans:envoi_apercu:>' class='submit' />\r
+               </p>\r
+               </div>\r
+       </form>]\r
+</div>\r
diff --git a/www/plugins/abomailmans/formulaires/abomailman_envoi_liste.php b/www/plugins/abomailmans/formulaires/abomailman_envoi_liste.php
new file mode 100644 (file)
index 0000000..9960860
--- /dev/null
@@ -0,0 +1,130 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+include_spip('inc/abomailmans');\r
+include_spip('inc/distant');\r
+\r
+// chargement des valeurs par defaut des champs du formulaire\r
+function formulaires_abomailman_envoi_liste_charger_dist(){\r
+       //initialise les variables d'environnement pas défaut\r
+       $valeurs = array(); \r
+       if (autoriser('modifier','abomailman')) {\r
+         $valeurs['editable']=true;\r
+       } else return $valeurs['editable']=false;\r
+\r
+       //$valeurs['id_abomailman'] = _request('id_abomailman');\r
+       $valeurs['sujet'] = _request('sujet');\r
+       $valeurs['template'] = _request('template');\r
+       $valeurs['message'] = _request('message');\r
+       $valeurs['date'] = _request('date');\r
+       $valeurs['id_rubrique'] = _request('id_rubrique');\r
+       $valeurs['id_mot'] = _request('id_mot');\r
+\r
+       return $valeurs;\r
+}\r
+\r
+function formulaires_abomailman_envoi_liste_verifier_dist(){\r
+       \r
+       //initialise le tableau des erreurs\r
+       $erreurs = array();\r
+       \r
+       //$valeurs['id_abomailman'] = _request('id_abomailman');\r
+       $valeurs['sujet'] = _request('sujet');\r
+       $valeurs['template'] = _request('template');\r
+       $valeurs['message'] = _request('message');\r
+       $valeurs['id_rubrique'] = _request('id_rubrique');\r
+       $valeurs['id_mot'] = _request('id_mot');\r
+\r
+       if ($date = recup_date(_request('date'))) {     //On met la date saisie au format MySql AAAA-MM-JJ                      \r
+               $valeurs['date'] = date("Y-m-d",mktime($date[3],$date[4],$date[5],$date[1],$date[2],$date[0]));\r
+       } else { // Devrait pas arriver mais bon\r
+               $valeurs['date'] = date("Y-m-d");\r
+       }\r
+       // On reinjecte dans le bon format\r
+       set_request('date', $valeurs['date']);\r
+       \r
+   if(!$valeurs['sujet']){ \r
+               $erreurs['sujet'] = _T('abomailmans:sujet_obligatoire');  \r
+   }\r
+   \r
+   if (count($erreurs)) {\r
+       refuser_traiter_formulaire_ajax();\r
+      $erreurs['message_erreur'] .= _T('abomailmans:verifier_formulaire');\r
+   }\r
\r
+       if (!count($erreurs) AND !_request('confirmer_previsu_abomailman')){\r
+               $previsu = abomailmain_inclure_previsu($valeurs);\r
+               $erreurs['previsu'] = $previsu;\r
+       }\r
\r
+       return $erreurs; // si c'est vide, traiter sera appele, sinon le formulaire sera resoumis\r
+}\r
+\r
+function abomailmain_inclure_previsu($datas){\r
+       $datas['bouton'] = _T('abomailmans:envoi_confirmer');\r
+       $datas['template_html'] = recuperer_fond('abomailman_template',$datas);\r
+       $datas['envoi_txt'] = "oui";\r
+       $datas['template_txt'] = recuperer_fond('abomailman_template',$datas);\r
+       return recuperer_fond('formulaires/inc-previsu_mail',$datas);\r
+}\r
+\r
+function formulaires_abomailman_envoi_liste_traiter_dist(){\r
+   refuser_traiter_formulaire_ajax();\r
+       \r
+       $query = array();\r
+       $nom_site = lire_meta("nom_site");\r
+       $email_webmaster = lire_meta("email_webmaster");\r
+       $charset = lire_meta('charset');\r
+       $email_receipt = _request('email_liste');\r
+       $sujet = _request('sujet');\r
+    \r
+   // Recuperation des donnees\r
+       //$query['id_abomailman'] = _request('id_abomailman'); \r
+       $query['template'] = _request('template');\r
+       $query['sujet'] = _request('sujet');\r
+       $query['message'] = _request('message');\r
+       $query['id_rubrique'] = _request('id_rubrique');\r
+       $query['id_mot'] = _request('id_mot');\r
+\r
+       if ($date = recup_date(_request('date'))) {     //On met la date saisie au format MySql AAAA-MM-JJ                      \r
+               $query['date'] = date("Y-m-d",mktime($date[3],$date[4],$date[5],$date[1],$date[2],$date[0]));\r
+       } else { // Devrait pas arriver mais bon\r
+               $query['date'] = date("Y-m-d");\r
+       }\r
+\r
+       $fond = recuperer_fond('abomailman_template',$query); \r
+       $body = array(\r
+               'html'=>$fond,\r
+       );\r
+       /* Format Texte */\r
+       $query['envoi_txt'] = "oui";\r
+       $body['texte'] = recuperer_fond('abomailman_template',$query);\r
+       \r
+       if (strlen($fond) > 10) {               \r
+               // email denvoi depuis config facteur\r
+               if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'\r
+                         AND $GLOBALS['meta']['facteur_adresse_envoi_email'])\r
+                       $from_email = $GLOBALS['meta']['facteur_adresse_envoi_email'];\r
+               else\r
+                       $from_email = $email_webmaster;\r
+               // nom denvoi depuis config facteur\r
+               if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'\r
+                         AND $GLOBALS['meta']['facteur_adresse_envoi_nom'])\r
+                       $from_nom = $GLOBALS['meta']['facteur_adresse_envoi_nom'];\r
+               else\r
+                       $from_nom = $nom_site;\r
+                               \r
+               if (abomailman_mail($from_nom, $from_email, "", $email_receipt, $sujet,$body, true, $charset)) {\r
+               $message = _T('abomailmans:email_envoye',array('liste'=>$email_receipt));\r
+               } else {\r
+                       $message = _T('pass_erreur_probleme_technique');\r
+               }\r
+       } else {\r
+               $message = _T('abomailmans:contenu_insuffisant');\r
+       }\r
+\r
+   return array('message_ok'=>$message);\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/abomailmans/formulaires/abomailman_mini_une_liste.html b/www/plugins/abomailmans/formulaires/abomailman_mini_une_liste.html
new file mode 100644 (file)
index 0000000..13bd990
--- /dev/null
@@ -0,0 +1,27 @@
+#CACHE{0}\r
+<div class="formulaire_spip formulaire_#FORM" id="formulaire_#FORM[_(#ENV{id_abomailman})]">\r
+\r
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+\r
+   [(#ENV*{editable}|oui)\r
+      <form method='post' action='#ENV{action}'>\r
+         <div class="abonnement">\r
+            #ACTION_FORMULAIRE{#ENV{action}}\r
+            <ul>\r
+               #SET{erreurs,#ENV**{erreurs}|table_valeur{la_demo}}\r
+               <li class="editer_email obligatoire[ (#GET{erreurs}|oui)erreur]">\r
+                  [<span class='erreur_message'>(#GET{erreurs})</span>]\r
+                  <input name="email" id="email" type="text" value="<:abomailmans:votre_email:>" onclick="this.value=''" />\r
+               </li>\r
+            </ul>\r
+            [(#REM) Piege a robots spammeurs, du moins on essaie]\r
+                       <p style="display:none;">\r
+                               <label for="nobot_abomailman"><:antispam_champ_vide:></label>\r
+                               <input type="text" class="text" name="nobot" id="nobot_abomailman" value="#ENV{nobot}" size="10" />\r
+                       </p>\r
+            <p class="boutons"><input type="submit" class="submit" value="<:bouton_valider:>" /></p>\r
+         </div>\r
+      </form>\r
+   ]\r
+</div>\r
diff --git a/www/plugins/abomailmans/formulaires/abomailman_mini_une_liste.php b/www/plugins/abomailmans/formulaires/abomailman_mini_une_liste.php
new file mode 100644 (file)
index 0000000..747d423
--- /dev/null
@@ -0,0 +1,94 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+include_spip('base/abstract_sql');\r
+\r
+// chargement des valeurs par defaut des champs du formulaire\r
+function formulaires_abomailman_mini_une_liste_charger_dist($id_abomailman = ""){\r
+\r
+       //initialise les variables d'environnement pas defaut\r
+       $valeurs = array('email');\r
+\r
+       // On verifie que la liste est bien accessible\r
+       if (! sql_getfetsel('id_abomailman','spip_abomailmans','id_abomailman ='.intval($id_abomailman).' AND desactive = 0')) {\r
+               spip_log("Le numero de liste n'est pas valable : $id_abomailman","abomailmans");\r
+               $valeurs['message_erreur'] = _T("abomailmans:liste_non_existante");\r
+       }\r
+       return $valeurs;\r
+}\r
+\r
+\r
+function formulaires_abomailman_mini_une_liste_verifier_dist($id_abomailman = ""){\r
+\r
+       //initialise le tableau des erreurs\r
+       $erreurs = array();\r
+\r
+       // Faire une fonction de verif sur le mail pour validite\r
+       $email = _request('email');\r
+       \r
+       if($email == ''){\r
+               $erreurs['erreur_email'] = _T("abomailmans:email_oublie");\r
+               spip_log("Aucun email n'est insere","abomailmans");\r
+       }\r
+       else{\r
+               include_spip('inc/filtres'); # pour email_valide()\r
+               if (!email_valide($email)){\r
+                       $erreurs['erreur_email'] = _T("abomailmans:email_valide");\r
+                       spip_log("Email non valide $email","abomailmans");\r
+               }\r
+               else{\r
+                       spip_log("Email = $email;","abomailmans");\r
+               }\r
+       }\r
+\r
+   //message d'erreur\r
+   if (count($erreurs)) {\r
+      $erreurs['message_erreur'] .= _T('abomailmans:verifier_formulaire');\r
+   }\r
+\r
+   return $erreurs; // si c'est vide, traiter sera appele, sinon le formulaire sera resoumis\r
+}\r
+\r
+function formulaires_abomailman_mini_une_liste_traiter_dist($id_abomailman = ""){\r
+       include_spip('inc/abomailmans');\r
+       \r
+       $nom = _request('nom');\r
+       $email = _request('email');\r
+\r
+       // Antispam basique :\r
+       // si l'input invisible a ete renseigne, ca ne peut etre qu'un bot\r
+       if (strlen(_request('nobot'))){\r
+               return array('message_erreur'=>_T('abomailmans:erreur_nobot'));\r
+       }\r
+       \r
+       $message = null;\r
+\r
+   // on initialise l'envoi\r
+       // on traite chaque liste via une fonction reutilisable ailleurs\r
+       // on passe abonnement a true d'office\r
+       $traiter=abomailman_traiter_abonnement($id_abomailman,true);\r
+       $titre = $traiter[0];\r
+       $proprio_email=$traiter[1];\r
+       $liste_email=$traiter[2];\r
+       $sujet=$traiter[3];\r
+       $body="$nom - $email ".$traiter[4];\r
+       $headers=$traiter[5];\r
+       \r
+       if (abomailman_mail($nom, $email, $proprio_email,$liste_email, $sujet, $body,$headers)){\r
+               $message_listes  .= "<p><strong>$titre</strong><p>";\r
+       }else{\r
+               $message_listes .= "<p><strong>". _T('pass_erreur_probleme_technique')."</strong></p>";\r
+               $probleme=true;\r
+       } \r
+               \r
+       $message .= $body."". _T("abomailmans:message_confirmation_unique_a");\r
+       $message .= $message_listes;\r
+       $message .= "<p>" . _T("abomailmans:message_confirm_suite") . "</p>";\r
+\r
+       if ($probleme==false)\r
+               return $message;\r
+       else\r
+               return $message_listes;\r
+}\r
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/formulaires/editer_abomailman.html b/www/plugins/abomailmans/formulaires/editer_abomailman.html
new file mode 100644 (file)
index 0000000..7c74956
--- /dev/null
@@ -0,0 +1,136 @@
+<div class="formulaire_spip formulaire_editer formulaire_abomailman_creation[_(#ENV{id_abomailman})]">\r
+       <!-- <br class='bugajaxie' /> -->\r
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+       [(#ENV{editable})\r
+       <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div>\r
+               #ACTION_FORMULAIRE{#ENV{action}}\r
+               <ul>\r
+                       <li class="editer editer_titre obligatoire[ (#ENV**{erreurs}|table_valeur{titre}|oui)erreur] editer_type_input">\r
+                               <label for="titre" class="obligatoire"><:texte_titre_obligatoire:></label>\r
+                               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{titre})</span>]\r
+                               <input type="text" id="titre" name="titre" value="[(#ENV**{titre})]" class="text multilang" size="50" />\r
+                       </li>\r
+                       <li class='editer editer_descriptif[ (#ENV**{erreurs}|table_valeur{descriptif}|oui)erreur] editer_type_textarea'>\r
+                               <label for='descriptif'><:abomailmans:texte_descriptif:></label>[\r
+                               <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{descriptif})</span>\r
+                               ]<textarea name='descriptif' id='descriptif' class='text multilang porte_plume_partout' cols='40' rows='2'>[(#ENV**{descriptif})]</textarea>\r
+                       </li>\r
+                       <li class='editer editer_abo_type[ (#ENV**{erreurs}|table_valeur{abo_type}|oui)erreur]'>\r
+                               <label for="desactive_active"><:abomailmans:label_type_abo:></label>\r
+                               <div class="choix">\r
+                                       <input type="radio" value="news" id="abo_type_news" name="abo_type"[(#ENV{abo_type, news}|=={news}|oui)checked="checked"] />\r
+                                       <label for="abo_type_news"><:abomailmans:label_type_news:></label>\r
+                               </div>\r
+                               <div class="choix">\r
+                                       <input type="radio" value="ml" id="abo_type_ml" name="abo_type"[(#ENV{abo_type, news}|=={ml}|oui)checked="checked"] />\r
+                                       <label for="abo_type_ml"><:abomailmans:label_type_ml:></label>\r
+                               </div>\r
+                       </li>\r
+                       <li class="fieldset">\r
+                               <fieldset>\r
+                                       <h3 class="legend"><:abomailmans:emails_a_renseigner:></h3>\r
+               <ul>\r
+                  <li class="editer obligatoire editer_email[ (#ENV**{erreurs}|table_valeur{email}|oui)erreur]">\r
+                     <label for="email" class="obligatoire"><:abomailmans:destinataire:></label>\r
+                     <p class="explication"><:abomailmans:emailliste_abomailman:></p>\r
+                     [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{email})</span>]\r
+                     <input type="text"  id="email" name="email" value="[(#ENV**{email})]" size="50" class="text" />\r
+                  </li>\r
+                  <li class="editer editer_email_subscribe[ (#ENV**{erreurs}|table_valeur{email_subscribe}|oui)erreur]">\r
+                     <label for="email_subscribe"><:abomailmans:emailliste_subscribe:></label>\r
+                     <p class="explication"><:abomailmans:explication_email_subscribe:></p>\r
+                     [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{email_subscribe})</span>]\r
+                     <input type="text"  id="email_subscribe" name="email_subscribe" value="[(#ENV**{email_subscribe})]" size="50" class="text" />\r
+                  </li>\r
+                  <li class="editer editer_email_unsubscribe[ (#ENV**{erreurs}|table_valeur{email_unsubscribe}|oui)erreur]">\r
+                     <label for="email_unsubscribe"><:abomailmans:emailliste_unsubscribe:></label>\r
+                     <p class="explication"><:abomailmans:explication_email_unsubscribe:></p>\r
+                     [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{email_unsubscribe})</span>]\r
+                     <input type="text"  id="email_unsubscribe" name="email_unsubscribe" value="[(#ENV**{email_unsubscribe})]" size="50" class="text" />\r
+                  </li>\r
+                  <li class="editer editer_email_sympa[ (#ENV**{erreurs}|table_valeur{email_sympa}|oui)erreur]">\r
+                     <label for="email_sympa"><:abomailmans:emailliste_abosympa:></label>\r
+                     <p class="explication"><:abomailmans:explication_email_sympa:></p>\r
+                     [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{email_sympa})</span>]\r
+                     <input type="text"  id="email_sympa" name="email_sympa" value="[(#ENV**{email_sympa})]" size="50" class="text" />\r
+                  </li>\r
+                  [<li class="editer editer_langue[ (#ENV**{erreurs}|table_valeur{langue}|oui)erreur]">\r
+                     <label for="langue"><:abomailmans:langue_liste:></label>\r
+                     [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{langue})</span>]\r
+                     <select name="langue" id="langue">\r
+                        <option value=""><:abomailmans:aucune_langue:></option>\r
+                        (#VAL{changer_lang}|liste_options_langues{#ENV*{langue}})\r
+                     </select>\r
+                  </li>]\r
+               </ul>\r
+                       </fieldset>\r
+                       </li>\r
+                       <li class="fieldset">\r
+                               <fieldset>\r
+                                       <h3 class="legend"><:abomailmans:envoi_regulier:></h3>\r
+                                       <ul>\r
+                  <li class="editer editer_periodicite">\r
+                     <label for='periodicite'><:abomailmans:envoi_regulier:></label>\r
+                     <p class="explication"><:abomailmans:envoi_regulier_info:></p>\r
+                     <div class='choix'>\r
+                        <label for="periodicite"><:abomailmans:envoi_regulier_tous_les:></label>\r
+                        <input type="text" size="4" value="[(#ENV{periodicite})]" id="periodicite" name="periodicite" />\r
+                        <label for="periodicite"><:abomailmans:periodicite:></label>\r
+                     </div>\r
+                  </li>\r
+                  <li class="editer choisir_template[ (#ENV**{erreurs}|table_valeur{template}|oui)erreur]">\r
+                     <label for="template"><:abomailmans:template_defaut:></label>\r
+                     <p class="explication"><:abomailmans:template_defaut_info:></p>\r
+                     [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{template})</span>]\r
+                     <select name="template" id="template">\r
+                        <INCLURE{fond=prive/listes/abomailman_templates}{id_abomailman}{erreurs}>\r
+                     </select>\r
+                  </li>\r
+                  <li class="editer editer_envoi_liste_parametres">\r
+                     <label for="envoi_liste_parametres"><:abomailmans:envoi_parametres:></label>\r
+                     <p class="explication">\r
+                        <:abomailmans:envoi_liste_parametres:>\r
+                        [(#ENV{modele_defaut}|oui)\r
+                           <br />\r
+                           [(#SET{date_ref,[(#DATE|moins30|affdate{annee})-][(#DATE|moins30|affdate{mois})]})]\r
+                           <:abomailmans:voir_modele_depuis:>[ (#DATE|moins30|affdate{nom_mois})][ (#DATE|moins30|affdate{annee})]&nbsp;: <a href="[(#URL_PAGE{abomailman_template}|parametre_url{template,[(#ENV{template})]}|parametre_url{date,#GET{date_ref}})][(#ENV**{envoi_liste_parametres})]"><:abomailmans:previsu_html:></a> | <a href="[(#URL_PAGE{abomailman_template}|parametre_url{template,[(#ENV{template})]}|parametre_url{date,#GET{date_ref}}|parametre_url{envoi_txt,oui})][(#ENV**{envoi_liste_parametres})]"><:abomailmans:previsu_txt:></a>.\r
+                        ]\r
+                     </p>\r
+                     <input type="text" id="envoi_liste_parametres" name="envoi_liste_parametres" value="[(#ENV**{envoi_liste_parametres})]" size="50"  class="text" />\r
+                  </li>\r
+               </ul>\r
+            </fieldset>\r
+         </li>\r
+         <li class="fieldset">\r
+            <fieldset>\r
+               <h3 class="legend"><:abomailmans:label_etat_liste:></h3>\r
+               <ul>\r
+                  <li class="editer editer_desactive obligatoire">\r
+                     <label for="desactive_active"><:abomailmans:activation:></label>\r
+                     <div class="choix">\r
+                        <input type="radio" value="0" id="desactive_active" name="desactive"[(#ENV{desactive, 0}|=={0}|oui) checked="checked"] />\r
+                        <label for="desactive_active"><:abomailmans:active:></label>\r
+                     </div>\r
+                     <div class="choix">\r
+                        <input type="radio" value="1" id="desactive_inactive" name="desactive"[(#ENV{desactive, 0}|=={1}|oui) checked="checked"] />\r
+                        <label for="desactive_inactive"><:abomailmans:desactive:></label>\r
+                     </div>\r
+                  </li>\r
+                  [(#ENV{id_abomailman}|intval|oui)\r
+                  <li class="editer editer_desactive_supprime">\r
+                     <label for="desactive_supprime"><:abomailmans:supprimer:></label>\r
+                     <div class="choix">\r
+                        <input type="checkbox" value="2" id="desactive_supprime" name="desactive"[(#ENV{desactive, 0}|=={2}|oui) checked="checked"] />\r
+                        <label for="desactive_supprime"><:abomailmans:suppression_definitive:></label>\r
+                     </div>\r
+                  </li>]\r
+               </ul>\r
+            </fieldset>\r
+         </li>\r
+      </ul>\r
+      <p class="boutons">\r
+         <input type="submit" class="submit" name="valider" value="[(#ENV{id_abomailman}|?{<:bouton_enregistrer:>,<:bouton_ajouter:>})]" />\r
+      </p>\r
+       </div></form>]\r
+</div>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/formulaires/editer_abomailman.php b/www/plugins/abomailmans/formulaires/editer_abomailman.php
new file mode 100644 (file)
index 0000000..5d746f8
--- /dev/null
@@ -0,0 +1,114 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+include_spip('inc/autoriser');\r
+include_spip('inc/actions');\r
+include_spip('inc/editer');\r
+\r
+// chargement des valeurs par defaut des champs du formulaire\r
+function formulaires_editer_abomailman_charger_dist($id_abomailman='new',$retour='', $config_fonc='', $row=array(), $hidden=''){\r
+       $valeurs = array();\r
+\r
+       //initialise les variables d'environnement pas défaut\r
+       if (!autoriser('creer', 'abomailman', 'oui')) {\r
+               $editable = false;\r
+       }else{\r
+               $valeurs = formulaires_editer_objet_charger('abomailman',$id_abomailman,0,0,$retour,$config_fonc,$row,$hidden);\r
+               $editable = true;\r
+       }\r
+\r
+       if(!$valeurs['langue']){\r
+               $valeurs['langue'] = lang_select();\r
+       }\r
+       unset($valeurs['lang']);\r
+\r
+       $recuptemplate = explode('&',_request('modele_defaut'));\r
+       $valeurs['template'] = $recuptemplate[0];\r
+       $valeurs['envoi_liste_parametres']=recup_param(_request('modele_defaut'));\r
+       $valeurs['editable'] = $editable;\r
+       return $valeurs;\r
+}\r
+\r
+/**\r
+ * Identifier le formulaire en faisant abstraction des parametres qui\r
+ * ne representent pas l'objet edite\r
+ */\r
+function formulaires_editer_abomailman_identifier_dist($id_abomailman='new', $retour='', $associer_objet='', $config_fonc='auteurs_edit_config', $row=array(), $hidden=''){\r
+       return serialize(array(intval($id_abomailman),$associer_objet));\r
+}\r
+\r
+function formulaires_editer_abomailman_verifier_dist($id_abomailman='new',$retour='', $config_fonc='', $row=array(), $hidden=''){\r
+\r
+       //initialise le tableau des erreurs\r
+       $erreurs = formulaires_editer_objet_verifier('abomailman',$id_abomailman,array('titre','email'));\r
+       spip_log($erreurs,'test');\r
+       // Faire une fonction de verif sur le mail et le titre pour validite\r
+       $desactive = _request('desactive');\r
+\r
+       // Si on fait une suppression, on ne vérifie pas le reste\r
+       if($desactive != '2'){\r
+               if (count($erreurs)<1){\r
+                       include_spip('inc/filtres'); # pour email_valide()\r
+                       if (!email_valide(_request('email'))){\r
+                               $erreurs['email'] = _T("abomailmans:email_valide");\r
+                       }\r
+               }\r
+       }\r
+       \r
+    //message d'erreur genéralisé\r
+    if (count($erreurs)>0) {\r
+        $erreurs['message_erreur'] .= _T('abomailmans:verifier_formulaire');\r
+    }\r
+\r
+    return $erreurs; // si c'est vide, traiter sera appele, sinon le formulaire sera resoumis\r
+}\r
+\r
+function formulaires_editer_abomailman_traiter_dist($id_abomailman='new',$retour='', $config_fonc='', $row=array(), $hidden=''){\r
+       $res = formulaires_editer_objet_traiter('abomailman',$id_abomailman,0,0,$retour,$config_fonc,$row,$hidden);\r
+   \r
+       $message = array();\r
+       $valeurs['envoi_liste_parametres'] = _request('envoi_liste_parametres');\r
+\r
+       $datas = array();\r
+\r
+    // Récupération des données\r
+       $datas['titre'] = _request('titre');\r
+       $datas['descriptif'] = _request('descriptif');\r
+       if(_request('abo_type') && in_array(_request('abo_type'), array('news','ml'))){\r
+               $datas['abo_type'] = _request('abo_type');\r
+       }\r
+       $datas['email'] = _request('email');\r
+       $datas['email_subscribe'] = _request('email_subscribe');\r
+       $datas['email_unsubscribe'] = _request('email_unsubscribe');\r
+       $datas['email_sympa'] = _request('email_sympa');\r
+       $datas['desactive'] = _request('desactive');\r
+       $datas['modele_defaut'] = str_replace('\'','',_request('template'))."".$valeurs['envoi_liste_parametres'];\r
+       $datas['periodicite'] = _request('periodicite');\r
+       $datas['lang'] = _request('langue');\r
+\r
+       // on récupère les données de la liste\r
+       if(intval($id_abomailman)){\r
+               if($datas['desactive'] == '2'){\r
+                       sql_delete("spip_abomailmans","id_abomailman = $id_abomailman");\r
+                       $message['message_ok'] = _T('abomailmans:liste_supprimee',array("id"=>$id_abomailman,"titre"=> $datas['titre']));\r
+                       $message['editable'] = false;\r
+               }else{\r
+                       sql_updateq("spip_abomailmans",$datas,"id_abomailman = $id_abomailman");\r
+                       $message['message_ok'] = _T('abomailmans:liste_updatee',array("id"=>$id_abomailman,"titre"=> $datas['titre']));\r
+               }\r
+       }else{\r
+               $message['message_ok'] = _T('abomailmans:liste_creee',array("id"=>$id_abomailman,"titre"=> $datas['titre']));\r
+               $message['editable'] = false;\r
+       }\r
+       \r
+       if (!$retour) {\r
+               $message['redirect'] = parametre_url(parametre_url(self(),'id_abomailman', $res['id_abomailman']),'abomailman','');\r
+       } else {\r
+               // sinon on utilise la redirection donnee.\r
+               $message['redirect'] = parametre_url($retour, 'id_abomailman', $res['id_abomailman']);\r
+       }\r
+   return $message;\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/formulaires/inc-previsu_mail.html b/www/plugins/abomailmans/formulaires/inc-previsu_mail.html
new file mode 100644 (file)
index 0000000..5e570ba
--- /dev/null
@@ -0,0 +1,30 @@
+<ul>\r
+       <li class="fieldset">\r
+               <fieldset class="previsu">\r
+         <h3 class="legend"><:previsualisation:> <:abomailmans:previsu_html:></h3>\r
+         <div class="abo_message">\r
+            #ENV*{template_html}\r
+         </div>\r
+         <h3 class="legend"><:previsualisation:> <:abomailmans:previsu_txt:></h3>\r
+         <div class="abo_message">\r
+            <pre width="80">#ENV*{template_txt, #VAL{abomailmans:pas_template_txt}|_T}</pre>\r
+         </div>\r
+         <h3 class="legend"><:abomailmans:destinataire:></h3>\r
+         <ul>\r
+            <li>\r
+               <label><:abomailmans:envoyer_courier_liste:></label>\r
+               <B_listes>\r
+               <select name="email_liste" id="email_liste" >\r
+               <BOUCLE_listes(ABOMAILMANS){par titre}>\r
+               <option value="#EMAIL">#TITRE -> #EMAIL</option>\r
+               </BOUCLE_listes>\r
+               </select>\r
+               </B_listes>\r
+            </li>\r
+       </ul>\r
+      </fieldset>\r
+       </li>\r
+</ul>\r
+[<p class="boutons">\r
+       <input name="confirmer_previsu_abomailman" type="submit" value="(#ENV{bouton})" />\r
+</p>]
\ No newline at end of file
diff --git a/www/plugins/abomailmans/genie/abomailmans_envois.php b/www/plugins/abomailmans/genie/abomailmans_envois.php
new file mode 100755 (executable)
index 0000000..0a5da56
--- /dev/null
@@ -0,0 +1,133 @@
+<?php\r
+/**\r
+ * Plugin Abomailmanss\r
+ * (c) 2009-2011 SPIP\r
+ * Distribue sous licence GPL\r
+ *\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+include_spip('inc/abomailmans');\r
+include_spip('inc/distant');\r
+\r
+/**\r
+ * Les abomailmans de chaque liste peuvent se faire par cron\r
+ * base sur les champs remplis de chaque liste\r
+ * automatique tout les /periodicite/ jours\r
+ * @param unknown_type $time\r
+ */\r
+function genie_abomailmans_envois_dist($time) {\r
+       \r
+       /**\r
+        * Les listes dont la date_envoi < maintenant+periodicite\r
+        * pour tester on peut mettre a MINUTE penser a remettre a DAY !!\r
+        */\r
+       $where = "periodicite!='' AND desactive='0' AND email!=''\r
+               AND date_envoi < DATE_SUB(NOW(), INTERVAL periodicite DAY)"; \r
+       $id_liste = sql_getfetsel("id_abomailman", "spip_abomailmans", $where, '', "date_envoi", "1");\r
+        \r
+       if ($id_liste) {\r
+               spip_log("il faut traiter liste id=$id_liste","abomailmans");\r
+               $res2 = liste_a_jour($id_liste);\r
+       } else $res2 = true;\r
+       \r
+       /**\r
+        * nul, si la tache n'a rien a faire\r
+        * positif, si la tache a ete traitee\r
+        * negatif, si la tache a commence, mais doit se poursuivre. \r
+        * Cela permet d'effectuer des taches par lots (pour eviter des timeout sur les executions des scripts PHP \r
+        * a cause de traitements trop longs).\r
+        * Dans ce cas la, le nombre negatif indique correspond au nombre de secondes d'intervalle \r
+        * pour la prochaine execution.\r
+        */\r
+       return ($res1 OR $res2) ? 0 : $id_liste;\r
+}       \r
+       \r
+       \r
+\r
+function liste_a_jour($id_liste) {\r
+       $envoi_ok=true;\r
+       $t = sql_fetsel("*", "spip_abomailmans", "id_abomailman=$id_liste");\r
+       if(!$t) { \r
+               spip_log("requete null ...","abomailmans");\r
+               return;\r
+       } else spip_log("envoi teste avec cron abomailmans","abomailmans");\r
+               \r
+       $datas = array();\r
+       $nom_site = lire_meta("nom_site");\r
+       $email_webmaster = lire_meta("email_webmaster");\r
+       $charset = lire_meta('charset');\r
+\r
+\r
+       $sujet=$t['titre']; \r
+       $date_envoi=$t['date_envoi']; \r
+       $email_receipt=$t['email'];\r
+       $modele_defaut=$t['modele_defaut'];\r
+       \r
+       $recuptemplate = explode('&',$modele_defaut);\r
+               \r
+       include_spip('abomailmans_fonctions');\r
+       $paramplus = recup_param($modele_defaut); //pour url\r
+       $periodicite=intval($t['periodicite']);\r
+\r
+       /**\r
+        * la page a envoyer doit etre testee a maintenant moins periodicite\r
+        */\r
+       $time = time() - (3600 * 24 * $periodicite);\r
+\r
+       /**\r
+        * construction du query\r
+        */\r
+       parse_str($paramplus,$query);\r
+       $query['id_abomailman'] = $t['id_abomailman'];\r
+       $query['template'] = $recuptemplate[0];\r
+       $query['date'] = date('Y-m-d H:i:s', $time);\r
+\r
+       /**\r
+        * on peut verifier le fond grace à l'url\r
+        */\r
+       $url_genere = generer_url_public('abomailman_template',$query,'&'); \r
+       $fond = recuperer_fond('abomailman_template',$query);\r
+\r
+       $body = array(\r
+               'html'=>$fond,\r
+       ); \r
+       /* Format Texte */\r
+       $query['envoi_txt'] = "oui";\r
+       $body['texte'] = recuperer_fond('abomailman_template',$query);\r
+\r
+       //Si la page renvoie un contenu\r
+       if (strlen($fond) > 10) {\r
+                               \r
+               // email denvoi depuis config facteur\r
+               if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'\r
+                         AND $GLOBALS['meta']['facteur_adresse_envoi_email'])\r
+                       $from_email = $GLOBALS['meta']['facteur_adresse_envoi_email'];\r
+               else\r
+                       $from_email = $email_webmaster;\r
+               // nom denvoi depuis config facteur\r
+               if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'\r
+                         AND $GLOBALS['meta']['facteur_adresse_envoi_nom'])\r
+                       $from_nom = $GLOBALS['meta']['facteur_adresse_envoi_nom'];\r
+               else\r
+                       $from_nom = $nom_site;\r
+                               \r
+               if (abomailman_mail($from_nom, $from_email, "", $email_receipt, $sujet,$body, true, $charset)) {\r
+                       spip_log("envoi ok = $url_genere tous les $periodicite jours sujet =".$sujet,"abomailmans");\r
+               } else {\r
+                       spip_log("!! envoi nok = $url_genere tous les $periodicite jours sujet =".$sujet,"abomailmans."._LOG_ERREUR);\r
+                       $envoi_ok=false;\r
+               }\r
+       }\r
+       else {\r
+               spip_log("maintenant=".date('Y-m-d H:i:s', time())." date demande = ".$query['date']." non envoye =$url_genere : rien de neuf depuis $periodicite jours","abomailmans"); \r
+       }\r
+       \r
+       if($envoi_ok) {\r
+               // Noter que l'envoi est OK meme si envoi echoue faute de contenu, on reessaiera dans /periodicite/ jours\r
+               sql_updateq("spip_abomailmans", array("date_envoi" => date('Y-m-d H:i:s', time())), "id_abomailman=".$t['id_abomailman']);\r
+       }\r
+       return false; # c'est bon\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/inc/abomailmans.php b/www/plugins/abomailmans/inc/abomailmans.php
new file mode 100755 (executable)
index 0000000..e4ba2d6
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+
+/*
+ * Abomailmans
+ * MaZiaR - NetAktiv
+ * tech@netaktiv.com
+ * Printemps 2007 - 2012
+ * Inspire de Spip-Listes
+ * $Id: abomailmans.php 59911 2012-03-29 10:00:37Z root $
+*/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// a utiliser dans le form de son choix ...
+function abomailman_traiter_abonnement($id_liste,$abonnement){
+       $liste_data = sql_fetsel("*","spip_abomailmans","id_abomailman = $id_liste");
+       $sujet=null;
+       $dowhat=null;
+       $titre=$liste_data['titre'];
+       //Si on a les 2 emails
+       if($liste_data['email_subscribe'] AND $liste_data['email_unsubscribe']){
+               spip_log("Liste defini par mails","abomailmans");
+               $liste_email = !empty($abonnement)?$liste_data['email_subscribe']:$liste_data['email_unsubscribe'];
+       }else{
+               //sinon comme avant
+               // 1er cas : c'est une liste MAILMAN ? join et leave etrange  !!!
+               //ne serait-ce pas plutot subscribe et unsubscribe ?
+               if($liste_data['email_sympa'] == '') {
+                       spip_log("Liste -join ou -leave","abomailmans");
+                       $liste_email = explode ("@", $liste_data['email']);
+                       // abonnement ou desabonement : on rajoute -join ou -leave dans l'email de la liste
+                       $dowhat = !empty($abonnement)?"-join@":"-leave@";
+                       $liste_email = $liste_email[0]."$dowhat".$liste_email[1];
+               }
+               // 2eme cas : c'est une liste SYMPA (presence de deux @ à suivre)
+               else {
+                       spip_log("Liste sympa","abomailmans");
+                       $proprio_email = $liste_data['email_sympa'];
+                       $sujet = empty($abonnement)? 'UNSUBSCRIBE ' : 'SUBSCRIBE ';
+                       $sujet .= $liste_data['email'].' ';
+                       $sujet .= empty($desabonnement) ? $nom : '';
+                       $liste_email = $liste_data['titre'];
+               }
+       }
+       $sujet=isset($sujet)?$sujet:$liste_email;
+       $quoifait=!empty($abonnement)?_T("abomailmans:veut_s_abonner"):_T("abomailmans:veut_se_desabonner");
+       $body="$quoifait"."\n ".$titre."(".$liste_data['email'].") \n "._T("abomailmans:envoi_vers")." $liste_email";
+
+
+       return array($titre,$proprio_email,$liste_email, $sujet, $body,$headers);
+}
+
+
+//* Envoi de mail via facteur
+function abomailman_mail($nom, $email, $to_email,$liste_email, $sujet="", $body="", $html="", $headers="") {
+       // si $to_mail est plein, c'est Sympa, s'il est vide c'est Mailman et il faut alors utiliser $liste_email
+       if (!$to_email)
+               $to_email = $liste_email;
+       
+       // Pas beau mais faudrait reprendre le code plus en profondeur
+       // et rajouter une liste de choix du robot en page de config
+       // Modifier le destinataire d’envoi dans le cas ezmlm pour que 
+       // les inscriptions fonctionnent si facteur utilise l’envoi via
+       // la fonction mail() de php. En effet dans ce cas, le header return-path
+       // n’est pas renseigné. Or c’est ce header qui est utilisé par le robot
+       // pour répondre et non le champ from... Il faut modifier le destinataire
+       // comme ceci maliste-subscribe-lemail=ledomaine.tld@monsite.tld
+       if (defined('_ABOMAILMAN_ROBOT_EZMLM') && preg_match("/subscribe/",$to_email)) {
+               $souscripteur = str_replace("@" , "=" , $email ) ;
+               $to_email = str_replace("@" , "-".$souscripteur."@" , $to_email ) ;
+       }
+
+       $envoyer_mail = charger_fonction('envoyer_mail','inc/');
+       if($envoyer_mail($to_email, $sujet, $body, $email, $headers))
+               $retour=true;
+       else
+               $retour=false;
+
+       spip_log("abomailman_mail nom $nom, email $email, to_email $to_email, liste_email $liste_email, sujet $sujet, body $body, html $html, headers $headers, retour envoyer_mail : $retour","abomailmans");
+       return $retour ;
+}
+
+
+?>
diff --git a/www/plugins/abomailmans/lang/abomailmans.xml b/www/plugins/abomailmans/lang/abomailmans.xml
new file mode 100644 (file)
index 0000000..c692a7f
--- /dev/null
@@ -0,0 +1,13 @@
+<traduction module="abomailmans" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/abomailmans/trunk/lang/" reference="fr">
+       <langue code="de" />
+       <langue code="en" url="http://trad.spip.net/tradlang_module/abomailmans?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/abomailmans?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/abomailmans?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/abomailmans/lang/abomailmans_de.php b/www/plugins/abomailmans/lang/abomailmans_de.php
new file mode 100644 (file)
index 0000000..fcebb20
--- /dev/null
@@ -0,0 +1,141 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/abomailmans?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailman' => 'Liste de diffusion ou discussions', # NEW
+       'abomailmans' => 'Listes de diffusion ou discussions', # NEW
+       'abonne' => 'Ich abonniere',
+       'activation' => 'Activation', # NEW
+       'active' => 'Aktiv',
+       'aucune_langue' => 'Keine ANgabn',
+
+       // B
+       'bouton_listes_diffusion' => 'Mailinglisten',
+       'btn_abonnement' => 'Abonnieren',
+       'btn_desabonnement' => 'Abbestellen',
+
+       // C
+       'choisir_liste' => 'Sie müssen eine Liste wählen.',
+       'contenu_date' => 'Inhalt ab diesem Datum', # MODIF
+       'creation_droits_insuffisants' => 'Sie haben kein Recht dazu ...',
+
+       // D
+       'desactive' => 'Abgeschaltet',
+       'destinataire' => 'Destinataire', # NEW
+
+       // E
+       'email' => 'E-Mail',
+       'email_abonnement' => 'Ihre E-Mail Adresse',
+       'email_envoye' => 'Die E-Mail wurde an die Mailingliste verschickt: @liste@.',
+       'email_oublie' => 'Sie haben ihre E-Mail Adresse vergessen',
+       'emailliste_abomailman' => 'E-Mail Adresse der Liste',
+       'emailliste_abosympa' => 'E-Mail Adresse des Sympa-Administrators',
+       'emailliste_subscribe' => 'Subscribe',
+       'emailliste_unsubscribe' => 'Unsubscribe', # MODIF
+       'emails_a_renseigner' => 'Emails à renseigner', # NEW
+       'envoi_apercu' => 'Vorschau',
+       'envoi_confirmer' => 'Bestätigen und absenden',
+       'envoi_liste_parametres' => 'Parameterliste',
+       'envoi_parametres' => 'Paramétres', # NEW
+       'envoi_regulier' => 'Automatics mail',
+       'envoi_regulier_info' => 'Keep empty if you do not want to send automatically',
+       'envoi_regulier_tous_les' => 'Send each',
+       'envoi_vers' => 'send to',
+       'envoyer_courier' => 'Mail senden',
+       'envoyer_courier_liste' => 'Mail an diese Mailingliste senden:',
+       'envoyer_mailmans' => 'Modell und Inhalt auswählen', # MODIF
+       'erreur_email_liste_oublie' => 'Die E-Mail Adresse ist obligatorisch.',
+       'erreur_nobot' => 'Votre inscription n\' a pu être effectué à cause d\'un problème technique', # NEW
+       'explication_email_subscribe' => 'Email for subscribe, something like <code>suffix+subscribe@exemple.org</code>',
+       'explication_email_sympa' => 'Wenn dieses Feld ausgefüllt ist, wird von einer Sympa-Liste ausgegangen,
+                                                       anderenfalls von einer Mailman-Liste.',
+       'explication_email_unsubscribe' => 'Email for unsubscribe',
+
+       // I
+       'icone_ajouter_liste' => 'Neue Liste hinzufügen',
+       'icone_envoyer_mail_liste' => 'Mail aus dem Inhalt dieser Website generieren und an die Buchstaben senden',
+       'icone_modifier_abomailman' => 'Modifier la liste', # NEW
+       'icone_retour_abomailman' => 'Retour à la liste', # NEW
+       'info_abomailman_aucun' => 'Aucune liste', # NEW
+       'info_abomailmans_1' => 'Une liste', # NEW
+       'info_abomailmans_nb' => '@nb@ listes', # NEW
+       'info_sisympa' => '[Obligatorisch bei Sympa-Listen]',
+       'insciption_listes_legende' => 'Mailing-Listen Abonnements', # MODIF
+       'inscription_lettres_legende' => 'Abonnement bei Newslettern<br />und Diskussionslisten',
+
+       // J
+       'je_m_abonne' => 'Markieren um Abonnement zu bestellen oder zu kündigen.',
+
+       // L
+       'label_etat_liste' => 'Status der Liste',
+       'label_type_abo' => 'Type', # NEW
+       'label_type_ml' => 'Liste de discussion', # NEW
+       'label_type_news' => 'Liste de diffusion', # NEW
+       'langue_liste' => 'Sprache der Liste',
+       'legende_inscription_ml' => 'Inscription à la liste de discussion', # NEW
+       'legende_inscription_news' => 'Inscription à la liste de diffusion', # NEW
+       'legende_inscriptions_ml' => 'Inscription aux listes de discussion', # NEW
+       'legende_inscriptions_news' => 'Inscription aux listes de diffusion', # NEW
+       'les_listes_mailmans' => 'Bekannte Mailman-Listen',
+       'lire_article' => 'Artikel lesen',
+       'liste_creee' => 'Die Liste Nummer @id@ (@titre@) wurde angelegt.',
+       'liste_non_existante' => 'Die Liste existiert nich oder wurde entfernt.',
+       'liste_oublie' => 'Sie habe vergessen, eine Liste auszuwählen!',
+       'liste_supprimee' => 'Die Liste Nummer @id@ (@titre@) wurde gelöscht.',
+       'liste_updatee' => 'Die Liste Nummer  @id@ (@titre@) wurde aktualisiert.',
+
+       // M
+       'message' => 'Einleitungstext vor den Inhalten ihrer Website',
+       'message_confirm_suite' => 'Um ihren Auftrag zu bestätigen beantworten sie bitte die Bestätigungsmail, die sie erhalten werden..',
+       'message_confirmation_a' => 'Aboanfragen an folgende Listen wurden gesendet:',
+       'message_confirmation_d' => 'Stornierungsaufträge an folgende Listen wurden gesendet. ',
+       'message_confirmation_unique_a' => 'Eine Aboanfragen an folgende Liste wurden gesendet:',
+       'message_confirmation_unique_d' => 'Stornierungsauftrag an folgende Liste wurden gesendet. ',
+       'mot' => 'Artikel zu diesem Schlagwort auflisten',
+
+       // N
+       'nom' => 'Name und Vorname (freiwillige Angabe)',
+       'nouveau_abomailman' => 'Nouvelle liste de diffusion', # NEW
+
+       // P
+       'pas_template_txt' => 'Il n\'y a pas de version texte pour ce modèle', # NEW
+       'periodicite' => ' days.',
+       'prenom' => 'Vorname',
+       'previsu_html' => 'html', # NEW
+       'previsu_txt' => 'texte', # NEW
+
+       // R
+       'rubrique' => 'Artikel der Rubrik auflisten',
+
+       // S
+       'souhaite_rester' => 'Ich möchte auf dem Laufenden bleiben',
+       'sujet' => 'Thema der Mail',
+       'sujet_obligatoire' => 'Es muss ein Thema angegeben werden.',
+       'suppression_definitive' => 'Suppression définitive !', # NEW
+       'supprimer' => 'Löschen',
+       'sympa_message_confirmation' => 'Eine Bestätigungsmail wurde an folgende Adresse gesendet: ', # MODIF
+
+       // T
+       'template' => 'Modell und Inhalte auswählen',
+       'template_defaut' => 'Default template',
+       'template_defaut_info' => 'Si le fichier modele_choisi.txt.html existe, la newsletter sera envoyée en mode html + texte. Sinon seule la version html sera expédiée.', # NEW
+       'texte_descriptif' => 'Descriptif', # NEW
+       'titre_abomailman' => 'Bezeichnung der Liste',
+       'titre_liste_obligatoire' => 'Die Liste muss eine Bezeichnung erhalten',
+       'toute_liste' => 'ALle Mailinglisten', # MODIF
+
+       // V
+       'verifier_formulaire' => 'Überprüfen sie den Inhalt des Formulars.',
+       'veut_s_abonner' => 'want to subscribe',
+       'veut_se_desabonner' => 'want to unsubscribe',
+       'voir_modele_depuis' => 'Voir un exemple du modéle avec', # NEW
+       'votre_email' => 'Ihre E-Mail'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/abomailmans_en.php b/www/plugins/abomailmans/lang/abomailmans_en.php
new file mode 100755 (executable)
index 0000000..129120f
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/abomailmans?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailman' => 'Newsletter or mailing list',
+       'abomailmans' => 'Mailing lists or newsletters',
+       'abonne' => 'I subscribe',
+       'activation' => 'Activation',
+       'active' => 'Active',
+       'aucune_langue' => 'None specified',
+
+       // B
+       'bouton_listes_diffusion' => 'Mailing lists',
+       'btn_abonnement' => 'Subscribe',
+       'btn_desabonnement' => 'Unsubscribe',
+
+       // C
+       'choisir_liste' => 'You should choose a list.',
+       'contenu_date' => 'Content since this date',
+       'creation_droits_insuffisants' => 'Your rights are insufficients',
+
+       // D
+       'desactive' => 'Disabled',
+       'destinataire' => 'Recipient',
+
+       // E
+       'email' => 'Email address',
+       'email_abonnement' => 'Your email address',
+       'email_envoye' => 'The email has been sent to the list : @liste@.',
+       'email_oublie' => 'You forgot your email address',
+       'emailliste_abomailman' => 'The email address of the list',
+       'emailliste_abosympa' => 'The email address of the Sympa admin',
+       'emailliste_subscribe' => 'Subscribe',
+       'emailliste_unsubscribe' => 'Unsubscribe',
+       'emails_a_renseigner' => 'Email addresses to provide',
+       'envoi_apercu' => 'Previsualization',
+       'envoi_confirmer' => 'Confirm and send',
+       'envoi_liste_parametres' => 'List of parameters [Facultatif]',
+       'envoi_parametres' => 'Settings',
+       'envoi_regulier' => 'Automatics mail',
+       'envoi_regulier_info' => 'Leave empty if you do not want to send automatically',
+       'envoi_regulier_tous_les' => 'Send each',
+       'envoi_vers' => 'send to',
+       'envoyer_courier' => 'Send an email',
+       'envoyer_courier_liste' => 'Send this content to this list :',
+       'envoyer_mailmans' => 'Select the template and its content',
+       'erreur_email_liste_oublie' => 'The email address of the list is mandatory',
+       'erreur_nobot' => 'No registration has been made ​​due to a technical problem',
+       'explication_email_subscribe' => 'Email for subscribe, something like <code>suffix+subscribe@exemple.org</code>',
+       'explication_email_sympa' => 'If this field is filled in, the list is considered as a "Sympa" list, if not, as a "Mailman" list.',
+       'explication_email_unsubscribe' => 'Email for unsubscribe',
+
+       // I
+       'icone_ajouter_liste' => 'Add a new list',
+       'icone_envoyer_mail_liste' => 'Send an e-mail to the lists from the content of this site',
+       'icone_modifier_abomailman' => 'Edit the list',
+       'icone_retour_abomailman' => 'Back to the list',
+       'info_abomailman_aucun' => 'No list',
+       'info_abomailmans_1' => 'A list',
+       'info_abomailmans_nb' => '@nb@ lists',
+       'info_sisympa' => '[Mandatory for a Sympa list]',
+       'insciption_listes_legende' => 'Subscription to the mailing lists',
+       'inscription_lettres_legende' => 'Subscription to the newsletters<br />and mailing lists',
+
+       // J
+       'je_m_abonne' => 'Check to confirm the subscription or unsubscription.',
+
+       // L
+       'label_etat_liste' => 'Status of the list',
+       'label_type_abo' => 'Type',
+       'label_type_ml' => 'Mailing-list',
+       'label_type_news' => 'Newsletter',
+       'langue_liste' => 'Language of the list',
+       'legende_inscription_ml' => 'Subscription to the mailing list',
+       'legende_inscription_news' => 'Subscription to the newsletter',
+       'legende_inscriptions_ml' => 'Subscription to the mailing lists',
+       'legende_inscriptions_news' => 'Subscription to the newsletters',
+       'les_listes_mailmans' => 'The Mailman\'s or Sympa\'s lists filled',
+       'lire_article' => 'Read the article',
+       'liste_creee' => 'The list number @id@ (@titre@) has been created.',
+       'liste_non_existante' => 'The asked list doesn\'t exist or has been deleted',
+       'liste_oublie' => 'You forgot to check a list.',
+       'liste_supprimee' => 'The list number @id@ (@titre@) has been deleted.',
+       'liste_updatee' => 'The list number @id@ (@titre@) has been updated.',
+
+       // M
+       'message' => 'Introduction of your email, before the site\'s content',
+       'message_confirm_suite' => 'To validate your request, please reply to the confirmation email that you will receive.',
+       'message_confirmation_a' => 'A subscription request to the following lists has been sent :',
+       'message_confirmation_d' => 'An unsubscribing request from the lists below has been sent. ',
+       'message_confirmation_unique_a' => 'A subscription request to the following list has been sent :',
+       'message_confirmation_unique_d' => 'An unsubscribing request from the list below has been sent. ',
+       'mot' => 'And list the articles linked to the keyword',
+
+       // N
+       'nom' => 'Name and surname (optional)',
+       'nouveau_abomailman' => 'New mailing list',
+
+       // P
+       'pas_template_txt' => 'There is no text version for this template',
+       'periodicite' => ' days.',
+       'prenom' => 'First name',
+       'previsu_html' => 'html',
+       'previsu_txt' => 'text',
+
+       // R
+       'rubrique' => 'And list the articles of the section',
+
+       // S
+       'souhaite_rester' => 'I wish to keep informed',
+       'sujet' => 'Subject of the mail',
+       'sujet_obligatoire' => 'The subject is mandatory.',
+       'suppression_definitive' => 'Permanent removal !',
+       'supprimer' => 'Delete',
+       'sympa_message_confirmation' => 'A validation email has been sent to the address: ',
+
+       // T
+       'template' => 'Choose a template and his content',
+       'template_defaut' => 'Default template',
+       'template_defaut_info' => 'If the file "choosed_template.txt.html" exists, the newsletter will be sent in html + text format. Otherwise, only the html version will be sent.',
+       'texte_descriptif' => 'Description',
+       'titre_abomailman' => 'Title of the list',
+       'titre_liste_obligatoire' => 'The title of the list is mandatory',
+       'toute_liste' => 'All mailing lists',
+
+       // V
+       'verifier_formulaire' => 'Please verify the filling of the form.',
+       'veut_s_abonner' => 'want to subscribe',
+       'veut_se_desabonner' => 'want to unsubscribe',
+       'voir_modele_depuis' => 'See an example of the template with',
+       'votre_email' => 'Your email'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/abomailmans_es.php b/www/plugins/abomailmans/lang/abomailmans_es.php
new file mode 100644 (file)
index 0000000..8ca4b81
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/abomailmans?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailman' => 'Lista de difusión o discusiones',
+       'abomailmans' => 'Listas de difusión o discusiones',
+       'abonne' => 'Me suscribo',
+       'activation' => 'Activación',
+       'active' => 'Activo',
+       'aucune_langue' => 'Ninguno específico',
+
+       // B
+       'bouton_listes_diffusion' => 'Listas de difusión',
+       'btn_abonnement' => 'Suscribirse',
+       'btn_desabonnement' => 'Darse de baja',
+
+       // C
+       'choisir_liste' => 'Debe elegir una lista.',
+       'contenu_date' => 'Contenido a partir de esta fecha',
+       'creation_droits_insuffisants' => 'Sus derechos son insuficientes...',
+
+       // D
+       'desactive' => 'Desactivado',
+       'destinataire' => 'Destinatario',
+
+       // E
+       'email' => 'Correo electrónico',
+       'email_abonnement' => 'Su dirección de correo electrónico',
+       'email_envoye' => 'El correo electrónico ha sido enviado a la lista de difusión: @liste@.',
+       'email_oublie' => 'Ha olvidado su dirección de correo electrónico',
+       'emailliste_abomailman' => 'La dirección de correo electrónico de la lista',
+       'emailliste_abosympa' => 'La dirección de correo electrónico del administrador Sympa',
+       'emailliste_subscribe' => 'Suscripción',
+       'emailliste_unsubscribe' => 'Baja como suscriptor',
+       'emails_a_renseigner' => 'Correos electrónicos a reportar',
+       'envoi_apercu' => 'Vista previa',
+       'envoi_confirmer' => 'Confirmar y enviar',
+       'envoi_liste_parametres' => 'Lista de parámetros de configuración [Opcional]',
+       'envoi_parametres' => 'Configuración',
+       'envoi_regulier' => 'Envíos automáticos',
+       'envoi_regulier_info' => 'Dejar en blanco para no recibir envíos automáticos',
+       'envoi_regulier_tous_les' => 'Enviar todos los',
+       'envoi_vers' => 'enviar a',
+       'envoyer_courier' => 'Envíar un correo electrónico',
+       'envoyer_courier_liste' => 'Enviar este correo electrónico a esta lista de difusión:',
+       'envoyer_mailmans' => 'Seleccionar el modelo y su contenido',
+       'erreur_email_liste_oublie' => 'La dirección de correo electrónico es obligatoria',
+       'erreur_nobot' => 'Su inscripción no ha podido efectuarse debido a un problema técnico',
+       'explication_email_subscribe' => 'Correo electrónico de suscripción, del estilo <code>suffixe+subscribe@exemple.org</code>',
+       'explication_email_sympa' => 'Si este campo es reportado, la lista se considera como una lista de servidor "Sympa", en caso contrario como una lista "Mailman" o "ezmlm".',
+       'explication_email_unsubscribe' => 'Correo electrónico de baja de suscripción',
+
+       // I
+       'icone_ajouter_liste' => 'Añadir una nueva lista',
+       'icone_envoyer_mail_liste' => 'Enviar un correo electrónico a los boletines a partir del contenido de este sitio',
+       'icone_modifier_abomailman' => 'Modificar la lista',
+       'icone_retour_abomailman' => 'Volver a la lista',
+       'info_abomailman_aucun' => 'Ninguna lista',
+       'info_abomailmans_1' => 'Una lista',
+       'info_abomailmans_nb' => '@nb@ listas',
+       'info_sisympa' => '[Obligatorio en caso de liste Sympa]',
+       'insciption_listes_legende' => 'Suscripción a las listas de suscripción',
+       'inscription_lettres_legende' => 'Suscripción a las listas de difusión y de discusiones',
+
+       // J
+       'je_m_abonne' => 'Marque para validar la suscripción o la baja en la suscripción',
+
+       // L
+       'label_etat_liste' => 'Estado de la lista',
+       'label_type_abo' => 'Tipo',
+       'label_type_ml' => 'Lista de discusión',
+       'label_type_news' => 'Lista de difusión',
+       'langue_liste' => 'Idioma de la lista',
+       'legende_inscription_ml' => 'Inscripción a la lista de discusión',
+       'legende_inscription_news' => 'Inscripción en la lista de difusión',
+       'legende_inscriptions_ml' => 'Inscripción en la listas de discusión',
+       'legende_inscriptions_news' => 'Inscripción a las listas de difusión',
+       'les_listes_mailmans' => 'Listas mailmans, sympa o ezmlm reportadas',
+       'lire_article' => 'Leer artículo',
+       'liste_creee' => 'La lista número @id@ (@titre@) ha sido creada.',
+       'liste_non_existante' => 'La lista solicitada no existe o ha sido eliminada',
+       'liste_oublie' => '¡Ha olvidado marcar una lista!',
+       'liste_supprimee' => 'La lista número @id@ (@titre@) ha sido eliminada.',
+       'liste_updatee' => 'La lista número @id@ (@titre@) ha sido actualizada.',
+
+       // M
+       'message' => 'Introducción a su correo, antes del contenido del sitio',
+       'message_confirm_suite' => 'Para confirmar su solicitud, responda a la solicitud de confirmación que ha recibido por correo electrónico.',
+       'message_confirmation_a' => 'Una solicitud de suscripción a las siguientes listas acaba de ser enviada:',
+       'message_confirmation_d' => 'Una solicitud de baja en la suscripción a las siguientes listas acaba de ser enviada.',
+       'message_confirmation_unique_a' => 'Una solicitud de suscripción a la siguiente lista acaba de ser enviada:',
+       'message_confirmation_unique_d' => 'Una solicitud de baja de la suscripción a la siguiente lista acaba de ser enviada. ',
+       'mot' => 'Y listar los artículos de la palabra clave',
+
+       // N
+       'nom' => 'Apellidos y nombre (opcional)',
+       'nouveau_abomailman' => 'Nueva lista de difusión',
+
+       // P
+       'pas_template_txt' => 'No hay una versión texto para este modelo',
+       'periodicite' => ' días.',
+       'prenom' => 'Nombre',
+       'previsu_html' => 'html',
+       'previsu_txt' => 'texto',
+
+       // R
+       'rubrique' => 'Y listar los artículos de la sección',
+
+       // S
+       'souhaite_rester' => 'Quiero estar informado/a',
+       'sujet' => 'Asunto del correo electrónico',
+       'sujet_obligatoire' => 'El asunto es obligatorio.',
+       'suppression_definitive' => '¡Eliminación definitiva!',
+       'supprimer' => 'Eliminar',
+       'sympa_message_confirmation' => 'Un correo electrónico de confirmación ha sido enviado a la dirección: ',
+
+       // T
+       'template' => 'Elija el modelo y su contenido',
+       'template_defaut' => 'Modelo por defecto',
+       'template_defaut_info' => 'Si el archivo modelo_elegido.txt.html existe, el boletín será enviado en modo html + texte. Si no, sólo la versión html será expedida. ',
+       'texte_descriptif' => 'Descripción',
+       'titre_abomailman' => 'Título de la lista',
+       'titre_liste_obligatoire' => 'El título de la lista es obligatorio',
+       'toute_liste' => 'Todas las listas de difusión',
+
+       // V
+       'verifier_formulaire' => 'Verifique el contenido del formulario.',
+       'veut_s_abonner' => 'quiere suscribirse',
+       'veut_se_desabonner' => 'quiere darse de baja',
+       'voir_modele_depuis' => 'Ver un ejemplo del modelo con',
+       'votre_email' => 'Su correo electrónico'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/abomailmans_fr.php b/www/plugins/abomailmans/lang/abomailmans_fr.php
new file mode 100755 (executable)
index 0000000..ef5733a
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/abomailmans/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailman' => 'Liste de diffusion ou discussions',
+       'abomailmans' => 'Listes de diffusion ou discussions',
+       'abonne' => 'Je m\'abonne',
+       'activation' => 'Activation',
+       'active' => 'Active',
+       'aucune_langue' => 'Aucune spécifique',
+
+       // B
+       'bouton_listes_diffusion' => 'Les listes de diffusion',
+       'btn_abonnement' => 'S\'abonner',
+       'btn_desabonnement' => 'Se désabonner',
+
+       // C
+       'choisir_liste' => 'Vous devez choisir une liste.',
+       'contenu_date' => 'Contenu à partir de cette date',
+       'creation_droits_insuffisants' => 'Vos droits sont insuffisants...',
+
+       // D
+       'desactive' => 'Désactivée',
+       'destinataire' => 'Destinataire',
+
+       // E
+       'email' => 'E-mail',
+       'email_abonnement' => 'Votre adresse e-mail',
+       'email_envoye' => 'L\'e-mail a été envoyé à la liste de diffusion : @liste@.',
+       'email_oublie' => 'Vous avez oublié votre adresse e-mail',
+       'emailliste_abomailman' => 'L\'adresse e-mail de la liste',
+       'emailliste_abosympa' => 'L\'adresse e-mail de l\'administrateur Sympa',
+       'emailliste_subscribe' => 'Abonnement',
+       'emailliste_unsubscribe' => 'Désabonnement',
+       'emails_a_renseigner' => 'Emails à renseigner',
+       'envoi_apercu' => 'Aperçu',
+       'envoi_confirmer' => 'Confirmer et envoyer',
+       'envoi_liste_parametres' => 'Liste des paramètres [Facultatif]',
+       'envoi_parametres' => 'Paramètres',
+       'envoi_regulier' => 'Envois automatiques',
+       'envoi_regulier_info' => 'Laisser vide pour ne pas avoir d\'envois automatiques',
+       'envoi_regulier_tous_les' => 'Envoi tous les',
+       'envoi_vers' => 'envoi vers',
+       'envoyer_courier' => 'Envoyer un courrier',
+       'envoyer_courier_liste' => 'Envoyer ce courrier à cette liste de diffusion :',
+       'envoyer_mailmans' => 'Sélectionner le modèle et son contenu',
+       'erreur_email_liste_oublie' => 'L\'adresse email de la liste est obligatoire',
+       'erreur_nobot' => 'Votre inscription n\' a pu être effectué à cause d\'un problème technique',
+       'explication_email_subscribe' => 'Email d\'abonnement, de style <code>suffixe+subscribe@exemple.org</code>',
+       'explication_email_sympa' => 'Si ce champ est renseigné, la liste est considérée comme une liste de serveur "Sympa", dans le cas contraire comme une liste "Mailman" ou "ezmlm".',
+       'explication_email_unsubscribe' => 'Email de désabonnement',
+
+       // I
+       'icone_ajouter_liste' => 'Ajouter une nouvelle liste',
+       'icone_envoyer_mail_liste' => 'Envoyer un e-mail aux lettres à partir du contenu de ce site',
+       'icone_modifier_abomailman' => 'Modifier la liste',
+       'icone_retour_abomailman' => 'Retour à la liste',
+       'info_abomailman_aucun' => 'Aucune liste',
+       'info_abomailmans_1' => 'Une liste',
+       'info_abomailmans_nb' => '@nb@ listes',
+       'info_sisympa' => '[Obligatoire si liste Sympa]',
+       'insciption_listes_legende' => 'Abonnement aux listes de diffusion',
+       'inscription_lettres_legende' => 'Abonnement aux listes de diffusion et de discussions',
+
+       // J
+       'je_m_abonne' => 'Cochez pour valider l\'abonnement ou le désabonnement.',
+
+       // L
+       'label_etat_liste' => 'État de la liste',
+       'label_type_abo' => 'Type',
+       'label_type_ml' => 'Liste de discussion',
+       'label_type_news' => 'Liste de diffusion',
+       'langue_liste' => 'Langue de la liste',
+       'legende_inscription_ml' => 'Inscription à la liste de discussion',
+       'legende_inscription_news' => 'Inscription à la liste de diffusion',
+       'legende_inscriptions_ml' => 'Inscription aux listes de discussion',
+       'legende_inscriptions_news' => 'Inscription aux listes de diffusion',
+       'les_listes_mailmans' => 'Les listes mailmans, sympa ou ezmlm renseignées',
+       'lire_article' => 'Lire l\'article',
+       'liste_creee' => 'La liste numéro @id@ (@titre@) a été créée.',
+       'liste_non_existante' => 'La liste demandée n\'existe pas ou a été supprimée',
+       'liste_oublie' => 'Vous avez oublié de cocher une liste !',
+       'liste_supprimee' => 'La liste numéro @id@ (@titre@) a été supprimée.',
+       'liste_updatee' => 'La liste numéro @id@ (@titre@) a été mise à jour.',
+
+       // M
+       'message' => 'Introduction à votre courrier, avant le contenu issu du site',
+       'message_confirm_suite' => 'Pour valider votre demande, répondez à la demande de confirmation que vous allez recevoir par mail.',
+       'message_confirmation_a' => 'Une demande d\'abonnement aux listes suivantes vient d\'être envoyée :',
+       'message_confirmation_d' => 'Une demande de désabonnement aux listes suivantes vient d\'être envoyée. ',
+       'message_confirmation_unique_a' => 'Une demande d\'abonnement à la liste suivante vient d\'être envoyée :',
+       'message_confirmation_unique_d' => 'Une demande de désabonnement à la liste suivante vient d\'être envoyée. ',
+       'mot' => 'Et lister les articles du mot clé',
+
+       // N
+       'nom' => 'Nom et prénom (facultatif)',
+       'nouveau_abomailman' => 'Nouvelle liste de diffusion',
+
+       // P
+       'pas_template_txt' => 'Il n\'y a pas de version texte pour ce modèle',
+       'periodicite' => ' jours.',
+       'prenom' => 'Prénom',
+       'previsu_html' => 'html',
+       'previsu_txt' => 'texte',
+
+       // R
+       'rubrique' => 'Et lister les articles de la rubrique',
+
+       // S
+       'souhaite_rester' => 'Je souhaite rester informé-e',
+       'sujet' => 'Sujet du courrier',
+       'sujet_obligatoire' => 'Le sujet est obligatoire.',
+       'suppression_definitive' => 'Suppression définitive !',
+       'supprimer' => 'Supprimer',
+       'sympa_message_confirmation' => 'Un email de validation a été envoyé à l\'adresse : ',
+
+       // T
+       'template' => 'Choisissez le modèle et son contenu',
+       'template_defaut' => 'Modèle par défaut',
+       'template_defaut_info' => 'Si le fichier modele_choisi.txt.html existe, la newsletter sera envoyée en mode html + texte. Sinon seule la version html sera expédiée.',
+       'texte_descriptif' => 'Descriptif',
+       'titre_abomailman' => 'Titre de la liste',
+       'titre_liste_obligatoire' => 'Le titre de la liste est obligatoire',
+       'toute_liste' => 'Toutes les listes de diffusion',
+
+       // V
+       'verifier_formulaire' => 'Vérifiez le remplissage du formulaire.',
+       'veut_s_abonner' => 'veut s\'abonner',
+       'veut_se_desabonner' => 'veut se désabonner',
+       'voir_modele_depuis' => 'Voir un exemple du modèle avec',
+       'votre_email' => 'Votre email'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/abomailmans_sk.php b/www/plugins/abomailmans/lang/abomailmans_sk.php
new file mode 100644 (file)
index 0000000..8d18185
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/abomailmans?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailman' => 'E-mailová alebo diskusná skupina',
+       'abomailmans' => 'E-mailové alebo diskusné skupiny',
+       'abonne' => 'Prihlasujem sa na odoberanie',
+       'activation' => 'Aktivácia',
+       'active' => 'Aktivovaný',
+       'aucune_langue' => 'Žiaden konkrétny',
+
+       // B
+       'bouton_listes_diffusion' => 'E-mailové skupiny',
+       'btn_abonnement' => 'Prihlásiť sa na odoberanie',
+       'btn_desabonnement' => 'Odhlásiť sa z odoberania',
+
+       // C
+       'choisir_liste' => 'Musíte si vybrať skupinu.',
+       'contenu_date' => 'Novinky z tohto dňa',
+       'creation_droits_insuffisants' => 'Vaše práva sú nedostatočné.',
+
+       // D
+       'desactive' => 'Deaktivovaný',
+       'destinataire' => 'Príjemca',
+
+       // E
+       'email' => 'E-mail',
+       'email_abonnement' => 'Vaša e-mailová adresa',
+       'email_envoye' => 'E-mail bol odoslaný do skupiny: @liste@.',
+       'email_oublie' => 'Zabudli ste svoju e-mailovú adresu',
+       'emailliste_abomailman' => 'E-mailová adresa skupiny',
+       'emailliste_abosympa' => 'E-mailová adresa administrátora (Sympa)',
+       'emailliste_subscribe' => 'Prihlásenie na odoberanie',
+       'emailliste_unsubscribe' => 'Odhlásenie sa z odoberania',
+       'emails_a_renseigner' => 'E-maily pre informácie',
+       'envoi_apercu' => 'Anketa',
+       'envoi_confirmer' => 'Potvrdiť a poslať',
+       'envoi_liste_parametres' => 'Zoznam parametrov [Nepovinné]',
+       'envoi_parametres' => 'Parametre',
+       'envoi_regulier' => 'Automatické odosielanie',
+       'envoi_regulier_info' => 'Nevypĺňajte, ak nechcete využívať automatické odosielanie',
+       'envoi_regulier_tous_les' => 'Poslať všetky',
+       'envoi_vers' => 'príjemca',
+       'envoyer_courier' => 'Poslať e-mail',
+       'envoyer_courier_liste' => 'Tento e-mail poslať do e-mailovej skupiny:',
+       'envoyer_mailmans' => 'Vyberte si šablónu a jej obsah',
+       'erreur_email_liste_oublie' => 'E-mailová adresa skupiny je povinný údaj',
+       'erreur_nobot' => 'Registrácia sa z technických príčin neuskutočnila',
+       'explication_email_subscribe' => 'E-mail na prihlásenie sa na odoberanie v podobe<code>suffixe+subscribe@exemple.org</code>',
+       'explication_email_sympa' => 'Ak toto pole vyplníte, skupina bude považovaná za skupinu servera Sympa, v opačnom prípade za skupinu servera "Mailman" alebo "ezmlm".',
+       'explication_email_unsubscribe' => 'E-mail na odhlásenie',
+
+       // I
+       'icone_ajouter_liste' => 'Pridať novú skupinu',
+       'icone_envoyer_mail_liste' => 'Poslať e-mail s textom tejto stránky',
+       'icone_modifier_abomailman' => 'Upraviť skupinu',
+       'icone_retour_abomailman' => 'Vrátiť sa na skupinu',
+       'info_abomailman_aucun' => 'Žiadna skupina',
+       'info_abomailmans_1' => 'Jedna skupina',
+       'info_abomailmans_nb' => '@nb@ skupín',
+       'info_sisympa' => '(Povinné pre skupinu Sympa)',
+       'insciption_listes_legende' => 'Odoberanie príspevkov e-mailových skupín',
+       'inscription_lettres_legende' => 'Odoberanie príspevkov e-mailových a diskusných skupín',
+
+       // J
+       'je_m_abonne' => 'Označením príslušného poľa potvrďte svoje prihlásenie alebo odhlásenie.',
+
+       // L
+       'label_etat_liste' => 'Stav skupiny',
+       'label_type_abo' => 'Typ',
+       'label_type_ml' => 'Diskusná skupina',
+       'label_type_news' => 'E-mailová skupina',
+       'langue_liste' => 'Jazyk skupiny',
+       'legende_inscription_ml' => 'Registrácia do diskusnej skupiny',
+       'legende_inscription_news' => 'Registrácia do e-mailovej skupiny',
+       'legende_inscriptions_ml' => 'Registrácia do diskusných skupín',
+       'legende_inscriptions_news' => 'Registrácia do e-mailových skupín',
+       'les_listes_mailmans' => 'Informované skupiny mailmans, sympa alebo ezmlm',
+       'lire_article' => 'Čítať článok',
+       'liste_creee' => 'Skupina číslo @id@ (@titre@) bola vytvorená.',
+       'liste_non_existante' => 'Požadovaná skupina neexistuje alebo bola vymazaná',
+       'liste_oublie' => 'Zabudli ste skontrolovať skupinu!',
+       'liste_supprimee' => 'Skupina číslo @id@ (@titre@) bola vymazaná.',
+       'liste_updatee' => 'Skupina číslo @id@ (@titre@) bola aktualizovaná.',
+
+       // M
+       'message' => 'Úvod do e-mailu pred obsahom stránky',
+       'message_confirm_suite' => 'Ak chcete potvrdiť požiadavku, postupujte podľa pokynov, ktoré dostanete e-mailom.',
+       'message_confirmation_a' => 'Bola odoslaná požiadavka na prihlásenie na odoberanie príspevkov týchto skupín:',
+       'message_confirmation_d' => 'Požiadavka na odhlásenie z odoberania príspevkov týchto skupín bola odoslaná.',
+       'message_confirmation_unique_a' => 'Bola odoslaná požiadavka na odoberanie príspevkov z tejto skupiny:',
+       'message_confirmation_unique_d' => 'Požiadavka na odhlásenie sa z odoberania príspevkov z tejto skupiny bola odoslaná.',
+       'mot' => 'A vypísať články s kľúčovým slovom ',
+
+       // N
+       'nom' => 'Priezvisko a meno (nepovinné)',
+       'nouveau_abomailman' => 'Nová e-mailová skupina',
+
+       // P
+       'pas_template_txt' => 'K tejto šablóne neexistuje textová verzie',
+       'periodicite' => ' dní/dni.',
+       'prenom' => 'Krstné meno',
+       'previsu_html' => 'html',
+       'previsu_txt' => 'nenaformátovaný text',
+
+       // R
+       'rubrique' => 'A vypísať články z rubriky',
+
+       // S
+       'souhaite_rester' => 'Chcem mať prehľad',
+       'sujet' => 'Predmet e-mailu',
+       'sujet_obligatoire' => 'Predmet je povinný.',
+       'suppression_definitive' => 'Definitívne odstránenie!',
+       'supprimer' => 'Odstrániť',
+       'sympa_message_confirmation' => 'Potvrdzovací e-mail bol odoslaný na túto adresu: ',
+
+       // T
+       'template' => 'Vyberte si šablónu a jej obsah',
+       'template_defaut' => 'Predvolená šablóna',
+       'template_defaut_info' => 'Ak súbor modele_choisi.txt.html existuje, bulletin bude odoslaný vo verzii html aj ako text. Inak bude odoslaný iba vo verzii html.',
+       'texte_descriptif' => 'Popis',
+       'titre_abomailman' => 'Názov skupiny',
+       'titre_liste_obligatoire' => 'Názov skupiny je povinný údaj',
+       'toute_liste' => 'Všetky e-mailové skupiny',
+
+       // V
+       'verifier_formulaire' => 'Skontrolujte, ako ste vyplnili formulár.',
+       'veut_s_abonner' => 'chcem sa prihlásiť',
+       'veut_se_desabonner' => 'chcem sa odhlásiť',
+       'voir_modele_depuis' => 'Zobraziť príklad šablóny s ',
+       'votre_email' => 'Váš e-mail'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/paquet-abomailmans.xml b/www/plugins/abomailmans/lang/paquet-abomailmans.xml
new file mode 100644 (file)
index 0000000..15f26a0
--- /dev/null
@@ -0,0 +1,13 @@
+<traduction module="paquet-abomailmans" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/abomailmans/trunk/lang/" reference="fr">
+       <langue code="de" />
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-abomailmans?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-abomailmans?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-abomailmans?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/abomailmans/lang/paquet-abomailmans_de.php b/www/plugins/abomailmans/lang/paquet-abomailmans_de.php
new file mode 100644 (file)
index 0000000..acdbf2a
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-abomailmans?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailmans_description' => 'Dieses Plugin ermöglich mit dem TAG #FORMULAIRE_ABOMAILMAN das Abnonnieren von Mailinglisten.
+                       Dem Adminstrator steht ein Interface zur Verwaltung dieser Listen zur Verfügung.',
+       'abomailmans_nom' => 'Abonnieren Sie Mailing-Listen',
+       'abomailmans_slogan' => 'Interfacer vos listes de diffusions mailman, ezmlm ou sympa avec votre SPIP' # NEW
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/paquet-abomailmans_en.php b/www/plugins/abomailmans/lang/paquet-abomailmans_en.php
new file mode 100644 (file)
index 0000000..125c1ac
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-abomailmans?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailmans_description' => 'This plugin adds a registration form to mailing lists and newsletters services as [Mailman->http://www.gnu.org/software/mailman/], [Ezmlm->http://www.ezmlm.org/] or [Sympa->http://www.sympa.org].
+
+The administrator can manage the lists from the private space via a dedicated interface.',
+       'abomailmans_nom' => 'Mailing lists and newsletters subscription',
+       'abomailmans_slogan' => 'Interface your Mailman, Ezmlm or Sympa mailing lists and newsletters with SPIP'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/paquet-abomailmans_es.php b/www/plugins/abomailmans/lang/paquet-abomailmans_es.php
new file mode 100644 (file)
index 0000000..3ec6930
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-abomailmans?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailmans_description' => 'Este plugin permite a través de una etiqueta #FORMULAIRE_ABOMAILMAN mostrar un formulario de suscripción al conjunto de las listas [Mailman->http://www.gnu.org/software/mailman/], [Ezmlm->http://www.ezmlm.org/] o [Sympa->http://www.sympa.org] renseignées.
+_ Esta inscripción se hace a través de la interfaz privada de SPIP por el menú "Edición Abomailmans listas de difusiones mailman".
+_ A continuación puede seleccionar artículos de su SPIP, por criterios de fecha, de sección y/o de palabra clave y enviar su contenido a estas listas, usando esqueletos de formateo de contenido.
+_ El enlace con las listas Mailman, Ezmlm y Sympa se hace por envíos de correo electrónico. ',
+       'abomailmans_nom' => 'Suscripción a las listas de difusión',
+       'abomailmans_slogan' => 'Vincular sus listas de difusiones mailman, ezmlm o sympa con su SPIP'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/paquet-abomailmans_fr.php b/www/plugins/abomailmans/lang/paquet-abomailmans_fr.php
new file mode 100644 (file)
index 0000000..f8f8867
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/abomailmans/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailmans_description' => 'Ce plugin permet via une balise #FORMULAIRE_ABOMAILMAN d\'afficher un formulaire d\'abonnement à l\'ensemble des listes [Mailman->http://www.gnu.org/software/mailman/], [Ezmlm->http://www.ezmlm.org/] ou [Sympa->http://www.sympa.org] renseignées.
+_ Cette inscription se fait via l\'interface privée de SPIP par le menu "Edition Abomailmans les listes de diffusions mailman".
+_ Ensuite il vous est possible de sélectionner des articles de votre SPIP, par des critères de date, de rubrique et/ou de mot-clé et envoyer leurs contenus à ces listes, en utilisant des squelettes de mise en page du contenu.
+_ Le lien avec les listes Mailman, Ezmlm et Sympa se fait par des envois d\'e-mail.',
+       'abomailmans_nom' => 'Abonnement à des listes de diffusion',
+       'abomailmans_slogan' => 'Interfacer vos listes de diffusions mailman, ezmlm ou sympa avec votre SPIP'
+);
+
+?>
diff --git a/www/plugins/abomailmans/lang/paquet-abomailmans_sk.php b/www/plugins/abomailmans/lang/paquet-abomailmans_sk.php
new file mode 100644 (file)
index 0000000..817dd1e
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-abomailmans?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'abomailmans_description' => 'Tento zásuvný modul umožňuje pomocou tagu #FORMULAIRE_ABOMAILMAN zobraziť formulár na prihlásenie sa na odoberanie príspevkov celého radu typov skupín (resp. konferencií)  [Mailman,->http://www.gnu.org/software/mailman/] [Ezmlm->http://www.ezmlm.org/] alebo [Sympa.->http://www.sympa.org] 
+_ Registrácia sa vykonáva cez súkromnú zónu SPIPu pomocou menu "Úprava skupín typu mailman".
+_ Potom si zo svojej stránky v SPIPe môžete vybrať články  podľa dátumu, rubriky a/lebo kľúčového slova a poslať ich do týchto skupín (resp. konferencií, mailing listov) pomocou šablón na úpravu vzhľadu textu.
+_ Odkaz na skupiny Mailman, Ezmlm a Sympa získate odoslaním e-mailu.',
+       'abomailmans_nom' => 'Odoberanie príspevkov e-mailových konferencií (skupín)',
+       'abomailmans_slogan' => 'Ovládajte svoje e-mailové skupiny, (e-mailové konferencie), diskusné skupiny či mailing listy typu mailman, ezmlm alebo sympa so svojím SPIPom'
+);
+
+?>
diff --git a/www/plugins/abomailmans/paquet.xml b/www/plugins/abomailmans/paquet.xml
new file mode 100644 (file)
index 0000000..6a1f0b8
--- /dev/null
@@ -0,0 +1,34 @@
+<paquet\r
+       prefix="abomailmans"\r
+       categorie="communication"\r
+       version="1.1.4"\r
+       etat="dev"\r
+       compatibilite="[3.0.0;3.0.*]"\r
+       logo="prive/themes/spip/images/abomailmans-32.png"\r
+       schema="0.34"\r
+       documentation="http://www.spip-contrib.net/Abomailmans-pour-s-abonner-a-des-listes-de-diffusion"\r
+>      \r
+\r
+       <nom>Abonnement à des listes de diffusion</nom>\r
+       <!-- Interfacer vos listes de diffusions mailman, ezmlm ou sympa avec votre SPIP -->\r
+\r
+       <auteur lien="http://www.netaktiv.com">NetAktiv</auteur>\r
+       <auteur lien="http://www.elastick.net">Anne-lise Martenot</auteur>\r
+       <auteur>Yffic</auteur>\r
+       <auteur lien="http://www.kent1.info">kent1</auteur>\r
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>\r
+       \r
+       <traduire module="abomailmans" reference="fr" gestionnaire="salvatore" />\r
+       <traduire module="paquet-abomailmans" reference="fr" gestionnaire="salvatore" />\r
+       \r
+       <pipeline nom="declarer_tables_interfaces" inclure="base/abomailmans_install.php" />\r
+       <pipeline nom="declarer_tables_objets_sql" inclure="base/abomailmans_install.php" />\r
+       <pipeline nom="taches_generales_cron" inclure="abomailmans_pipelines.php" />\r
+       <pipeline nom="abomailmans" action="go" inclure="abomailmans_pipelines.php" />\r
+       <pipeline nom="autoriser" inclure="abomailmans_autoriser.php" />\r
+\r
+       <necessite nom="facteur" compatibilite="[2.0.0;[" />\r
+       \r
+       <menu nom="abomailmans" titre="abomailmans:bouton_listes_diffusion" parent="bando_edition" icone="images/abomailmans-16.png" />\r
+       <menu nom="abomailman_edit" parametres="new=oui" titre="abomailmans:icone_ajouter_liste" parent="outils_rapides" icone="images/abomailmans-new-16.png" />\r
+</paquet>\r
diff --git a/www/plugins/abomailmans/prive/listes/abomailman_mots.html b/www/plugins/abomailmans/prive/listes/abomailman_mots.html
new file mode 100644 (file)
index 0000000..f50a3c2
--- /dev/null
@@ -0,0 +1,9 @@
+<BOUCLE_groupes_mots(GROUPES_MOTS){tables_liees LIKE %articles%}{par num titre,titre}>
+       <B_mots>
+               <optgroup label="[(#TITRE|supprimer_numero|attribut_html)]">
+               <BOUCLE_mots(MOTS){id_groupe}{par num titre,titre}>
+                       <option value="#ID_MOT"[(#ENV{id_mot}|=={#ID_MOT}|oui) selected="selected"]>[(#TITRE|supprimer_numero)]</option>
+               </BOUCLE_mots>
+               </optgroup>
+       </B_mots>
+</BOUCLE_groupes_mots>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/listes/abomailman_rubriques.html b/www/plugins/abomailmans/prive/listes/abomailman_rubriques.html
new file mode 100644 (file)
index 0000000..02ec561
--- /dev/null
@@ -0,0 +1,17 @@
+#SET{id_parent,#ENV{id_rubrique,0}}
+#SET{niveau,#ENV{niveau,1}}
+[(#GET{niveau}|>={2}|oui)
+       [(#SET{marge,#ENV{marge}|concat{----}})]
+       
+]
+<BOUCLE_rubriques(RUBRIQUES){id_parent=#GET{id_parent}}{par id_rubrique}>
+[(#GET{niveau}|=={1}|oui)
+       [(#SET{marge,&bull;})]
+]
+[(#GET{niveau}|=={2}|oui)
+       [(#SET{marge,'&nbsp;&nbsp;&nbsp;|----'})]
+]
+
+<option value="#ID_RUBRIQUE"[(#ENV{id_rubrique_env}|=={#ID_RUBRIQUE}|oui) selected="selected"]>#GET{marge}&nbsp;[(#TITRE|supprimer_numero)]</option>
+[(#INCLURE{fond=prive/listes/abomailman_rubriques}{niveau=[(#GET{niveau}|plus{1})]}{id_rubrique=#ID_RUBRIQUE}{id_rubrique_env}{marge=#GET{marge}})]
+</BOUCLE_rubriques>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/listes/abomailman_templates.html b/www/plugins/abomailmans/prive/listes/abomailman_templates.html
new file mode 100755 (executable)
index 0000000..a5c3340
--- /dev/null
@@ -0,0 +1,16 @@
+[(#REM) Tous les fichiers *.html, mais pas les .txt.html ]\r
+#SET{arraytemplate,#EVAL{find_all_in_path("templates/",".*(?<!txt)\.html$")}}\r
+\r
+<BOUCLE_abomailman(ABOMAILMANS){id_abomailman}>\r
+[(#SET{select,[(#MODELE_DEFAUT|nettoie_chemin)]})]\r
+</BOUCLE_abomailman>\r
+[(#ENV{template}|oui)\r
+[(#SET{select,[(#ENV{template})]})]\r
+]\r
+\r
+\r
+<BOUCLE_template(POUR){tableau #GET{arraytemplate}}{par valeur}>\r
+<option value="[(#VALEUR|nettoie_chemin)]" \r
+[(#GET{select}|=={[(#VALEUR|nettoie_chemin)]}|oui) selected="selected" ]>\r
+[(#VALEUR|nettoie_chemin)]</option>\r
+</BOUCLE_template>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/listes/listes_des_listes.html b/www/plugins/abomailmans/prive/listes/listes_des_listes.html
new file mode 100644 (file)
index 0000000..5b8556f
--- /dev/null
@@ -0,0 +1,20 @@
+<B_listes>
+<li class="editer abomailman_listes[ (#ENV**{erreurs}|table_valeur{listes}|oui)erreur]">
+       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{listes})</span>]
+       <ul>
+               <li class="editer_listes">
+                       [(#GRAND_TOTAL|>{1}|oui)
+                       <label><:abomailman:label_choisir_listes:></label>]
+               <BOUCLE_listes(ABOMAILMANS){id_abomailman ?}{desactive=0}>
+               <div class="choix">
+                       <input name="listes[]" type="checkbox" id="liste_#ID_ABOMAILMAN" value="#ID_ABOMAILMAN"[(#GRAND_TOTAL|=={1}|oui) checked="checked"] />
+                       <label for="liste_#ID_ABOMAILMAN" class="#EDIT{titre}">#TITRE</label>
+                       [<p class="explications #EDIT{descriptif}">
+                       (#DESCRIPTIF|PtoBR)
+                       </p>]
+               </div>
+               </BOUCLE_listes>
+               </li>
+       </ul>
+</li>
+</B_listes>
diff --git a/www/plugins/abomailmans/prive/objets/contenu/abomailman.html b/www/plugins/abomailmans/prive/objets/contenu/abomailman.html
new file mode 100644 (file)
index 0000000..3bd664d
--- /dev/null
@@ -0,0 +1,30 @@
+<BOUCLE_afficher_contenu(ABOMAILMANS){id_abomailman=#ENV{id,#ENV{id_abomailman}}}>
+<div class="champ contenu_titre[ (#TITRE*|strlen|?{'',vide})]">
+       <div class='label'><:info_titre:></div>
+       <div dir='#LANG_DIR' class='#EDIT{titre} titre'>#TITRE</div>
+</div>
+<div class="champ contenu_descriptif[ (#DESCRIPTIF*|strlen|?{'',vide})]">
+       <div class='label'><:info_descriptif:></div>
+       [(#DESCRIPTIF|image_reduire{500,0})]</div>
+</div>
+<div class="champ contenu_email[ (#EMAIL*|strlen|?{'',vide})]">
+       <div class='label'><:abomailmans:emailliste_abomailman:></div>
+       <div dir='#LANG_DIR' class='#EDIT{email} email'>[(#EMAIL)]</div>
+</div>
+[<div class="champ contenu_email_sympa[ (#EMAIL_SYMPA*|strlen|?{'',vide})]">
+       <div class='label'><:abomailmans:emailliste_abosympa:></div>
+       <div dir='#LANG_DIR' class='#EDIT{email_sympa} email_sympa'>(#EMAIL_SYMPA)</div>
+</div>]
+[<div class="champ contenu_periodicite[ (#PERIODICITE*|strlen|?{'',vide})]">
+       <div class='label'><:abomailmans:envoi_regulier:></div>
+       <div dir='#LANG_DIR' class='#EDIT{periodicite} descriptif'>(#PERIODICITE)</div>
+</div>]
+[<div class="champ contenu_lang[ (#LANG*|strlen|?{'',vide})]">
+       <div class='label'><:abomailmans:langue_liste:></div>
+       <div dir='#LANG_DIR' class='#EDIT{lang} lang'>(#LANG|traduire_nom_langue|sinon{<:abomailmans:aucune_langue:>})</div>
+</div>]                        
+[<div class="champ contenu_notes">
+       <div class='label'><:info_notes:></div>
+       <div dir='#LANG_DIR' class='#EDIT{notes} notes'>(#NOTES)</div>
+</div>
+]</BOUCLE_afficher_contenu>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/objets/infos/abomailman.html b/www/plugins/abomailmans/prive/objets/infos/abomailman.html
new file mode 100644 (file)
index 0000000..674be39
--- /dev/null
@@ -0,0 +1,4 @@
+<div class='infos'>
+#SET{texte_objet,#ENV{type}|objet_info{texte_objet}|_T}
+<div class='numero'><:titre_cadre_numero_objet{objet=#GET{texte_objet}}:><p>[(#ENV{id}|generer_info_entite{#ENV{type},[(#ENV{type}|id_table_objet)],'**'})]</p></div>
+</div>
diff --git a/www/plugins/abomailmans/prive/squelettes/contenu/abomailman.html b/www/plugins/abomailmans/prive/squelettes/contenu/abomailman.html
new file mode 100644 (file)
index 0000000..80aef1b
--- /dev/null
@@ -0,0 +1,24 @@
+<BOUCLE_afficher_contenu(ABOMAILMANS){id_abomailman=#ENV{id_abomailman}}{si #ENV{exec}|=={abomailman}}>\r
+[(#BOITE_OUVRIR{[\r
+       [(#AUTORISER{modifier,abomailman,#ID_ABOMAILMAN})\r
+               [(#ID_ABOMAILMAN|afficher_qui_edite{abomailman}|non)\r
+                       [(#URL_ECRIRE{abomailman_edit,id_abomailman=#ID_ABOMAILMAN}|icone_verticale{<:abomailmans:icone_modifier_abomailman:>,abomailmans-24,edit,right ajax preload})]\r
+               ]\r
+               [(#ID_ABOMAILMAN|afficher_qui_edite{abomailman}|oui)\r
+                       [(#URL_ECRIRE{abomailman_edit,id_abomailman=#ID_ABOMAILMAN}|icone_verticale{#ID_ABOMAILMAN|afficher_qui_edite{abomailmans-24},warning-24,'',right ajax preload})]\r
+               ]\r
+       ]\r
+       <h1>[(#RANG). ](#TITRE|sinon{<:info_sans_titre:>})[(#CHEMIN_IMAGE{abomailmans-24.png}|balise_img{article,cadre-icone})]</h1>\r
+],simple fiche_objet})]\r
+<div>\r
+<div id="wysiwyg">\r
+#INCLURE{fond=prive/objets/contenu/abomailman,env}\r
+</div>\r
+#BOITE_FERMER\r
+\r
+[(#EVAL{_AJAX}|oui)\r
+       <script type="text/javascript">/*<!\[CDATA\[*/reloadExecPage('#ENV{exec}','#navigation');/*\]\]>*/</script>\r
+]\r
+</BOUCLE_afficher_contenu>\r
+[(#ENV**{exec}|=={abomailman_edit}|?{#INCLURE{fond=prive/squelettes/contenu/abomailman_edit,env,retourajax=oui},#REM|sinon_interdire_acces})]\r
+<//B_afficher_contenu>\r
diff --git a/www/plugins/abomailmans/prive/squelettes/contenu/abomailman_edit.html b/www/plugins/abomailmans/prive/squelettes/contenu/abomailman_edit.html
new file mode 100644 (file)
index 0000000..d35478b
--- /dev/null
@@ -0,0 +1,30 @@
+[(#ID_ABOMAILMAN|intval|oui)\r
+       [(#AUTORISER{modifier,abomailman,#ID_ABOMAILMAN}|sinon_interdire_acces)]\r
+][(#ID_ABOMAILMAN|intval|non)\r
+       [(#AUTORISER{creer,abomailman}|sinon_interdire_acces)]\r
+]\r
+#SET{retour,#ENV{redirect}|sinon{#ID_ABOMAILMAN|intval|?{#URL_ECRIRE{abomailman,id_abomailman=#ID_ABOMAILMAN},#URL_ECRIRE{abomailmans}}}}\r
+\r
+<div class='cadre-formulaire-editer'>\r
+       <BOUCLE_liste(ABOMAILMANS){id_abomailman}>\r
+       <div class="entete-formulaire">\r
+               [(#GET{retour}|icone_verticale{<:icone_retour:>,abomailmans-24,'',left retour[(#ENV{retourajax,''}|oui)ajax preload]})]\r
+               <h1>[(#TITRE|supprimer_numero)]</h1>\r
+       </div>\r
+       </BOUCLE_liste>\r
+       <div class="entete-formulaire">\r
+               [(#GET{retour}|icone_verticale{<:icone_retour:>,abomailmans-24,'',left retour[(#ENV{retourajax,''}|oui)ajax preload]})]\r
+               <h1><:abomailmans:icone_ajouter_liste:></h1>\r
+       </div>\r
+       <//B_liste>\r
+       #SET{redirect,#ENV{redirect,#ID_ABOMAILMAN|generer_url_entite{abomailman}}}\r
+       [(#ENV{retourajax,''}|oui)\r
+               #SET{redirect,'javascript:if (window.jQuery) jQuery(".entete-formulaire .retour a").followLink();'}\r
+               <div class="ajax">\r
+       ]\r
+       #FORMULAIRE_EDITER_ABOMAILMAN{#ENV{id_abomailman,oui},#GET{redirect}}\r
+       [(#ENV{retourajax,''}|oui)\r
+               </div>\r
+               <script type="text/javascript">/*<!\[CDATA\[*/reloadExecPage('#ENV{exec}','#navigation,#extra');/*\]\]>*/</script>\r
+       ]\r
+</div>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/squelettes/contenu/abomailman_envoyer.html b/www/plugins/abomailmans/prive/squelettes/contenu/abomailman_envoyer.html
new file mode 100644 (file)
index 0000000..bdd5b3b
--- /dev/null
@@ -0,0 +1,7 @@
+<div class='cadre-formulaire-editer'>\r
+<div class="entete-formulaire">\r
+       [(#GET{retour}|icone_verticale{<:icone_retour:>,abomailmans-24,'',left retour[(#ENV{retourajax,''}|oui)ajax preload]})]\r
+       <h1><:abomailmans:envoyer_courier:></h1>\r
+</div>\r
+#FORMULAIRE_ABOMAILMAN_ENVOI_LISTE\r
+</div>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/squelettes/contenu/abomailmans.html b/www/plugins/abomailmans/prive/squelettes/contenu/abomailmans.html
new file mode 100644 (file)
index 0000000..2e0616a
--- /dev/null
@@ -0,0 +1,40 @@
+#CACHE{0}\r
+\r
+<h1><:abomailmans:les_listes_mailmans:></h1>\r
+\r
+<B_listes>\r
+#BOITE_OUVRIR\r
+       #ANCRE_PAGINATION\r
+       <div class="liste-objets abomailmans">\r
+       <table class='spip liste'>\r
+               <BOUCLE_listes(ABOMAILMANS){par titre}{pagination 10}>\r
+               <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">\r
+                       <td class="statut">\r
+                               [<img src="(#CHEMIN{images/[(#REPONSES|?{'puce-verte-breve.gif','puce-orange-breve.gif'})]})" width="7" height="7" style="border:none" alt="" />]\r
+                       </td>\r
+                       <td class="titre">\r
+                               [(#TITRE)]\r
+                       </td>\r
+                       <td class="lang">\r
+                               #LANG\r
+                       </td>\r
+                       <td class="statut">\r
+                               [(#DESACTIVE|=={1}|?{<:abomailmans:desactive:>,<:abomailmans:active:>})]\r
+                       </td>\r
+                       <td class='id'>[(#AUTORISER{modifier,abomailman,#ID_ABOMAILMAN}|?{\r
+                               <a href="[(#URL_ECRIRE{abomailman,id_abomailman=#ID_ABOMAILMAN})]">#ID_ABOMAILMAN</a>,\r
+                               #ID_ABOMAILMAN\r
+                       })]</td>\r
+               </tr>\r
+               </BOUCLE_listes>\r
+       </table>\r
+       [<div class="pagination">\r
+               (#PAGINATION)\r
+       </div>]\r
+</div>\r
+[(#BOITE_FERMER)]\r
+</B_listes>\r
+[(#AUTORISER{creer, abomailman}|oui)\r
+       [(#URL_ECRIRE{abomailman_edit,id_abomailman=new}|parametre_url{redirect,#SELF}\r
+               |icone_verticale{<:abomailmans:icone_ajouter_liste:>,abomailmans-24,new,right})]\r
+]
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/squelettes/navigation/abomailman.html b/www/plugins/abomailmans/prive/squelettes/navigation/abomailman.html
new file mode 100644 (file)
index 0000000..fb094b5
--- /dev/null
@@ -0,0 +1,8 @@
+[(#ID_ABOMAILMAN|generer_info_entite{abomailman,[(#VAL{abomailman}|id_table_objet)],'**'}|intval|=={#ID_ABOMAILMAN}|sinon_interdire_acces)]
+<BOUCLE_nav(ABOMAILMANS){id_abomailman}{si #ENV{exec}|=={abomailman}}>
+#BOITE_OUVRIR{'','info'}
+#PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{'type','abomailman','id',#ID_ABOMAILMAN}}}
+#BOITE_FERMER
+</BOUCLE_nav>
+[(#ENV{exec}|=={abomailman_edit}|oui)<INCLURE{fond=prive/squelettes/navigation/abomailman_edit,env}>]
+<//B_nav>
diff --git a/www/plugins/abomailmans/prive/squelettes/navigation/abomailmans.html b/www/plugins/abomailmans/prive/squelettes/navigation/abomailmans.html
new file mode 100644 (file)
index 0000000..4c9b97d
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_abos_active(ABOMAILMANS){desactive=0}{0,1}>\r
+[(#BOITE_OUVRIR)]\r
+[(#URL_ECRIRE{abomailman_envoyer}|icone_horizontale{<:abomailmans:icone_envoyer_mail_liste:>,abomailmans-envoyer-24})]\r
+[(#BOITE_FERMER)]\r
+</BOUCLE_abos_active>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/style_prive_plugin_abomailmans.html b/www/plugins/abomailmans/prive/style_prive_plugin_abomailmans.html
new file mode 100644 (file)
index 0000000..54a7677
--- /dev/null
@@ -0,0 +1,8 @@
+#CACHE{3600*100,cache-client}\r
+#HTTP_HEADER{Content-Type: text/css; charset=iso-8859-15}\r
+#HTTP_HEADER{Vary: Accept-Encoding}\r
+\r
+.abo_message {\r
+   overflow:auto;\r
+       width:520px;\r
+}
\ No newline at end of file
diff --git a/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-16.png b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-16.png
new file mode 100755 (executable)
index 0000000..a98ffe9
Binary files /dev/null and b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-16.png differ
diff --git a/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-24.png b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-24.png
new file mode 100644 (file)
index 0000000..b2b75fa
Binary files /dev/null and b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-24.png differ
diff --git a/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-32.png b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-32.png
new file mode 100644 (file)
index 0000000..5ef4e7a
Binary files /dev/null and b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-32.png differ
diff --git a/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-envoyer-24.png b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-envoyer-24.png
new file mode 100644 (file)
index 0000000..d2f7761
Binary files /dev/null and b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-envoyer-24.png differ
diff --git a/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-new-16.png b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-new-16.png
new file mode 100644 (file)
index 0000000..68dc0af
Binary files /dev/null and b/www/plugins/abomailmans/prive/themes/spip/images/abomailmans-new-16.png differ
diff --git a/www/plugins/abomailmans/svn.revision b/www/plugins/abomailmans/svn.revision
new file mode 100644 (file)
index 0000000..d7ef541
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/abomailmans/trunk
+Revision: 73175
+Dernier commit: 2013-06-01 20:43:16 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/abomailmans/trunk</origine>
+<revision>73175</revision>
+<commit>2013-06-01 20:43:16 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/abomailmans/templates/nouveautes.html b/www/plugins/abomailmans/templates/nouveautes.html
new file mode 100755 (executable)
index 0000000..31a071e
--- /dev/null
@@ -0,0 +1,67 @@
+#CACHE{0}[(#HTTP_HEADER{Content-type: text/html[; charset=(#CHARSET)]})]
+[(#REM)
+/**********************************************************
+* Ce squelette pour Abomailmains
+* Attention a :
+* - ne pas envoyer des gabarits de plus de 10Ko
+* - ne pas placer de balises d'ouverture ou de fermeture html et body
+* ils seront ajoutes automatiquement a l'envoi du mail
+* - mettre les style  CSS directement dans les balises pour etre sur qu'ils seront interpretes (meme par les webmails)
+* - les urls et liens images seront automatiquement converties en absolues
+*  ex. rubrique5.html -> http://www.monsite.org/rubrique5.html
+* Inspire du plugin Spip-Listes
+* $Id: nouveautes.html 59659 2012-03-23 14:00:11Z root $
+***********************************************************/]
+<B_articlesDate>
+<style>
+.nl_container a {
+       text-decoration:none;
+       color:#3996BB;}
+.nl_container a:hover {
+       color: #46839B;
+       text-decoration: underline;}
+</style>
+
+<div class="nl_container" style='width:100%;padding:10px;background-color:#FFF;color:#333333;font-size:12px;font-family:Georgia,"Times New Roman",Times,serif;'>
+<table width="690" border="0" align="center" cellpadding="0" cellspacing="5" bgcolor="#FFF">
+   <tr>
+      <td>
+       <h1><a href="#URL_SITE_SPIP">
+               [(#LOGO_SITE_SPIP||image_reduire{100,100}|inserer_attribut{style,'border:0;'}|sinon{#NOM_SITE_SPIP})]
+         </a></h1>
+         <BOUCLE_abomailman(ABOMAILMANS){id_abomailman}>#DESCRIPTIF</BOUCLE_abomailman>
+         </B_abomailman>
+            [<h2>(#ENV{sujet})</h2>]
+            [<p><b>(#ENV{message})</b></p>]
+         <//B_abomailman>
+                       <div style="border-bottom:1px solid #E00000;margin-bottom:1em;">&nbsp;</div>
+      </td>
+   </tr>
+   <BOUCLE_articlesDate(ARTICLES){age_relatif< 0}{id_rubrique ?}{id_mot ?}{par date}{inverse}>
+   <BOUCLE_agenda(MOTS){titre=AGENDA}{id_article}>#SET{type, agenda}</BOUCLE_agenda>
+   <tr>
+       <td>
+         [(#GET{type}|!={'agenda'}|?{'',' '}) <!-- SI agenda -->
+            [<div style="padding:0.2em;font-style:italic;">
+               [(#DATE_REDAC|nom_jour)] (#DATE_REDAC|affdate_jourcourt)[ - (#DATE_REDAC|affdate{'H:i'})]
+            </div>]
+         ]
+         [<h3>(#TITRE|textebrut|supprimer_numero)</h3>]
+         <!-- SI PAS agenda -->
+         [(#GET{type}|=={'agenda'}|?{'',' '})<p style="padding:0.2em;font-style:italic;">[(#DATE|affdate)]</p>]
+         <div><BOUCLE_ariane(HIERARCHIE){id_article}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a></BOUCLE_ariane></div>
+         <table width="100%" border="0" cellspacing="10"><tr>
+            <td valign="top">[<p style="text-align:justify;margin-top:0">(#INTRODUCTION|textebrut|liens_absolus)</p>]</td>
+            <td width="100" valign="top">
+               [(#LOGO_ARTICLE||image_reduire{100,100}|liens_absolus)]
+            </td>
+         </tr></table>
+         <a href="[(#URL_ARTICLE|url_absolue)]" style="float:right;padding:0 0 0 1em;margin:0.5em 0 0 0;"><:abomailmans:lire_article:></a>
+         <br style="clear: both; margin: 0; padding: 0; border: none; height: 0; line-height: 1px; font-size: 1px;" />
+         <div style="border-bottom:1px solid #E00000;margin-bottom:1em;">&nbsp;</div>
+      </td>
+   </tr>
+   </BOUCLE_articlesDate>
+</table>
+</div>
+</B_articlesDate>
diff --git a/www/plugins/abomailmans/templates/nouveautes.txt.html b/www/plugins/abomailmans/templates/nouveautes.txt.html
new file mode 100644 (file)
index 0000000..b31aee3
--- /dev/null
@@ -0,0 +1,38 @@
+#CACHE{0}[(#HTTP_HEADER{Content-type: text/plain[; charset=(#CHARSET)]})]\r
+[(#REM)\r
+/**********************************************************\r
+* Ce squelette pour Abomailmains\r
+* Attention a :\r
+* - ne pas envoyer des gabarits de plus de 10Ko\r
+* - les urls et liens images seront automatiquement converties en absolues\r
+*  ex. rubrique5.html -> http://www.monsite.org/rubrique5.html\r
+* Inspire du plugin Spip-Listes\r
+* $Id: nouveautes.html 44651 2011-02-14 10:33:12Z yffic@lefourneau.com $\r
+***********************************************************/]\r
+<B_articlesDate>\r
+\r
+<BOUCLE_abomailman(ABOMAILMANS){id_abomailman}>[(#DESCRIPTIF)]</BOUCLE_abomailman>\r
+</B_abomailman>\r
+[(#ENV{sujet})]\r
+[(#ENV{message})]\r
+<//B_abomailman>\r
+\r
+------------------------------------------------------------------------------\r
+<BOUCLE_articlesDate(ARTICLES){age_relatif< 0}{id_rubrique ?}{id_mot ?}{par date}{inverse}>\r
+<BOUCLE_agenda(MOTS){titre=AGENDA}{id_article}>#SET{type, agenda}</BOUCLE_agenda>\r
+[(#GET{type}|!={'agenda'}|?{'',' '})<!-- SI agenda -->\r
+   [[(#DATE_REDAC|nom_jour)] (#DATE_REDAC|affdate_jourcourt)[ - (#DATE_REDAC|affdate{'H:i'})]]\r
+]\r
+[(#TITRE|textebrut|supprimer_numero)]\r
+[(#GET{type}|=={'agenda'}|?{'',' '})[(#DATE|affdate)]]<!-- SI PAS agenda -->\r
+<BOUCLE_ariane(HIERARCHIE){id_article}> > [(#TITRE|couper{80})]</BOUCLE_ariane>\r
+[(#INTRODUCTION|textebrut|liens_absolus)]\r
+<:abomailmans:lire_article:> : [(#URL_ARTICLE|url_absolue)]\r
+\r
+------------------------------------------------------------------------------\r
+</BOUCLE_articlesDate>\r
+------------------------------------------------------------------------------\r
+\r
+[(#NOM_SITE_SPIP|textebrut)] (#URL_SITE_SPIP)\r
+</B_articlesDate>\r
+[(#FILTRE{supprimer_tags|filtrer_entites|trim})]
\ No newline at end of file
diff --git a/www/plugins/abomailmans/templates/nouveautes_fr_en.html b/www/plugins/abomailmans/templates/nouveautes_fr_en.html
new file mode 100644 (file)
index 0000000..24ce9dc
--- /dev/null
@@ -0,0 +1,98 @@
+#CACHE{0}[(#HTTP_HEADER{Content-type: text/html[; charset=(#CHARSET)]})]\r
+[(#REM)\r
+/**********************************************************\r
+* Ce squelette pour Abomailmains\r
+* Attention a :\r
+* - ne pas envoyer des gabarits de plus de 10Ko\r
+* - ne pas placer de balises d'ouverture ou de fermeture html et body\r
+* ils seront ajoutes automatiquement a l'envoi du mail\r
+* - mettre les style  CSS directement dans les balises pour etre sur qu'ils seront interpretes (meme par les webmails)\r
+* - les urls et liens images seront automatiquement converties en absolues\r
+*  ex. rubrique5.html -> http://www.monsite.org/rubrique5.html\r
+* Inspire du plugin Spip-Listes\r
+* $Id: nouveautes.html 44651 2011-02-14 10:33:12Z yffic@lefourneau.com $\r
+***********************************************************/]\r
+#SET{tableau_nouveautes,#ARRAY}\r
+<BOUCLE_articles(ARTICLES){id_rubrique ?}{id_mot ?}{age_relatif<0}>\r
+       #SET{tableau_nouveautes, #GET{tableau_nouveautes}|push{#ID_ARTICLE}}\r
+</BOUCLE_articles>\r
+\r
+<style>\r
+.nl_container a {\r
+       text-decoration:none;\r
+       color:#3996BB;}\r
+.nl_container a:hover {\r
+       color: #46839B;\r
+       text-decoration: underline;}\r
+</style>\r
+\r
+<div class="nl_container" style='width:100%;padding:5px;background-color:#FFF;color:#333333;font-size:10px;font-family:Arial, Helvetica, sans-serif'>\r
+<table width="800" border="0" align="center" cellpadding="0" cellspacing="5" bgcolor="#FFF">\r
+   <tr>\r
+      <td>\r
+       <h1><a href="#URL_SITE_SPIP">\r
+               [(#LOGO_SITE_SPIP||image_reduire{100,100}|inserer_attribut{style,'border:0;'}|sinon{#NOM_SITE_SPIP})]\r
+         </a></h1>\r
+      </td>\r
+   </tr>\r
+   <tr>\r
+      <td>\r
+         <table width="100%" border="0" cellspacing="10"><tr>\r
+            <td width="340" align="right" valign="top">\r
+               <BOUCLE_abomailman_fr(ABOMAILMANS){id_abomailman}>[(#DESCRIPTIF*|extraire_multi{fr}|propre)]</BOUCLE_abomailman_fr>\r
+               </B_abomailman_fr>\r
+                  [<h2>(#ENV*{sujet}|extraire_multi{fr})</h2>]\r
+                  [<p><b>(#ENV*{message}|extraire_multi{fr})</b></p>]\r
+               <//B_abomailman_fr>\r
+            </td>\r
+            <td width="100">&nbsp;</td>\r
+            <td valign="top" width="340">\r
+               <BOUCLE_abomailman_en(ABOMAILMANS){id_abomailman}>[(#DESCRIPTIF*|extraire_multi{en}|propre)]</BOUCLE_abomailman_en>\r
+               </B_abomailman_en>\r
+                  [<h2>(#ENV*{sujet}|extraire_multi{en})</h2>]\r
+                  [<p><b>(#ENV*{message}|extraire_multi{en})</b></p>]\r
+               <//B_abomailman_en>\r
+            </td>\r
+         </tr></table>\r
+         <div style="border-bottom:1px solid #E00000;margin-bottom:1em;">&nbsp;</div>\r
+      </td>\r
+   </tr>\r
+   <BOUCLE_articlesDate(ARTICLES){id_rubrique ?}{id_mot ?}{age_relatif<0}{par date}{inverse}>\r
+   <BOUCLE_test(CONDITION){si #ID_ARTICLE|=={#ID_TRAD}|ou{#GET{tableau_nouveautes}|find{#ID_TRAD}|non}}>\r
+   <tr>\r
+       <td>\r
+         <table width="100%" border="0" cellspacing="10"><tr>\r
+            <td valign="top" align="right" width="340">\r
+               <BOUCLE_traduction_fr(ARTICLES){traduction}{lang=fr}{doublons}>\r
+                  [<h3>(#TITRE|textebrut|supprimer_numero)</h3>]\r
+                  <div style="padding:0.2em;font-style:italic;">[(#DATE|affdate)]</div>\r
+                  <div>\r
+                     <BOUCLE_ariane_fr(HIERARCHIE){id_article}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE*|extraire_multi{fr}|supprimer_numero|couper{80})]</a></BOUCLE_ariane_fr>\r
+                  </div>\r
+                  [<p style="text-align:justify;margin-top:0">(#INTRODUCTION{150}|textebrut|liens_absolus)</p>\r
+                  <p><a href="[(#URL_ARTICLE|url_absolue)]">Lire l'article</a></p>]\r
+                  [(#SET{logo,#LOGO_ARTICLE||image_reduire{100,100}|liens_absolus})]\r
+               </BOUCLE_traduction_fr>\r
+            </td>\r
+            <td width="100" valign="top">\r
+               [(#GET{logo})]\r
+            </td>\r
+            <td valign="top" width="340">\r
+               <BOUCLE_traduction_en(ARTICLES){traduction}{lang=en}{doublons}>\r
+                  [<h3>(#TITRE|textebrut|supprimer_numero)</h3>]\r
+                  <div style="padding:0.2em;font-style:italic;">[(#DATE|affdate)]</div>\r
+                  <div>\r
+                     <BOUCLE_ariane_en(HIERARCHIE){id_article}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE*|extraire_multi{en}|supprimer_numero|couper{80})]</a></BOUCLE_ariane_en>\r
+                  </div>\r
+                  [<p style="text-align:justify;margin-top:0">(#INTRODUCTION{150}|textebrut|liens_absolus)</p>\r
+                  <p><a href="[(#URL_ARTICLE|url_absolue)]">Read the article</a></p>]\r
+               </BOUCLE_traduction_en>\r
+            </td>\r
+         </tr></table>\r
+         <div style="border-bottom:1px solid #E00000;margin-bottom:1em;">&nbsp;</div>\r
+      </td>\r
+   </tr>\r
+   </BOUCLE_test>\r
+   </BOUCLE_articlesDate>\r
+</table>\r
+</div>\r
diff --git a/www/plugins/abomailmans/templates/nouveautes_fr_en.txt.html b/www/plugins/abomailmans/templates/nouveautes_fr_en.txt.html
new file mode 100644 (file)
index 0000000..6d5987d
--- /dev/null
@@ -0,0 +1,58 @@
+#CACHE{0}[(#HTTP_HEADER{Content-type: text/plain[; charset=(#CHARSET)]})]\r
+[(#REM)\r
+/**********************************************************\r
+* Ce squelette pour Abomailmains\r
+* Attention a :\r
+* - ne pas envoyer des gabarits de plus de 10Ko\r
+* - les urls et liens images seront automatiquement converties en absolues\r
+*  ex. rubrique5.html -> http://www.monsite.org/rubrique5.html\r
+* Inspire du plugin Spip-Listes\r
+* $Id: nouveautes.html 44651 2011-02-14 10:33:12Z yffic@lefourneau.com $\r
+***********************************************************/]\r
+<B_articlesDateFr>\r
+\r
+<BOUCLE_abomailman_fr(ABOMAILMANS){id_abomailman}>[(#DESCRIPTIF*|extraire_multi{fr}|propre)]</BOUCLE_abomailman_fr>\r
+</B_abomailman_fr>\r
+[(#ENV*{sujet}|extraire_multi{fr})]\r
+[(#ENV*{message}|extraire_multi{fr})]\r
+<//B_abomailman_fr>\r
+\r
+------------------------------------------------------------------------------\r
+\r
+<BOUCLE_articlesDateFr(ARTICLES){id_rubrique ?}{id_mot ?}{age_relatif< 0}{lang=fr}{par date}{inverse}>\r
+[(#SURTITRE|textebrut|supprimer_numero) :]\r
+[(#TITRE|textebrut|supprimer_numero)]\r
+[(#DATE|affdate)]\r
+<BOUCLE_arianeFr(HIERARCHIE){id_article}> > [(#TITRE*|extraire_multi{fr}|couper{80})]</BOUCLE_arianeFr>\r
+[(#INTRODUCTION|textebrut|liens_absolus)]\r
+Lire l'article : [(#URL_ARTICLE|url_absolue)]\r
+------------------------------------------------------------------------------\r
+</BOUCLE_articlesDateFr>\r
+\r
+[(#NOM_SITE_SPIP*|extraire_multi{fr}|textebrut)] (#URL_SITE_SPIP)\r
+</B_articlesDateFr>\r
+\r
+##############################################################################\r
+<B_articlesDateEn>\r
+\r
+<BOUCLE_abomailman_en(ABOMAILMANS){id_abomailman}>[(#DESCRIPTIF*|extraire_multi{en}|propre)]</BOUCLE_abomailman_en>\r
+</B_abomailman_en>\r
+[(#ENV*{sujet}|extraire_multi{en})]\r
+[(#ENV*{message}|extraire_multi{en})]\r
+<//B_abomailman_en>\r
+\r
+------------------------------------------------------------------------------\r
+\r
+<BOUCLE_articlesDateEn(ARTICLES){id_rubrique ?}{id_mot ?}{age_relatif< 0}{lang=en}{par date}{inverse}>\r
+[(#SURTITRE|textebrut|supprimer_numero) :]\r
+[(#TITRE|textebrut|supprimer_numero)]\r
+[(#DATE|affdate)]\r
+<BOUCLE_arianeEn(HIERARCHIE){id_article}> > [(#TITRE*|extraire_multi{en}|couper{80})]</BOUCLE_arianeEn>\r
+[(#INTRODUCTION|textebrut|liens_absolus)]\r
+Read the article : [(#URL_ARTICLE|url_absolue)]\r
+------------------------------------------------------------------------------\r
+</BOUCLE_articlesDateEn>\r
+\r
+[(#NOM_SITE_SPIP*|extraire_multi{en}|textebrut)] (#URL_SITE_SPIP)\r
+</B_articlesDateEn>\r
+[(#FILTRE{supprimer_tags|filtrer_entites|trim})]
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/composition-vide.html b/www/plugins/compositions_v3/composition-vide.html
new file mode 100644 (file)
index 0000000..47c4874
--- /dev/null
@@ -0,0 +1,9 @@
+[(#REM)
+
+  Squelette
+  (c) Cedric Morin 2009
+  Distribue sous licence GPL
+
+       Un squelette qui ne produit rien.
+]
+#CACHE{3600*100}
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/compositions_administrations.php b/www/plugins/compositions_v3/compositions_administrations.php
new file mode 100644 (file)
index 0000000..20393d9
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+/*
+ * Plugin Compositions
+ * (c) 2007-2009 Cedric Morin
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+/**
+ * Upgrade des tables
+ * 
+ * @param string $nom_meta_base_version
+ * @param string $version_cible
+ */
+function compositions_upgrade($nom_meta_base_version,$version_cible){
+       include_spip('base/objets');
+       $tables_objets = array_keys(lister_tables_objets_sql());
+       $maj = array();
+       $maj['create'] = array();
+       foreach($tables_objets as $table){
+               $maj['create'][] = array('sql_alter',"TABLE $table ADD composition varchar(255) DEFAULT '' NOT NULL");
+               $maj['create'][] = array('sql_alter',"TABLE $table ADD composition_lock tinyint(1) DEFAULT 0 NOT NULL");
+       }
+       $maj['create'][] = array('sql_alter',"TABLE spip_rubriques ADD composition_branche_lock tinyint(1) DEFAULT 0 NOT NULL");
+
+       $maj['0.5.0'] = array();
+       foreach($tables_objets as $table){
+               $maj['0.5.0'][] = array('sql_alter',"TABLE $table ADD composition varchar(255) DEFAULT '' NOT NULL");
+               $maj['0.5.0'][] = array('sql_alter',"TABLE $table ADD composition_lock tinyint(1) DEFAULT 0 NOT NULL");
+       }
+       $maj['0.5.0'][] = array('sql_alter',"TABLE spip_rubriques ADD composition_branche_lock tinyint(1) DEFAULT 0 NOT NULL");
+
+       include_spip('base/upgrade');
+       maj_plugin($nom_meta_base_version, $version_cible, $maj);
+}
+
+/**
+ * Une fonction pour verifier que les champs sont bien sur tous les objets,
+ * appelee lors de la configuration
+ * (cas d'un nouvel objet ajoute apres l'install du plugin)
+ * 
+ * @return void
+ */
+function compositions_check_upgrade(){
+       include_spip('base/objets');
+       $tables_objets = array_keys(lister_tables_objets_sql());
+       $trouver_table = charger_fonction('trouver_table','base');
+       foreach($tables_objets as $table){
+               $desc = $trouver_table($table);
+               if (!isset($desc['field']['composition']))
+                       sql_alter("TABLE $table ADD composition varchar(255) DEFAULT '' NOT NULL");
+               if (!isset($desc['field']['composition_lock']))
+                       sql_alter("TABLE $table ADD composition_lock tinyint(1) DEFAULT 0 NOT NULL");
+       }
+}
+
+/**
+ * Desinstallation
+ *
+ * @param string $nom_meta_base_version
+ */
+function compositions_vider_tables($nom_meta_base_version) {
+       include_spip('inc/meta');
+       include_spip('base/abstract_sql');
+
+       include_spip('base/objets');
+       $tables_objets = array_keys(lister_tables_objets_sql());
+       foreach($tables_objets as $table){
+               sql_alter("TABLE $table DROP composition");
+               sql_alter("TABLE $table DROP composition_lock");
+       }
+       sql_alter("TABLE spip_rubriques DROP composition_branche_lock");
+
+       effacer_meta('compositions');
+       effacer_meta($nom_meta_base_version);
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/compositions_fonctions.php b/www/plugins/compositions_v3/compositions_fonctions.php
new file mode 100644 (file)
index 0000000..88dcd56
--- /dev/null
@@ -0,0 +1,451 @@
+<?php\r
+/**\r
+ * Plugin Compositions\r
+ * (c) 2007-2013 Cedric Morin\r
+ * Distribue sous licence GPL\r
+ * \r
+ * @package SPIP\Compositions\Fonctions\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+define('_COMPOSITIONS_MATCH','-([^0-9][^.]*)');\r
+\r
+/**\r
+ * Lister les objets actives par configuration\r
+ *\r
+ * @return array\r
+ */\r
+function compositions_objets_actives(){\r
+       static $config=null;\r
+       if (is_null($config)){\r
+               // lister les objets dont on a active la composition dans la configuration\r
+               $config = isset($GLOBALS['meta']['compositions']) ? unserialize($GLOBALS['meta']['compositions']) : array();\r
+               $config = (isset($config['objets'])?$config['objets']:array('spip_articles','spip_rubriques'));\r
+               $config = array_map('objet_type',$config);\r
+       }\r
+       return $config;\r
+}\r
+\r
+/**\r
+ * Retrouver le nom du dossier ou sont stockees les compositions\r
+ * reglage par defaut, ou valeur personalisee via cfg\r
+ * \r
+ * @return string\r
+ */\r
+function compositions_chemin(){\r
+       $config_chemin = 'compositions/';\r
+       if (defined('_DIR_PLUGIN_Z') OR defined('_DIR_PLUGIN_ZCORE'))\r
+               $config_chemin = (isset($GLOBALS['z_blocs'])?reset($GLOBALS['z_blocs']):'contenu').'/';\r
+\r
+       elseif (isset($GLOBALS['meta']['compositions'])){\r
+               $config = unserialize($GLOBALS['meta']['compositions']);\r
+               if (isset ($config['chemin_compositions'])){\r
+                       $config_chemin = rtrim($config['chemin_compositions'],'/').'/';\r
+               }\r
+       }\r
+       \r
+       return $config_chemin;\r
+}\r
+\r
+/**\r
+ * Tester si la stylisation auto est activee\r
+ * @return string\r
+ */\r
+function compositions_styliser_auto(){\r
+       $config_styliser = true;\r
+       if (defined('_DIR_PLUGIN_Z') OR defined('_DIR_PLUGIN_ZCORE')){\r
+               $config_styliser = false; // Z s'occupe de styliser les compositions\r
+       }\r
+       elseif (isset($GLOBALS['meta']['compositions'])){\r
+               $config = unserialize($GLOBALS['meta']['compositions']);\r
+               $config_styliser = $config['styliser_auto'] != 'non';\r
+       }\r
+       return $config_styliser?' ':'';\r
+}\r
+\r
+/**\r
+ * Lister les compositions disponibles : toutes ou pour un type donne\r
+ * Si informer est a false, on ne charge pas les infos du xml\r
+ *\r
+ * @param string $type\r
+ * @param bool $informer\r
+ * @return array\r
+ */\r
+function compositions_lister_disponibles($type, $informer=true){\r
+       include_spip('inc/compositions');\r
+       $type_match = "";\r
+       if (strlen($type)){\r
+               $type = objet_type($type); // securite\r
+               $type_match = $type;\r
+       }\r
+       else {\r
+               $type_match = "[a-z0-9]+";\r
+       }\r
+\r
+       // rechercher les skel du type article-truc.html\r
+       // truc ne doit pas commencer par un chiffre pour eviter de confondre avec article-12.html\r
+       $match = "/($type_match)("._COMPOSITIONS_MATCH.")?[.]html$";\r
+\r
+       // lister les compositions disponibles\r
+       $liste = find_all_in_path(compositions_chemin(),$match);\r
+       $res = array();\r
+       if (count($liste)){\r
+               foreach($liste as $s) {\r
+                       $base = preg_replace(',[.]html$,i','',$s);\r
+                       if (preg_match(",$match,ims",$s,$regs)\r
+                         AND ($composition = !$informer\r
+                               OR $composition = compositions_charger_infos($base)))\r
+                               $res[$regs[1]][$regs[3]] = $composition;\r
+                       // retenir les skels qui ont un xml associe\r
+               }\r
+       }\r
+       // Pipeline compositions_lister_disponibles\r
+       $res = pipeline('compositions_lister_disponibles',array(\r
+               'args'=>array('type' => $type,'informer' => $informer), \r
+               'data'=> $res\r
+               )\r
+       );\r
+       return $res;\r
+}\r
+\r
+/**\r
+ * Liste les id d'un type donne utilisant une composition donnee\r
+ *\r
+ * @param string $type\r
+ * @param string $composition\r
+ * @return array\r
+ */\r
+function compositions_lister_utilisations($type,$composition){\r
+       $table_sql = table_objet_sql($type);\r
+       if (!in_array($table_sql, sql_alltable())) return;\r
+       $_id_table_objet = id_table_objet($type);\r
+       return sql_allfetsel("$_id_table_objet as id,titre", $table_sql, "composition=".sql_quote($composition));\r
+}\r
+\r
+/**\r
+ * Selectionner le fond en fonction du type et de la composition\r
+ * en prenant en compte la configuration pour le chemin\r
+ * et le fait que la composition a pu etre supprimee\r
+ *\r
+ * @param string $composition\r
+ * @param string $type\r
+ * @param string $defaut\r
+ * @param string $ext\r
+ * @param bool $fullpath\r
+ * @param string $vide\r
+ * @return string\r
+ */\r
+function compositions_selectionner($composition,$type,$defaut="",$ext="html",$fullpath = false, $vide="composition-vide"){\r
+       if ($type=='syndic') $type='site'; //grml\r
+       $fond = compositions_chemin() . $type;\r
+\r
+       // regarder si compositions/article-xxx est disponible\r
+       if (strlen($composition)\r
+               AND $f = find_in_path("$fond-$composition.$ext"))\r
+               return $fullpath ? $f : $fond . "-$composition";\r
+       else\r
+               // sinon regarder si compositions/article-defaut est disponible\r
+               if (strlen($defaut)\r
+                       AND $f = find_in_path("$fond-$defaut.$ext"))\r
+                       return $fullpath ? $f : $fond . "-$defaut";\r
+\r
+       // se rabattre sur compositions/article si disponible\r
+       if ($f = find_in_path("$fond.$ext"))\r
+               return $fullpath ? $f : $fond;\r
+\r
+       // sinon une composition vide pour ne pas generer d'erreur\r
+       if ($vide AND $f = find_in_path("$vide.$ext"))\r
+               return $fullpath ? $f : $vide;\r
+\r
+       // rien mais ca fera une erreur dans le squelette si appele en filtre\r
+       return '';\r
+}\r
+\r
+/**\r
+ * Decrire une composition pour un objet\r
+ * @param string $type\r
+ * @param string $composition\r
+ * @return array|bool|string\r
+ */\r
+function compositions_decrire($type, $composition){\r
+       static $compositions = array();\r
+       if (!function_exists('compositions_charger_infos'))\r
+               include_spip('inc/compositions');\r
+       if ($type=='syndic') $type='site'; //grml\r
+       if (isset($compositions[$type][$composition]))\r
+               return $compositions[$type][$composition];\r
+       $ext = "html";\r
+       $fond = compositions_chemin() . $type;\r
+       if (strlen($composition)\r
+               AND $f = find_in_path("$fond-$composition.$ext")\r
+               AND $desc = compositions_charger_infos($f))\r
+               return $compositions[$type][$composition] = $desc;\r
+       return $compositions[$type][$composition] = false;\r
+}\r
+\r
+/**\r
+ * Un filtre a utiliser sur [(#COMPOSITION|composition_class{#ENV{type}})]\r
+ * pour poser des classes generiques sur le <body>\r
+ * si une balise <class>toto</class> est definie dans la composition c'est elle qui est appliquee\r
+ * sinon on pose simplement le nom de la composition\r
+ * \r
+ * @param string $composition\r
+ * @param string $type\r
+ * @return string\r
+ */\r
+function composition_class($composition,$type){\r
+       if ($desc = compositions_decrire($type, $composition)\r
+               AND isset($desc['class'])\r
+               AND strlen($desc['class']))\r
+               return $desc['class'];\r
+       return $composition;\r
+}\r
+\r
+/**\r
+ * Liste les types d'objets qui ont une composition ET sont autorises par la configuration\r
+ * utilise la valeur en cache meta sauf si demande de recalcul\r
+ * ou pas encore definie\r
+ *\r
+ * @staticvar array $liste\r
+ * @return array\r
+ */\r
+function compositions_types(){\r
+       static $liste = null;\r
+       if (is_null($liste)) {\r
+               if (_VAR_MODE OR !isset($GLOBALS['meta']['compositions_types'])){\r
+                       include_spip('inc/compositions');\r
+                       compositions_cacher();\r
+               }\r
+               $liste = explode(',',$GLOBALS['meta']['compositions_types']);\r
+       }\r
+       return $liste;\r
+}\r
+\r
+/**\r
+ * Renvoie les parametres necessaires pour utiliser l'heritage de composition de façon generique\r
+ * recupere les donnes du pipeline compositions_declarer_heritage.\r
+ * Si $type n'est pas precise, on renvoie simplement le tableau des objets pouvant heriter.\r
+ * \r
+ * @param string $type\r
+ * @staticvar array $heritages\r
+ * @return array\r
+ */\r
+function compositions_recuperer_heritage($type=NULL){\r
+       static $heritages = NULL;\r
+       if (is_null($heritages)) // recuperer les heritages declares via le pipeline compositions_declarer_heritage\r
+               $heritages = pipeline('compositions_declarer_heritage', array());\r
+       \r
+       if (is_null($type))\r
+               return $heritages;\r
+\r
+       if (array_key_exists($type, $heritages)) {\r
+               $type_parent = $heritages[$type];\r
+               $table_parent =  table_objet_sql($type_parent);\r
+               $nom_id_parent = ($type==$type_parent) ? 'id_parent' : id_table_objet($type_parent); // Recursivite pour les rubriques, nom de l'identifiant du parent dans la table enfant\r
+               $nom_id_table_parent = id_table_objet($type_parent); // Nom de l'identifiant du parent dans la table parent\r
+               \r
+               // verifier que table et champs existent...\r
+               $trouver_table = charger_fonction('trouver_table', 'base');\r
+               if (!$type_parent\r
+                       OR !$desc = $trouver_table($table_parent)\r
+                       OR !isset($desc['field']['composition'])\r
+                       OR !isset($desc['field'][$nom_id_parent]))\r
+                       return '';\r
+\r
+               return array(\r
+                       'type_parent' => $type_parent,\r
+                       'table_parent' => $table_parent,\r
+                       'nom_id_parent' => $nom_id_parent,\r
+                       'nom_id_table_parent' => $nom_id_table_parent\r
+               );\r
+       }\r
+       return array();\r
+}\r
+\r
+/**\r
+ * Renvoie la composition qui s'applique a un objet\r
+ * en tenant compte, le cas echeant, de la composition heritee\r
+ * si etoile=true on renvoi directment le champ sql\r
+ *\r
+ * @param string $type\r
+ * @param integer $id\r
+ * @param string $serveur\r
+ * @param bool $etoile\r
+ * @return string\r
+ */\r
+function compositions_determiner($type, $id, $serveur='', $etoile = false){\r
+       static $composition = array();\r
+       $id = intval($id);\r
+       \r
+       if (isset($composition[$etoile][$serveur][$type][$id]))\r
+               return $composition[$etoile][$serveur][$type][$id];\r
+\r
+       include_spip('base/abstract_sql');\r
+       $table = table_objet($type);\r
+       $table_sql = table_objet_sql($type);\r
+       $_id_table = id_table_objet($type);\r
+\r
+       $retour = '';\r
+\r
+       $trouver_table = charger_fonction('trouver_table', 'base');\r
+       $desc = $trouver_table($table,$serveur);\r
+       if (isset($desc['field']['composition']) AND $id){\r
+               $select = "composition";\r
+\r
+       $heritage = compositions_recuperer_heritage($type);\r
+       if (isset($desc['field'][$heritage['nom_id_parent']]))\r
+               $select .= ', '.$heritage['nom_id_parent'].' as id_parent';\r
+\r
+       $row = sql_fetsel($select, $table_sql, "$_id_table=".intval($id), '', '', '', '', $serveur);\r
+       if ($row['composition'] != '')\r
+               $retour = $row['composition'];\r
+       elseif (!$etoile\r
+         AND isset($row['id_parent'])\r
+         AND $row['id_parent'])\r
+               $retour = compositions_heriter($type, $id, $row['id_parent'], $serveur);\r
+       }\r
+       return $composition[$etoile][$serveur][$type][$id] = (($retour == '-') ? '' : $retour);\r
+}\r
+\r
+/**\r
+ * Renvoie la composition heritee par un objet selon son identifiant.\r
+ * Optionnellement, on peut lui transmettre directement l'id du parent s'il a ate calcule.\r
+ *\r
+ * @param string $type\r
+ * @param integer $id\r
+ * @param integer $id_parent\r
+ * @param string $serveur\r
+ * @return string\r
+ */\r
+function compositions_heriter($type, $id, $id_parent=NULL, $serveur=''){\r
+       if ($type=='syndic') $type='site'; //grml\r
+       if (intval($id) < 1) return '';\r
+       static $infos = null;\r
+       $compo_parent = '';\r
+       \r
+       $heritage = compositions_recuperer_heritage($type);\r
+       $type_parent = $heritage['type_parent'];\r
+       $table_parent = $heritage['table_parent'];\r
+       $nom_id_parent = $heritage['nom_id_parent'];\r
+       $nom_id_table_parent = $heritage['nom_id_table_parent'];\r
+       \r
+       if (is_null($id_parent))\r
+               $id_parent = sql_getfetsel($nom_id_parent, table_objet_sql($type), id_table_objet($type).'='.intval($id));\r
+       \r
+       $heritages = compositions_recuperer_heritage();\r
+       \r
+       do {\r
+               $select = 'composition';\r
+               if ($heritages[$type_parent]==$type_parent) // S'il y a recursivite sur le parent\r
+                       $select .= ', id_parent';\r
+               $row = sql_fetsel($select, $table_parent, $nom_id_table_parent.'='.intval($id_parent),'','','','',$serveur);\r
+               if (strlen($row['composition']) AND $row['composition']!='-')\r
+                       $compo_parent = $row['composition'];\r
+               elseif (strlen($row['composition'])==0 AND isset($heritages[$type_parent])) // Si le parent peut heriter, il faut verifier s'il y a heritage\r
+                       $compo_parent = compositions_determiner($type_parent, $id_parent, $serveur='');\r
+               \r
+               if (strlen($compo_parent) AND is_null($infos))\r
+                       $infos = compositions_lister_disponibles('');\r
+                       \r
+       }\r
+       while ($id_parent = $row['id_parent']\r
+               AND\r
+               (!strlen($compo_parent) OR !isset($infos[$type_parent][$compo_parent]['branche'][$type])));\r
+\r
+       if (strlen($compo_parent) AND isset($infos[$type_parent][$compo_parent]['branche'][$type]))\r
+               return $infos[$type_parent][$compo_parent]['branche'][$type];\r
+\r
+       return '';\r
+}\r
+\r
+/**\r
+ * #COMPOSITION\r
+ * Renvoie la composition s'appliquant a un objet\r
+ * en tenant compte, le cas echeant, de l'heritage.\r
+ *\r
+ * Sans precision, l'objet et son identifiant sont pris\r
+ * dans la boucle en cours, mais l'on peut specifier notre recherche\r
+ * en passant objet et id_objet en argument de la balise :\r
+ * #COMPOSITION{article, 8}\r
+ *\r
+ * #COMPOSITION* renvoie toujours le champs brut, sans tenir compte de l'heritage\r
+ *\r
+ * @param array $p     AST au niveau de la balise\r
+ * @return array       AST->code modifie pour calculer le nom de la composition\r
+ */\r
+function balise_COMPOSITION_dist($p) {\r
+       $_composition = "";\r
+       if ($_objet = interprete_argument_balise(1, $p)) {\r
+               $_id_objet = interprete_argument_balise(2, $p);\r
+       } else {\r
+               $_composition = champ_sql('composition',$p);\r
+               $_id_objet = champ_sql($p->boucles[$p->id_boucle]->primary, $p);\r
+               $_objet = "objet_type('" . $p->boucles[$p->id_boucle]->id_table . "')";\r
+       }\r
+       // si on veut le champ brut, et qu'on l'a sous la main, inutile d'invoquer toute la machinerie\r
+       if ($_composition AND $p->etoile)\r
+               $p->code = $_composition;\r
+       else {\r
+               $connect = $p->boucles[$p->id_boucle]->sql_serveur;\r
+               $p->code = "compositions_determiner($_objet, $_id_objet, '$connect', ".($p->etoile?'true':'false').")";\r
+               // ne declencher l'usine a gaz que si composition est vide ...\r
+               if ($_composition)\r
+                       $p->code = "((\$zc=$_composition)?(\$zc=='-'?'':\$zc):".$p->code.")";\r
+       }\r
+       return $p;\r
+}\r
+\r
+/**\r
+ * Indique si la composition d'un objet est verrouillee ou non,\r
+ * auquel cas, seul le webmaster peut la modifier\r
+ *\r
+ * @param string $type\r
+ * @param integer $id\r
+ * @param string $serveur\r
+ * @return string\r
+ */\r
+function compositions_verrouiller($type, $id, $serveur=''){\r
+       $config = unserialize($GLOBALS['meta']['compositions']);\r
+       if (isset($config['tout_verrouiller']) AND $config['tout_verrouiller'] == 'oui')\r
+               return true;\r
+       \r
+       include_spip('base/abstract_sql');\r
+       $table = table_objet($type);\r
+       $table_sql = table_objet_sql($type);\r
+       $_id_table = id_table_objet($type);\r
+\r
+       $trouver_table = charger_fonction('trouver_table', 'base');\r
+       $desc = $trouver_table($table,$serveur);\r
+       if (isset($desc['field']['composition_lock']) AND $id){\r
+               $lock = sql_getfetsel('composition_lock', $table_sql, "$_id_table=".intval($id), '', '', '', '', $serveur);\r
+               if ($lock)\r
+                       return true;\r
+               elseif (isset($desc['field']['id_rubrique'])) {\r
+                       $id_rubrique = sql_getfetsel('id_rubrique', $table_sql, "$_id_table=".intval($id), '', '', '', '', $serveur);\r
+                       return compositions_verrou_branche($id_rubrique, $serveur);\r
+               }\r
+               else\r
+                       return false;\r
+       }\r
+       else return false;\r
+}\r
+\r
+/**\r
+ * Indique si les objets d'une branche sont verrouilles\r
+ * @param integer $id_rubrique\r
+ * @param string $serveur\r
+ * @return string\r
+ */\r
+function compositions_verrou_branche($id_rubrique, $serveur=''){\r
+       \r
+       if (intval($id_rubrique) < 1) return false;\r
+       if($infos_rubrique = sql_fetsel(array('id_parent','composition_branche_lock'),'spip_rubriques','id_rubrique='.intval($id_rubrique),'','','','',$serveur)) {\r
+               if ($infos_rubrique['composition_branche_lock'])\r
+                       return true;\r
+               else\r
+                       return compositions_verrou_branche($infos_rubrique['id_parent'],$serveur);\r
+       }\r
+       return '';\r
+}\r
+?>\r
diff --git a/www/plugins/compositions_v3/compositions_ieconfig.php b/www/plugins/compositions_v3/compositions_ieconfig.php
new file mode 100644 (file)
index 0000000..ea5c520
--- /dev/null
@@ -0,0 +1,14 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+// On déclare ici la config du core\r
+function compositions_ieconfig_metas($table){\r
+       $table['compositions']['titre'] = _T('compositions:compositions');\r
+       $table['compositions']['icone'] = 'composition-16.png';\r
+       $table['compositions']['metas_serialize'] = 'compositions';\r
+       \r
+       return $table;\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/compositions_pipeline.php b/www/plugins/compositions_v3/compositions_pipeline.php
new file mode 100644 (file)
index 0000000..32584c6
--- /dev/null
@@ -0,0 +1,144 @@
+<?php\r
+/*\r
+ * Plugin Compositions\r
+ * (c) 2007-2009 Cedric Morin\r
+ * Distribue sous licence GPL\r
+ *\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * Declaration des champs sur les objets\r
+ *\r
+ * @param array $tables\r
+ * @return array\r
+ */\r
+function compositions_declarer_tables_objets_sql($tables){\r
+\r
+       // champs composition et composition_lock sur tous les objets\r
+       // c'est easy\r
+       $tables[]['field']['composition'] = "varchar(255) DEFAULT '' NOT NULL";\r
+       $tables[]['field']['composition_lock'] = "tinyint(1) DEFAULT 0 NOT NULL";\r
+       $tables['spip_rubriques']['field']['composition_branche_lock'] = "tinyint(1) DEFAULT 0 NOT NULL";\r
+\r
+       return $tables;\r
+}\r
+\r
+\r
+/**\r
+ * Fonction vide pour le pipeline homonyme\r
+ */\r
+function compositions_autoriser(){}\r
+\r
+/**\r
+ * Autorisation de modifier la composition\r
+ *\r
+ * @param string $faire\r
+ * @param string $type\r
+ * @param int $id\r
+ * @param array $qui\r
+ * @param array $opt\r
+ * @return bool\r
+ */\r
+function autoriser_styliser_dist($faire, $type='', $id=0, $qui = NULL, $opt = NULL){\r
+       include_spip('compositions_fonctions');\r
+       if (!autoriser('modifier',$type,$id,$qui,$opt))\r
+               return false;\r
+       if (compositions_verrouiller($type, $id) AND !autoriser('webmestre'))\r
+               return false;\r
+       return true;\r
+}\r
+\r
+\r
+/**\r
+ * Pipeline styliser pour definir le fond d'un objet en fonction de sa composition\r
+ *\r
+ * @param array $flux\r
+ * @return array\r
+ */\r
+function compositions_styliser($flux){\r
+       include_spip('compositions_fonctions');\r
+       // en contexte Z, c'est Z ou Z-core qui stylise (on ne n'en occupe donc pas ici)\r
+       if (compositions_styliser_auto() AND !defined('_DIR_PLUGIN_Z') AND !defined('_DIR_PLUGIN_ZCORE')){\r
+               $type = $flux['args']['fond']; // on fait l'approximation fond=type\r
+               // si le type n'est pas l'objet d'une composition, ne rien faire\r
+               if (in_array($type,compositions_types())){\r
+                       $contexte = isset($flux['args']['contexte'])?$flux['args']['contexte']:$GLOBALS['contexte'];\r
+                       $serveur = $flux['args']['connect'];\r
+\r
+                       $ext = $flux['args']['ext'];\r
+                       $_id_table = id_table_objet($type);\r
+\r
+                       if ($id = $contexte[$_id_table] AND $composition = compositions_determiner($type,$id,$serveur)){\r
+                               if ($fond = compositions_selectionner($composition, $type, '', $ext, true, "")){\r
+                                       $flux['data'] = substr($fond, 0, - strlen(".$ext"));\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       return $flux;\r
+}\r
+\r
+/**\r
+ * Affichage du formulaire de selection de la composition\r
+ *\r
+ * @param array $flux\r
+ * @return array\r
+ */\r
+function compositions_affiche_milieu($flux){\r
+       $e = trouver_objet_exec($flux['args']['exec']);\r
+       $objets = compositions_objets_actives();\r
+       if (in_array($e['type'],$objets)\r
+         AND $e['edition']===false){\r
+               $type = $e['type'];\r
+               if ($id = $flux['args'][$e['id_table_objet']]) {\r
+                       $config = unserialize($GLOBALS['meta']['compositions']);\r
+                       $aut = autoriser('styliser',$type,$id);\r
+                       if ((!isset($config['masquer_formulaire']) OR $config['masquer_formulaire'] != 'oui' OR $aut)\r
+                               AND (\r
+                                       ($c=compositions_lister_disponibles($type) AND is_array(reset($c)))\r
+                                       OR ($type == 'rubrique' AND (!isset($config['tout_verrouiller']) OR $config['tout_verrouiller'] != 'oui'))\r
+                                 )\r
+                               ) {\r
+                               $ids = 'formulaire_editer_composition_objet-' . "$type-$id";\r
+                               $texte = recuperer_fond(\r
+                                       'prive/editer/compositions',\r
+                                       array(\r
+                                               'type'=>$type,\r
+                                               'id'=>$id,\r
+                                       )\r
+                               );\r
+\r
+                               if (($p = strpos($flux['data'],'<!--affiche_milieu-->'))!==false)\r
+                                       $flux['data'] = substr_replace($flux['data'],$texte,$p,0);\r
+                               else\r
+                                       $flux['data'] .= $texte;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return $flux;\r
+}\r
+\r
+/**\r
+ * Le pipeline compositions_declarer_heritage permet de declarer les heritages\r
+ * sous la forme :\r
+ *             $heritages['objet'] = 'parent';\r
+ * ce qui permet ensuite de faire dans le fichier parent-ma_compo.xml\r
+ * <branche type="objet" composition="une_compo" />\r
+ * \r
+ * A partir de compositions 3.3.0 cette declaration est obligatoire.\r
+ * Les objets "standards" de SPIP sont declares ici. (a deplacer dans leurs plugins respectifs ?)\r
+ */\r
+function compositions_compositions_declarer_heritage($heritages){\r
+       $heritages['mot'] = 'groupe_mots';\r
+       $heritages['rubrique'] = 'rubrique';\r
+       $heritages['article'] = 'rubrique';\r
+       $heritages['breve'] = 'rubrique';\r
+       $heritages['site'] = 'rubrique';\r
+       return $heritages;\r
+}\r
+\r
+\r
+?>\r
diff --git a/www/plugins/compositions_v3/formulaires/configurer_compositions.html b/www/plugins/compositions_v3/formulaires/configurer_compositions.html
new file mode 100644 (file)
index 0000000..f43a62d
--- /dev/null
@@ -0,0 +1,49 @@
+<div class='formulaire_spip formulaire_configurer formulaire_configurer_forums_contenu' id='formulaire_configurer_forums_contenu'>
+<h3 class='titrem'><:compositions:compositions:></h3>
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+       <form method="post" action="#SELF"><div>
+               #ACTION_FORMULAIRE
+               <ul>
+                       #SET{name,objets}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
+                       <li class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
+                               <label><:compositions:label_activer_composition_objets:></label>[
+                               <span class='erreur_message'>(#GET{erreurs})</span>
+                               ]
+                               #INCLURE{fond=formulaires/inc-choisir-objets,name=#GET{name},selected=#ENV**{#GET{name},#LISTE{spip_articles,spip_rubriques}}}
+                       </li>
+
+                       <li class='configurer_chemin_compositions'>
+                               <label for="chemin_compositions"><:compositions:label_chemin_compositions:></label>
+                               [(#PLUGIN{z}|ou{#PLUGIN{zcore}}|non)<div class='explication'><:compositions:label_chemin_compositions_details:></div>]
+                               <input type="text" name="chemin_compositions" value="[(#REM|compositions_chemin|entites_html)]" id="chemin_compositions" class="text" [(#PLUGIN{z}|ou{#PLUGIN{zcore}}|oui)disabled="true"] />
+                       </li>
+                       [(#PLUGIN{z}|ou{#PLUGIN{zcore}}|non)<li class='configurer_styliser_auto'>
+                               <label><:compositions:label_styliser:></label>
+                               <div class="choix">
+                                       <input type="checkbox" name="styliser_auto" [checked="(#ENV{styliser_auto}|=={non}|?{checked})"] id="styliser_auto" value='non' />
+                                       <label for="styliser_auto"><:compositions:label_styliser_auto:></label>
+                               </div>
+                       </li>
+                       ]
+                       <li class='configurer_masquer_formulaire'>
+                               <label><:compositions:label_masquer_formulaire:></label>
+                               <div class="choix">
+                                       <input type="checkbox" name="masquer_formulaire" [checked="(#ENV{masquer_formulaire}|=={oui}|?{checked})"] id="masquer_formulaire" value='oui' />
+                                       <label for="masquer_formulaire"><:compositions:label_masquer_formulaire_composition:></label>
+                               </div>
+                       </li>
+                       <li class='configurer_tout_verrouiller'>
+                               <label><:compositions:label_tout_verrouiller:></label>
+                               <div class="choix">
+                                       <input type="checkbox" name="tout_verrouiller" [checked="(#ENV{tout_verrouiller}|=={oui}|?{checked})"] id="tout_verrouiller" value='oui' />
+                                       <label for="tout_verrouiller"><:compositions:label_verrouiller_toutes_compositions:></label>
+                               </div>
+                       </li>
+               </ul>
+               <p class='boutons'><input class='submit' type="submit" name="_cfg_ok" value="<:bouton_enregistrer:>" /></p>
+       </div></form>
+
+</div>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/formulaires/configurer_compositions_fonctions.php b/www/plugins/compositions_v3/formulaires/configurer_compositions_fonctions.php
new file mode 100644 (file)
index 0000000..99d8f57
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+/*
+ * Plugin Compositions
+ * (c) 2007-2009 Cedric Morin
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('compositions_administrations');
+compositions_check_upgrade();
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/formulaires/editer_composition_objet.html b/www/plugins/compositions_v3/formulaires/editer_composition_objet.html
new file mode 100644 (file)
index 0000000..959bcd5
--- /dev/null
@@ -0,0 +1,105 @@
+<div class="formulaire_spip formulaire_#FORM formulaire_#FORM-#ENV{objet}-#ENV{id,nouveau}">\r
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+       [(#ENV{editable})\r
+       <form method='post' action='#ENV{action}'><div>\r
+               [(#REM) declarer les hidden qui declencheront le service du formulaire\r
+               parametre : url d'action ]\r
+               #ACTION_FORMULAIRE{#ENV{action}}\r
+       ]\r
+       <h4[\r
+               style="background-image: url((#ENV{_compositions}|table_valeur{#ENV{composition}}|table_valeur{icon}|image_reduire{24,24}|extraire_attribut{src}))"][\r
+               title="(#ENV{_compositions}|table_valeur{#ENV{composition}}|table_valeur{description}|attribut_html)"]>\r
+               <:compositions:composition_utilisee:>\r
+                       <span class="composition_actuelle">[(#ENV{composition}|oui)[(#ENV{_compositions}|table_valeur{#ENV{composition}}|table_valeur{nom}|supprimer_numero|sinon{#ENV{composition}})]\r
+                       ][(#ENV{composition}|non)\r
+                               [(#ENV{composition_heritee}|oui)\r
+                                       [(#ENV{composition_heritee}|=={'-'}|oui)<:compositions:composition_defaut:>]\r
+                                       [(#ENV{composition_heritee}|!={'-'}|oui)[(#ENV{_compositions}|table_valeur{''}|table_valeur{nom}|supprimer_numero|sinon{#ENV{composition_heritee}})]]\r
+                                       <span class="precision">(<:compositions:composition_heritee:>)</span>\r
+                               ]\r
+                               [(#ENV{composition_heritee}|non)<:compositions:composition_defaut:>]\r
+                       ][(#ENV{composition_verrouillee}|oui) <img src="#CHEMIN_IMAGE{cadenas-16.png}" alt="" />]\r
+                       </span>\r
+       </h4>\r
+       [(#ENV{editable})\r
+       <span class="toggle_box_link" style="display:none;">&#91;<a href="#"\r
+                       onclick="var f=jQuery(this).parents('form').eq(0);f.find('p').show('fast');f.find('ul').show('fast');f.find('.toggle_box_link').hide('fast');return false;"\r
+                       ><:bouton_changer:></a>&#93;</span>\r
+       ]\r
+       <div class="detail">\r
+               [(#ENV{composition_verrouillee}|oui)<p><:compositions:composition_verrouillee:></p>]\r
+               <B_heritages><p><:compositions:heritages:> <BOUCLE_heritages(POUR){tableau #ENV{_compositions}|table_valeur{#ENV{composition}}|table_valeur{branche}}{', '}>#CLE (#VALEUR)</BOUCLE_heritages>.</p></B_heritages>\r
+       </div>\r
+\r
+       [(#ENV{editable})\r
+       <ul>\r
+               #SET{fl,compositions}\r
+               #SET{name,composition}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}#SET{obli,''}\r
+               [<li class="editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">\r
+                       <label>[(#GET{fl}|concat{':label_',#GET{name}}|_T)]</label>\r
+                               [<span class='erreur_message'>(#GET{erreurs})</span>]\r
+                               (#INCLURE{fond=formulaires/inc-selecteur_composition}{name=#GET{name}}{id=#GET{name}}{id_rubrique}{selected=#ENV{#GET{name}}}{_compositions}{composition_heritee})\r
+               </li>]\r
+               \r
+               #SET{lock,''}\r
+               [(#AUTORISER{webmestre}|et{#ENV{verrou_branche}|non}|et{#CONFIG{compositions/tout_verrouiller}|non}|oui)\r
+                       #SET{name,composition_lock}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}#SET{obli,''}\r
+                       <li class="editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">\r
+                               [<span class='erreur_message'>(#GET{erreurs})</span>]\r
+                               <label><:compositions:label_composition_explication:></label>\r
+                               [(#ENV{_compositions}|is_array|oui)\r
+                               <div class="choix">\r
+                                       <input type="checkbox" class="checkbox" name="#GET{name}" value="1" id="#GET{name}"[ (#ENV{#GET{name}}|oui)checked="checked"] />\r
+                                       <label for="#GET{name}">[(#GET{fl}|concat{':label_',#GET{name}}|_T)]</label>\r
+                               </div>\r
+                               ]\r
+                               [(#ENV{_compositions}|is_array|non)<input type="hidden" name="composition_lock" id="composition_lock" value="#ENV{composition_lock}" />]\r
+                               [(#ENV{objet}|=={rubrique}|oui)\r
+                               #SET{name,composition_branche_lock}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}#SET{obli,''}\r
+                                       [<span class='erreur_message'>(#GET{erreurs})</span>]\r
+                                       <div class="choix">\r
+                                               <input type="checkbox" class="checkbox" name="#GET{name}" value="1" id="#GET{name}"[ (#ENV{#GET{name}}|oui)checked="checked"] />\r
+                                               <label for="#GET{name}">[(#GET{fl}|concat{':label_',#GET{name}}|_T)]</label>\r
+                                       </div>\r
+                               ]\r
+                       </li>\r
+                       #SET{lock,'oui'}\r
+               ]\r
+               [(#ENV{verrou_branche}|oui)\r
+               <li>\r
+                       <label><:compositions:label_information:></label>\r
+                       <:compositions:label_branche_verrouillee:>\r
+               </li>\r
+               ]\r
+               [(#CONFIG{compositions/tout_verrouiller}|oui)\r
+               <li>\r
+                       <label><:compositions:label_information:></label>\r
+                       <:compositions:label_toutes_verrouilles:>\r
+               </li>\r
+               ]\r
+       </ul>\r
+       [(#GET{lock}|non)\r
+               <input type="hidden" name="composition_lock" id="composition_lock" value="#ENV{composition_lock}" />\r
+               [(#ENV{objet}|=={rubrique}|oui)\r
+                       <input type="hidden" name="composition_branche_lock" id="composition_branche_lock" value="#ENV{composition_branche_lock}" />\r
+               ]\r
+       ]\r
+\r
+         [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]\r
+         <!--extra-->\r
+         <p class='boutons'>\r
+                       <span class='image_loading'>&nbsp;</span>\r
+                       <input type='submit' class='submit' name='annuler' value='<:bouton_annuler:>' />\r
+                       <input type='submit' class='submit' name='changer' value='<:bouton_changer:>' />\r
+               </p>\r
+       </div></form>\r
+       ]\r
+</div>\r
+<script type="text/javascript">// <![CDATA[\r
+       $(document).ready(function(){\r
+               $(".formulaire_editer_composition_objet .toggle_box_link").show(0);\r
+               $(".formulaire_editer_composition_objet p").hide(0);\r
+               $(".formulaire_editer_composition_objet ul").hide(0);\r
+       });\r
+ //]]></script>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/formulaires/editer_composition_objet.php b/www/plugins/compositions_v3/formulaires/editer_composition_objet.php
new file mode 100644 (file)
index 0000000..18e7689
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+/*
+ * Plugin Compositions
+ * (c) 2007-2009 Cedric Morin
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/compositions');
+/**
+ * Chargement des donnees du formulaire
+ *
+ * @param string $type
+ * @param int $id
+ * @return array
+ */
+function formulaires_editer_composition_objet_charger($type,$id){
+       $valeurs = array();
+       $table_objet_sql = table_objet_sql($type);
+       $id_table_objet = id_table_objet($type);
+       $valeurs[$id_table_objet] = intval($id);
+
+       $valeurs['editable'] = true;
+       $valeurs['id'] = "$type-$id";
+       $valeurs['id_objet'] = $id;
+       $valeurs['objet'] = $type;
+
+       $row = sql_fetsel('composition,composition_lock',$table_objet_sql,"$id_table_objet=".intval($id));
+       $valeurs['composition'] = $row['composition'];
+       $valeurs['composition_lock'] = $row['composition_lock'];
+       
+       if ($type=='rubrique')
+               $valeurs['composition_branche_lock'] = sql_getfetsel('composition_branche_lock',$table_objet_sql,"$id_table_objet=".intval($id));
+       
+       $valeurs['composition_heritee'] = compositions_heriter($type, $id);
+       $valeurs['verrou_branche'] = compositions_verrou_branche($type, $id);
+       $valeurs['verrou_branche'] = false;
+       $valeurs['composition_verrouillee'] = compositions_verrouiller($type, $id);
+
+       $valeurs['compositions'] = compositions_lister_disponibles($type);
+       $valeurs['_compositions'] = reset($valeurs['compositions']); // on ne regarde qu'un seul type
+       if (is_array($valeurs['_compositions']) AND !isset($valeurs['_compositions'][''])){
+               $valeurs['_compositions'] = array_merge(
+                       array(''=>array('nom'=>_T('compositions:composition_defaut'),'description'=>'','icon'=>'','configuration'=>'')),
+                       $valeurs['_compositions']
+               );
+       }
+       
+       // Si on herite d'une composition
+       // On modifie le tableau des compositions
+       if ($valeurs['composition_heritee'] AND $valeurs['composition_heritee'] != '-') {
+               $compo_defaut = $valeurs['_compositions'][$valeurs['composition_heritee']];
+               $compo_vide = $valeurs['_compositions'][''];
+               unset($valeurs['_compositions'][$valeurs['composition_heritee']]);
+               unset($valeurs['_compositions']['']);
+               $valeurs['_compositions'] = array_merge(
+                       array('' => $compo_defaut,'-' => $compo_vide),
+                       $valeurs['_compositions']
+               );
+       }
+       
+       $valeurs['_hidden'] = "<input type='hidden' name='$id_table_objet' value='$id' />";
+
+       if (!autoriser('styliser',$type,$id))
+               $valeurs['editable'] = false;
+
+       return $valeurs;
+}
+
+/**
+ * Traitement
+ *
+ * @param string $type
+ * @param int $id
+ * @return array
+ */
+function formulaires_editer_composition_objet_traiter($type,$id){
+       $valeurs = array();
+       $table_objet_sql = table_objet_sql($type);
+       $id_table_objet = id_table_objet($type);
+       $update = array();
+
+       if (!is_null($p = _request('composition')))
+               $update['composition'] = $p;
+
+       if (autoriser('webmestre'))
+               $update['composition_lock'] = _request('composition_lock')?1:0;
+               
+       if (autoriser('webmestre') AND $type == 'rubrique')
+               $update['composition_branche_lock'] = _request('composition_branche_lock')?1:0;
+
+       sql_updateq($table_objet_sql,$update,"$id_table_objet=".intval($id));
+
+       // mettre a jour la liste des types de compo en cache
+       compositions_cacher();
+       return array('message_ok'=>'','editable'=>true);
+}
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/formulaires/inc-informeur_composition.html b/www/plugins/compositions_v3/formulaires/inc-informeur_composition.html
new file mode 100644 (file)
index 0000000..0ac2614
--- /dev/null
@@ -0,0 +1,8 @@
+<B_pour>
+<BOUCLE_pour(POUR){tableau #ENV{_compositions}}{cle=#ENV{selected}}>
+<div class='choix'>[(#VALEUR|table_valeur{icon}|image_reduire{24,24}|inserer_attribut{class,logo})]
+[(#VALEUR|table_valeur{nom})]
+[<br /><span class='descriptif'>(#VALEUR|table_valeur{description})</span>]
+</div>
+</BOUCLE_pour>
+</B_pour>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/formulaires/inc-selecteur_composition.html b/www/plugins/compositions_v3/formulaires/inc-selecteur_composition.html
new file mode 100644 (file)
index 0000000..d63dfc4
--- /dev/null
@@ -0,0 +1,7 @@
+<B_pour>\r
+<BOUCLE_pour(POUR){tableau #ENV{_compositions}}{par nom}>\r
+<div class='choix'>\r
+<input type='radio' class='radio' name='#ENV{name}' id='[(#ENV{name})]-#CLE' value='#CLE'[(#CLE|=={#ENV{selected}}|oui)checked='checked'] /><label for='[(#ENV{name})]-#CLE'>[(#VALEUR|table_valeur{icon}|sinon{#CHEMIN_IMAGE{composition-24.png}}|image_reduire{24,24}|inserer_attribut{class,logo})][(#VALEUR|table_valeur{nom}|supprimer_numero)][(#ENV{composition_heritee}|et{#CLE|=={''}}|oui)(<:compositions:composition_heritee:>)][<br /><span class='descriptif'>(#VALEUR|table_valeur{description})</span>]</label>\r
+</div>\r
+</BOUCLE_pour>\r
+</B_pour>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/images/composition-cours.png b/www/plugins/compositions_v3/images/composition-cours.png
new file mode 100644 (file)
index 0000000..96fd125
Binary files /dev/null and b/www/plugins/compositions_v3/images/composition-cours.png differ
diff --git a/www/plugins/compositions_v3/images/composition-tableau.png b/www/plugins/compositions_v3/images/composition-tableau.png
new file mode 100755 (executable)
index 0000000..ce4f60e
Binary files /dev/null and b/www/plugins/compositions_v3/images/composition-tableau.png differ
diff --git a/www/plugins/compositions_v3/images/composition-test.png b/www/plugins/compositions_v3/images/composition-test.png
new file mode 100644 (file)
index 0000000..d4ba8cd
Binary files /dev/null and b/www/plugins/compositions_v3/images/composition-test.png differ
diff --git a/www/plugins/compositions_v3/images/objet-liste-contenus-dates.png b/www/plugins/compositions_v3/images/objet-liste-contenus-dates.png
new file mode 100644 (file)
index 0000000..8a09263
Binary files /dev/null and b/www/plugins/compositions_v3/images/objet-liste-contenus-dates.png differ
diff --git a/www/plugins/compositions_v3/images/objet-liste-contenus.png b/www/plugins/compositions_v3/images/objet-liste-contenus.png
new file mode 100644 (file)
index 0000000..0c39d8e
Binary files /dev/null and b/www/plugins/compositions_v3/images/objet-liste-contenus.png differ
diff --git a/www/plugins/compositions_v3/images/objet-simple.png b/www/plugins/compositions_v3/images/objet-simple.png
new file mode 100644 (file)
index 0000000..1f387f3
Binary files /dev/null and b/www/plugins/compositions_v3/images/objet-simple.png differ
diff --git a/www/plugins/compositions_v3/inc/compositions.php b/www/plugins/compositions_v3/inc/compositions.php
new file mode 100644 (file)
index 0000000..f705be1
--- /dev/null
@@ -0,0 +1,102 @@
+<?php
+/*
+ * Plugin Compositions
+ * (c) 2007-2009 Cedric Morin
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('compositions_fonctions');
+
+/**
+ * Separer le type et le nom de la composition dans un nom de fichier
+ *
+ * @param string $nom
+ * @return array
+ */
+function compositions_decomposer_nom($nom){
+       $reg = ",^([a-z][^-.]*)("._COMPOSITIONS_MATCH.")?$,i";
+       if (
+               // recuperer le type et la composition
+         preg_match($reg,$nom,$matches)
+         // il y a bien un type
+         AND $type=$matches[1]
+       ){
+               $composition = isset($matches[3])?$matches[3]:'';
+               return array($type,$composition);
+       }
+       return array($nom,"");
+}
+
+/**
+ * Charger les informations contenues dans le xml d'une composition
+ *
+ * @param string $nom
+ * @param string $info
+ * @return array|string
+ */
+function compositions_charger_infos($nom,$info=""){
+               // on peut appeller avec le nom du squelette
+               $nom = preg_replace(',[.]html$,i','',$nom).".xml";
+               include_spip('inc/xml');
+               $composition = array();
+               if ($xml = spip_xml_load($nom,false)){
+                       if (count($xml['composition'])){
+                               $xml = reset($xml['composition']);
+                               $composition['nom'] = _T_ou_typo(spip_xml_aplatit($xml['nom']));
+                               $composition['description'] = isset($xml['description'])?_T_ou_typo(spip_xml_aplatit($xml['description'])):'';
+                               if (isset($xml['icon'])) {
+                                       $icon = chemin_image(reset($xml['icon']));
+                                       if (!$icon)
+                                               $icon = find_in_path(reset($xml['icon']));
+                               } else
+                                       $icon = '';
+                               $composition['icon'] = $icon;
+                               $composition['class'] = isset($xml['class'])?trim(reset($xml['class'])):'';
+                               $composition['configuration'] = isset($xml['configuration'])?spip_xml_aplatit($xml['configuration']):'';
+                               $composition['branche'] = array();
+                               if (spip_xml_match_nodes(',^branche,', $xml, $branches)){
+                                       foreach (array_keys($branches) as $branche){
+                                               list($balise, $attributs) = spip_xml_decompose_tag($branche);
+                                               $composition['branche'][$attributs['type']] = $attributs['composition'];
+                                       }
+                               }
+                       }
+               }
+               if (!$info)
+                       return $composition;
+               else 
+                       return isset($composition[$info])?$composition[$info]:"";
+}
+
+
+/**
+ * Ecrire dans une meta la liste des objets qui sont sous le regime des
+ * compositions
+ * La fonction est appelee
+ * - lors de la stylisation si la meta n'est pas encore definie
+ * - a chaque fois qu'on selectionne un composition dans l'espace prive
+ * - si var_mode=recalcul
+ * On est sur ainsi que toute nouvelle composition selectionnee est dedans
+ * Si une composition est retiree du file system sans etre deselectionnee
+ * l'erreur sera evitee par la verification d'existence au moment de styliser
+ *
+ * @param array $liste
+ */
+function compositions_cacher($liste=null){
+       // lister les compositions vraiment utilisees
+       if (!is_array($liste)){
+               include_spip('compositions_fonctions');
+               $liste = compositions_lister_disponibles('',false);
+       }
+       // lister les objets dont on a active la composition dans la configuration
+       $config = compositions_objets_actives();
+
+       $liste = array_intersect($config,array_keys($liste));
+       ecrire_meta('compositions_types',implode(',',$liste));
+       spip_log('compositions: maj des compositions_types ['.$GLOBALS['meta']['compositions_types'].']');
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/lang/compositions.xml b/www/plugins/compositions_v3/lang/compositions.xml
new file mode 100644 (file)
index 0000000..0c8d758
--- /dev/null
@@ -0,0 +1,15 @@
+<traduction module="compositions" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/compositions/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/compositions?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/compositions?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/compositions?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/compositions?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/compositions_v3/lang/compositions_en.php b/www/plugins/compositions_v3/lang/compositions_en.php
new file mode 100644 (file)
index 0000000..56b4719
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/compositions?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'composition' => 'Composition',
+       'composition_defaut' => 'default composition',
+       'composition_heritee' => 'inherited',
+       'composition_utilisee' => 'Used :',
+       'composition_verrouillee' => 'This composition is locked by the webmaster',
+       'compositions' => 'Compositions',
+
+       // D
+       'des_utilisations' => '@nb@ uses',
+
+       // H
+       'heritages' => 'This composition defines default compositions for the following objects:',
+
+       // L
+       'label_activer_composition_objets' => 'Use compositions on objects',
+       'label_branche_verrouillee' => 'The compositions of this branch are locked.',
+       'label_chemin_compositions' => 'Compositions folder',
+       'label_chemin_compositions_details' => 'Specify the path where the skeletons will be found for composition.',
+       'label_composition' => 'Type of composition',
+       'label_composition_branche_lock' => 'Lock the composition of all objects in the branch',
+       'label_composition_explication' => 'You are Webmaster, you can',
+       'label_composition_lock' => 'Lock the composition',
+       'label_composition_rubrique' => 'Sections composition',
+       'label_information' => 'Information',
+       'label_masquer_formulaire' => 'Hide the form',
+       'label_masquer_formulaire_composition' => 'Hide the selection form of a composition when the user does not have the rights to edit it.',
+       'label_pas_de_composition' => 'No composition',
+       'label_styliser' => 'Selection of skeletons',
+       'label_styliser_auto' => 'Do not use automatic selection. The selection is supported by my skeletons.',
+       'label_tout_verrouiller' => 'Lock all',
+       'label_toutes_verrouilles' => 'All compositions are locked.',
+       'label_verrouiller_toutes_compositions' => 'Lock all compositions (only the webmasters can change them).',
+
+       // U
+       'une_utilisation' => '1 use'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/compositions_es.php b/www/plugins/compositions_v3/lang/compositions_es.php
new file mode 100644 (file)
index 0000000..4c1aa3b
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/compositions?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'composition' => 'Composición',
+       'composition_defaut' => 'composición por defecto',
+       'composition_heritee' => 'heredada',
+       'composition_utilisee' => 'Composición:',
+       'composition_verrouillee' => 'Esta composición esta cerrada por el administrador.',
+       'compositions' => 'Composiciones',
+
+       // D
+       'des_utilisations' => '@nb@ utilizaciones',
+
+       // H
+       'heritages' => 'Esta composición define las composiciones por defecto para los siguientes objetos:',
+
+       // L
+       'label_activer_composition_objets' => 'Utilizar las composiciones en los objetos',
+       'label_branche_verrouillee' => 'Las composiciones de esta rama están bloqueadas.',
+       'label_chemin_compositions' => 'Carpeta de las composiciones',
+       'label_chemin_compositions_details' => 'Indique el camino en el que buscar los esqueletos de composición.',
+       'label_composition' => 'Composición',
+       'label_composition_branche_lock' => 'Bloquear la composición de todos los objetos de la rama',
+       'label_composition_explication' => 'Usted es administrador, puede',
+       'label_composition_lock' => 'Bloquear la composición',
+       'label_composition_rubrique' => 'Composición de las secciones',
+       'label_information' => 'Información',
+       'label_masquer_formulaire' => 'Ocultar el formulario',
+       'label_masquer_formulaire_composition' => 'Ocultar el formulario de elección de una composición cuando el usuario no tenga los derechos para modificarla. ',
+       'label_pas_de_composition' => ' Ninguna composición',
+       'label_styliser' => 'Selección de los esqueletos',
+       'label_styliser_auto' => 'No utilizar la selección automatica. La selección está implementada por mis esqueletos.',
+       'label_tout_verrouiller' => 'Bloquear todo',
+       'label_toutes_verrouilles' => 'Todas las composiciones están bloqueadas.',
+       'label_verrouiller_toutes_compositions' => 'Bloquear todas las composiciones (sólo los administradores podrán modificarlas).',
+
+       // U
+       'une_utilisation' => '1 utilización'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/compositions_fr.php b/www/plugins/compositions_v3/lang/compositions_fr.php
new file mode 100644 (file)
index 0000000..4384ab3
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/compositions/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'composition' => 'Composition',
+       'composition_defaut' => 'composition par défaut',
+       'composition_heritee' => 'héritée',
+       'composition_utilisee' => 'Composition :',
+       'composition_verrouillee' => 'Cette composition est verrouillé par le webmestre.',
+       'compositions' => 'Compositions',
+
+       // D
+       'des_utilisations' => '@nb@ utilisations',
+
+       // H
+       'heritages' => 'Cette composition définit des compositions par défaut pour les objets suivants :',
+
+       // L
+       'label_activer_composition_objets' => 'Utiliser les compositions sur les objets',
+       'label_branche_verrouillee' => 'Les compositions de cette branche sont verrouillées.',
+       'label_chemin_compositions' => 'Dossier des compositions',
+       'label_chemin_compositions_details' => 'Indiquez le chemin dans lequel seront recherchés les squelettes de composition.',
+       'label_composition' => 'Composition',
+       'label_composition_branche_lock' => 'Verrouiller la composition de tous les objets de la branche',
+       'label_composition_explication' => 'Vous êtes Webmestre, vous pouvez',
+       'label_composition_lock' => 'Verrouiller la composition',
+       'label_composition_rubrique' => 'Composition des rubriques',
+       'label_information' => 'Information',
+       'label_masquer_formulaire' => 'Masquer le formulaire',
+       'label_masquer_formulaire_composition' => 'Masquer le formulaire de choix d\'une composition lorsque l\'utilisateur n\'a pas les droits de la modifier.',
+       'label_pas_de_composition' => 'Aucune composition',
+       'label_styliser' => 'Sélection des squelettes',
+       'label_styliser_auto' => 'Ne pas utiliser la sélection automatique. La sélection est prise en charge par mes squelettes.',
+       'label_tout_verrouiller' => 'Tout verrouiller',
+       'label_toutes_verrouilles' => 'Toutes les compositions sont verrouillées.',
+       'label_verrouiller_toutes_compositions' => 'Verrouiller toutes les compositions (seuls les webmestres pourront les modifier).',
+
+       // U
+       'une_utilisation' => '1 utilisation'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/compositions_ru.php b/www/plugins/compositions_v3/lang/compositions_ru.php
new file mode 100644 (file)
index 0000000..6cf56cc
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/compositions?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'composition' => 'Шаблон страницы',
+       'composition_defaut' => 'шаблон по умолчанию',
+       'composition_heritee' => 'унаследован',
+       'composition_utilisee' => 'Используется:',
+       'composition_verrouillee' => 'Возможность сменить шаблон заблокирована вебмастером.',
+       'compositions' => 'Шаблоны страниц',
+
+       // D
+       'des_utilisations' => '@nb@ используется',
+
+       // H
+       'heritages' => 'Этот шаблон определяет шаблоны страниц по умолчанию для следующих объектов:',
+
+       // L
+       'label_activer_composition_objets' => 'Использовать выбор шаблонов для объектов',
+       'label_branche_verrouillee' => 'Выбор шаблонов в этой ветке заблокирован вебмастером.',
+       'label_chemin_compositions' => 'Папка с шаблонами',
+       'label_chemin_compositions_details' => 'Укажите папку в которой находятся файлы шаблонов.',
+       'label_composition' => 'Доступные шаблоны',
+       'label_composition_branche_lock' => 'Заблокировать возможность менять шаблон для всех объектов в этой ветке',
+       'label_composition_explication' => 'У вас права вебмастера, вы можете',
+       'label_composition_lock' => 'Заблокировать шаблон',
+       'label_composition_rubrique' => 'Шаблон для разделов',
+       'label_information' => 'Информация',
+       'label_masquer_formulaire' => 'Спрятать форму',
+       'label_masquer_formulaire_composition' => 'Скрывать форму выбора шаблона страницы для пользователей, у которых нет прав их менять.',
+       'label_pas_de_composition' => 'Нет шаблонов',
+       'label_styliser' => 'Выбор шаблонов страниц',
+       'label_styliser_auto' => 'Не использовать автоматический выбор. Выбор поддерживается моими шаблонами.',
+       'label_tout_verrouiller' => 'Заблокировать все шабоны',
+       'label_toutes_verrouilles' => 'Все шаблоны заблокированы.',
+       'label_verrouiller_toutes_compositions' => 'Заблокировать все шаблоны(только вебмастер сайта может их менять).',
+
+       // U
+       'une_utilisation' => '1 использование'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/compositions_sk.php b/www/plugins/compositions_v3/lang/compositions_sk.php
new file mode 100644 (file)
index 0000000..76684b3
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/compositions?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'composition' => 'Rozmiestnenie',
+       'composition_defaut' => 'predvolené rozmiestnenie',
+       'composition_heritee' => 'zdedené',
+       'composition_utilisee' => 'Rozmiestnenie:',
+       'composition_verrouillee' => 'Toto rozmiestnenie webmaster zamkol.',
+       'compositions' => 'Rozmiestnenia',
+
+       // D
+       'des_utilisations' => '@nb@ použití',
+
+       // H
+       'heritages' => 'Toto rozmiestnenie je predvolených rozmiestnením pre tieto objekty:',
+
+       // L
+       'label_activer_composition_objets' => 'Rozmiestnenia používať na objekty',
+       'label_branche_verrouillee' => 'Rozmiestnenia tejto vetvy sú zamknuté.',
+       'label_chemin_compositions' => 'Priečinok s rozmiestneniami',
+       'label_chemin_compositions_details' => 'Zadajte umiestnenie, v ktorom sa budú hľadať šablóny rozmiestnenia.',
+       'label_composition' => 'Rozmiestnenie',
+       'label_composition_branche_lock' => 'Zamknúť rozmiestnenie všetkých objektov vetvy',
+       'label_composition_explication' => 'Vy ste webmaster, môžete',
+       'label_composition_lock' => 'Zamknúť rozmiestnenie',
+       'label_composition_rubrique' => 'Rozmiestnenie pre rubriky',
+       'label_information' => 'Informácie',
+       'label_masquer_formulaire' => 'Schovať formulár',
+       'label_masquer_formulaire_composition' => 'Schovať formulár s výberom rozmiestnenia, ak ho používateľ nemá právo meniť.',
+       'label_pas_de_composition' => 'Žiadne rozmiestnenie',
+       'label_styliser' => 'Výber šablón',
+       'label_styliser_auto' => 'Nepoužívajte automatický výber. Výber podporujú moje šablóny.',
+       'label_tout_verrouiller' => 'Zamknúť všetky',
+       'label_toutes_verrouilles' => 'Všetky rozmiestnenia sú zamknuté.',
+       'label_verrouiller_toutes_compositions' => 'Zamknúť všetky rozmiestnenia (môže to zmeniť len webmaster).',
+
+       // U
+       'une_utilisation' => '1 použitie'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/paquet-compositions.xml b/www/plugins/compositions_v3/lang/paquet-compositions.xml
new file mode 100644 (file)
index 0000000..bf5b385
--- /dev/null
@@ -0,0 +1,15 @@
+<traduction module="paquet-compositions" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/compositions/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/compositions_v3/lang/paquet-compositions_en.php b/www/plugins/compositions_v3/lang/paquet-compositions_en.php
new file mode 100644 (file)
index 0000000..e89f046
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'compositions_description' => 'This plugin allows you to define several variants of compositions for each kind of SPIP objects (article, sections, etc..) and to easily apply them, case by case, from the private area.',
+       'compositions_nom' => 'Compositions',
+       'compositions_slogan' => 'Differ page layouts according to sections, articles...'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/paquet-compositions_es.php b/www/plugins/compositions_v3/lang/paquet-compositions_es.php
new file mode 100644 (file)
index 0000000..8acdb0e
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'compositions_description' => 'Este plugin le permite definir diversas variantes de composiciones para cada tipo de objeto SPIP (artículo, sección, etcétera) y aplicarlas, simplemente, caso por caso, desde el espacio privado.',
+       'compositions_nom' => 'Composiciones',
+       'compositions_slogan' => 'Variar los formateos según las secciones, los artículos...'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/paquet-compositions_fr.php b/www/plugins/compositions_v3/lang/paquet-compositions_fr.php
new file mode 100644 (file)
index 0000000..374952e
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/compositions/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'compositions_description' => 'Ce plugin vous permet de définir plusieurs variantes de compositions pour chaque type objet SPIP (article, rubrique, etc.) et de les appliquer simplement, cas par cas, depuis l\'espace privé.',
+       'compositions_nom' => 'Compositions',
+       'compositions_slogan' => 'Varier les mises en page selon les rubriques, les articles...'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/paquet-compositions_ru.php b/www/plugins/compositions_v3/lang/paquet-compositions_ru.php
new file mode 100644 (file)
index 0000000..2c5a3a6
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'compositions_description' => 'Этот плагин позволяет вам задавать определенный шаблон вывода для конкретного раздела, статьи и т.д. ',
+       'compositions_nom' => 'Шаблоны страниц (Compositions)',
+       'compositions_slogan' => 'Возможность задавать определенный шаблон для вывода статьи, раздела и т.д.'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/lang/paquet-compositions_sk.php b/www/plugins/compositions_v3/lang/paquet-compositions_sk.php
new file mode 100644 (file)
index 0000000..e282cd8
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-compositions?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'compositions_description' => 'Tento zásuvný modul vám umožňuje definovať niekoľko variantov rozmiestnenia pre každý typ objektu SPIPu (článok, rubrika, atď.) a jednoducho ho rad radom použiť zo súkromnej zóny.',
+       'compositions_nom' => 'Rozmiestnenia',
+       'compositions_slogan' => 'Meňte rozmiestnenie podľa rubrík, článkov, atď.'
+);
+
+?>
diff --git a/www/plugins/compositions_v3/paquet.xml b/www/plugins/compositions_v3/paquet.xml
new file mode 100644 (file)
index 0000000..81d5892
--- /dev/null
@@ -0,0 +1,39 @@
+<paquet
+       prefix="compositions"
+       categorie="outil"
+       version="3.3.2"
+       etat="test"
+       compatibilite="[3.0.0-dev;3.0.*]"
+       logo="prive/themes/spip/images/composition-32.png"
+       schema="0.5.0"
+       documentation="http://contrib.spip.net/?article3777"
+>
+
+       <nom>Compositions</nom>
+       <!-- Varier les mises en page selon les rubriques, les articles... -->
+
+       <auteur lien="http://www.yterium.com">Cedric Morin</auteur>
+
+       <copyright>2007-2012</copyright>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>
+
+       <traduire module="compositions" reference="fr" gestionnaire="salvatore" />
+
+       <pipeline nom="declarer_tables_objets_sql" inclure="compositions_pipeline.php" />
+       <pipeline nom="affiche_milieu" inclure="compositions_pipeline.php" />
+       <pipeline nom="autoriser" inclure="compositions_pipeline.php" />
+       <pipeline nom="styliser" inclure="compositions_pipeline.php" />
+       <pipeline nom="compositions_lister_disponibles" action="" />
+       <pipeline nom="compositions_declarer_heritage" action="" />
+       <pipeline nom="ieconfig_metas" inclure="compositions_ieconfig.php" />
+       <pipeline nom="compositions_declarer_heritage"  inclure="compositions_pipeline.php" />
+
+       <utilise nom="Z" compatibilite="[1.7.10;[" />
+       <utilise nom="Zcore" compatibilite="[2.0.0-dev;[" />
+       <utilise nom="Zpip" compatibilite="[2.0.0-dev;[" />
+       
+       <necessite nom="spip_bonux" compatibilite="[3.0.0;[" />
+
+       <menu nom="compositions" titre="compositions:compositions" parent="menu_configuration" icone="images/composition-16.png" action="configurer_compositions" />
+</paquet>
diff --git a/www/plugins/compositions_v3/prive/editer/compositions.html b/www/plugins/compositions_v3/prive/editer/compositions.html
new file mode 100644 (file)
index 0000000..e448f8e
--- /dev/null
@@ -0,0 +1 @@
+[<div class="ajax composition">(#FORMULAIRE_EDITER_COMPOSITION_OBJET{#ENV{type},#ENV{id}})</div>]\r
diff --git a/www/plugins/compositions_v3/prive/squelettes/contenu/compositions.html b/www/plugins/compositions_v3/prive/squelettes/contenu/compositions.html
new file mode 100644 (file)
index 0000000..aef0deb
--- /dev/null
@@ -0,0 +1,28 @@
+#SET{compositions,#REM|compositions_lister_disponibles}\r
+<BOUCLE_compositions(POUR){tableau #GET{compositions}}>\r
+       <B_pour>\r
+       <h4>[(#CLE|table_objet|ucfirst)]</h4>\r
+       <ul class="liste_items compositions">\r
+       <BOUCLE_pour(POUR){tableau #VALEUR}{par nom}>\r
+       <li class="item">\r
+       [(#VALEUR|table_valeur{icon}|image_reduire{24,24}|inserer_attribut{class,logo})]\r
+       <h3>[(#VALEUR|table_valeur{nom}|supprimer_numero)]</h3>\r
+       [<div class='descriptif'>(#VALEUR|table_valeur{description})</div>]\r
+\r
+        <B_heritages>\r
+        <div class='descriptif'><:compositions:heritages:> <BOUCLE_heritages(POUR){tableau #ENV{compositions}|table_valeur{#ENV{composition}}|table_valeur{branche}}{', '}>#CLE (#VALEUR)</BOUCLE_heritages>.</div>\r
+        </B_heritages>\r
+\r
+               <B_util>\r
+                       [(#TOTAL_BOUCLE|singulier_ou_pluriel{compositions:une_utilisation,compositions:des_utilisations})]\r
+                       <ul>\r
+                       <BOUCLE_util(POUR){tableau #_compositions:CLE|compositions_lister_utilisations{#CLE}}>\r
+                       <li><a href="[(#VALEUR|table_valeur{id}|generer_url_entite{#_compositions:CLE})]">[(#VALEUR|table_valeur{titre}|supprimer_numero)][ | (#VALEUR|table_valeur{id})]</a></li>\r
+                       </BOUCLE_util>\r
+                       </ul>\r
+               </B_util>\r
+       </li>\r
+       </BOUCLE_pour>\r
+       </ul>\r
+       </B_pour>\r
+</BOUCLE_compositions>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/prive/squelettes/contenu/configurer_compositions.html b/www/plugins/compositions_v3/prive/squelettes/contenu/configurer_compositions.html
new file mode 100644 (file)
index 0000000..e148f11
--- /dev/null
@@ -0,0 +1,6 @@
+[(#AUTORISER{configurer,composition}|sinon_interdire_acces)]
+
+<h1 class="grostitre"><:compositions:compositions:></h1>
+<div class="ajax">
+       #FORMULAIRE_CONFIGURER_COMPOSITIONS
+</div>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/prive/style_prive_plugin_compositions.html b/www/plugins/compositions_v3/prive/style_prive_plugin_compositions.html
new file mode 100644 (file)
index 0000000..29a74e0
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM) <style>]
+
+.formulaire_editer_composition_objet .editer_composition .choix {min-height:24px; padding-top:4px;overflow: hidden }
+.formulaire_editer_composition_objet .editer_composition .choix input {display:block;float: #ENV{left};}
+.formulaire_editer_composition_objet .editer_composition .choix label {display:block;float: #ENV{left}; width: 80%;}
+.formulaire_editer_composition_objet .editer_composition .choix img.logo {float:#ENV{left};margin-#ENV{right}:5px;}
+
+.formulaire_editer_composition_objet h4 {
+       padding-#ENV{left}: 30px;
+       background: url(#CHEMIN_IMAGE{composition-24.png}) no-repeat #ENV{left};
+       min-height: 24px;
+       padding-top: 4px;
+       margin-bottom: 0;
+}
+.formulaire_editer_composition_objet h4 .precision {font-size: 85%;}
+
+.formulaire_editer_composition_objet .detail {
+       padding-#ENV{left}: 30px;
+}
+
+.formulaire_editer_composition_objet h4 span.composition_actuelle {font-weight: normal;}
+
+.formulaire_editer_composition_objet span.descriptif {font-style: italic;}
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/prive/themes/spip/images/composition-16.png b/www/plugins/compositions_v3/prive/themes/spip/images/composition-16.png
new file mode 100644 (file)
index 0000000..79cd6b0
Binary files /dev/null and b/www/plugins/compositions_v3/prive/themes/spip/images/composition-16.png differ
diff --git a/www/plugins/compositions_v3/prive/themes/spip/images/composition-24.png b/www/plugins/compositions_v3/prive/themes/spip/images/composition-24.png
new file mode 100644 (file)
index 0000000..13f7b71
Binary files /dev/null and b/www/plugins/compositions_v3/prive/themes/spip/images/composition-24.png differ
diff --git a/www/plugins/compositions_v3/prive/themes/spip/images/composition-32.png b/www/plugins/compositions_v3/prive/themes/spip/images/composition-32.png
new file mode 100644 (file)
index 0000000..a0a14ee
Binary files /dev/null and b/www/plugins/compositions_v3/prive/themes/spip/images/composition-32.png differ
diff --git a/www/plugins/compositions_v3/prive/themes/spip2/images/composition-16.png b/www/plugins/compositions_v3/prive/themes/spip2/images/composition-16.png
new file mode 100644 (file)
index 0000000..b131f9c
Binary files /dev/null and b/www/plugins/compositions_v3/prive/themes/spip2/images/composition-16.png differ
diff --git a/www/plugins/compositions_v3/prive/themes/spip2/images/composition-24.png b/www/plugins/compositions_v3/prive/themes/spip2/images/composition-24.png
new file mode 100644 (file)
index 0000000..954f8f0
Binary files /dev/null and b/www/plugins/compositions_v3/prive/themes/spip2/images/composition-24.png differ
diff --git a/www/plugins/compositions_v3/prive/themes/spip2/images/composition-32.png b/www/plugins/compositions_v3/prive/themes/spip2/images/composition-32.png
new file mode 100644 (file)
index 0000000..78f420a
Binary files /dev/null and b/www/plugins/compositions_v3/prive/themes/spip2/images/composition-32.png differ
diff --git a/www/plugins/compositions_v3/saisies/composition.html b/www/plugins/compositions_v3/saisies/composition.html
new file mode 100644 (file)
index 0000000..67dc588
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM) 
+
+  Saisie Composition
+  
+  Action :
+    - Permet de choisir une composition pour un type d'objet.
+  
+  Parametres :
+    - type : le type d'objet de la composition
+       - composition_vide : non ou vide - Si non permet de ne pas afficher l'option de composition vide
+  
+  Exemple d'appel :
+       [(#SAISIE{composition, composition_rubrique,
+               label=<:plugin:label_composition_rubrique:>,
+               type=rubrique})]
+
+][(#SET{type,#ENV{type,article}})]
+[(#SET{compositions,[(#ENV{_compositions,[(#GET{type}|compositions_lister_disponibles|reset)]})]})]
+[(#ENV{composition_vide}|!={non}|oui)
+       [(#SET{composition_vide,[(#ARRAY{'',[(#ARRAY{nom,<:compositions:label_pas_de_composition:>,description,'',icon,'',configuration,''})]})]})]
+       [(#SET{compositions,[(#GET{composition_vide}|array_merge{#GET{compositions}})]})]
+]
+<div class="composition">
+[(#INCLURE{fond=formulaires/inc-selecteur_composition,_compositions=#GET{compositions},name=#ENV{nom},selected=#ENV{valeur},env})]
+</div>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/saisies/composition_fonctions.php b/www/plugins/compositions_v3/saisies/composition_fonctions.php
new file mode 100644 (file)
index 0000000..ef7d013
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/compositions');
+?>
\ No newline at end of file
diff --git a/www/plugins/compositions_v3/svn.revision b/www/plugins/compositions_v3/svn.revision
new file mode 100644 (file)
index 0000000..f3ef8df
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/compositions/trunk
+Revision: 73176
+Dernier commit: 2013-06-01 20:43:22 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/compositions/trunk</origine>
+<revision>73176</revision>
+<commit>2013-06-01 20:43:22 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/crayons/action/crayons.php b/www/plugins/crayons/action/crayons.php
new file mode 100644 (file)
index 0000000..ab776a0
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// On a ete appele par un formulaire normal (ajax est traite par crayons_store)
+function action_crayons_dist() {
+       include_spip('action/crayons_store');
+       $r = crayons_store();
+
+       // soit exit, soit un redirect gere par SPIP
+       if (trim($r['$erreur'])) {
+               include_spip('inc/minipres');
+               echo minipres($r['$erreur']);
+               exit;
+       }
+
+       // S'il n'y a pas de redirect, on est mal : eviter toutefois la page blanche
+       if (!_request('redirect'))
+               die('OK');
+
+       // Invalider le cache parce que bon... a priori on est dans une
+       // interface qui va avoir besoin de refresh
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+}
+
+?>
\ 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 (file)
index 0000000..fcd47a0
--- /dev/null
@@ -0,0 +1,432 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Affiche le controleur (formulaire) d'un crayon
+ * suivant la classe CSS décrivant le champ à éditer (produit par #EDIT)
+ *
+ * @param string $class
+ *   Class CSS décrivant le champ
+ * @param null $c
+ * 
+ * @return array
+ *   Tableau avec 2 entrées possibles :
+ *   - '$erreur' : texte d'erreur éventuel
+ *   - '$html' : code HTML du controleur
+**/
+function affiche_controleur($class, $c=null) {
+       $return = array('$erreur'=>'');
+
+       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) = explode('-', $this->name, 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
+                '<input type="hidden" class="crayon-id" name="crayons[]"'
+               .' value="'.$this->key.'" />'."\n"
+               . '<input type="hidden" name="name_'.$this->key
+               .'" value="'.$this->name.'" />'."\n"
+               . '<input type="hidden" name="class_' . $this->key
+               . '" value="' . $this->class . '" />' . "\n"
+               . '<input type="hidden" name="md5_'.$this->key
+               .'" value="'.$this->md5.'" />'."\n"
+               . '<input type="hidden" name="fields_'.$this->key
+               .'" value="'.join(',',array_keys($this->texts)).'" />'
+               ."\n"
+               ;
+       }
+
+/*
+ Fabriquer les balises des champs d'apres un modele controleurs/(type_)modele.html
+       $contexte est un tableau (nom=>valeur) qui sera enrichi puis passe à recuperer_fond
+*/
+       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
+       $spec est soit un scalaire 'ligne' ou 'texte' précisant le type de balise
+       soit un array($champ=>array('type'=>'...', 'attrs'=>array(attributs specifique du champs)))
+       $attrs est un tableau (attr=>val) d'attributs communs ou pour le champs unique
+*/
+       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 = '<textarea style="width:100%;" class="crayon-active"'
+                                       . ' name="content_'.$this->key.'_'.$champ.'" id="'.$id.'">'
+                                       . "\n"
+                                       . entites_html($val)
+                                       . "</textarea>\n";
+                                       break;
+                               case 'ligne':
+                               default:
+                                       $input = '<input class="crayon-active text" type="text"'
+                                       . ' name="content_'.$this->key.'_'.$champ.'"'
+                                       . ' value="'
+                                       . entites_html($val)
+                                       . '" />'."\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 = "<div style='width:".$this->largeur."px;height:23px;'>"
+                                               . (function_exists('afficher_barre')
+                                                       ? afficher_barre("document.getElementById('$id')")
+                                                       : '')
+                                               . '</div>'
+                                               . $input;
+                               }
+                       }
+
+                       $return .= $input;
+               }
+               return $return;
+       }
+
+}
+
+
+/*
+       Fabriquer les boutons du formulaire
+*/
+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 .= '<button type="button" class="crayon-' . $bnam .
+                       '" title="' . $bdef[1] . '">' . $bdef[1] . '</button>';
+       }
+
+       if ($html)
+               return '<div class="crayon-boutons"><div>'.$html.'</div></div>';
+}
+
+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(
+               '<div class="formulaire_spip">'
+               . '<form class="formulaire_crayon'.$class.'" method="post" action="'
+               . url_absolue(parametre_url(self(),'action', $action))
+               . '" enctype="multipart/form-data">'
+               . $html
+               . crayons_boutons()
+               . '</form>'
+               .'</div>'
+       );
+}
+
+//
+// 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
+                       .'<input type="hidden" name="secu_'.$this->key.'" value="'.$secu.'" />'."\n";
+       }
+}
+
+function action_crayons_html_dist() {
+       // CONTROLEUR
+       // 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)
+       include_spip('inc/crayons');
+
+       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 (file)
index 0000000..da10a53
--- /dev/null
@@ -0,0 +1,483 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function verif_secu($w, $secu) {
+    return (
+        $secu == md5($GLOBALS['meta']['alea_ephemere'].'='.$w)
+    OR
+        $secu == md5($GLOBALS['meta']['alea_ephemere_ancien'].'='.$w)
+    );
+}
+
+function post_crayons() {
+    $results = array();
+
+    if (isset($_POST['crayons']) AND is_array($_POST['crayons']))
+    foreach ($_POST['crayons'] as $crayon) {
+
+        $name = $_POST['name_'.$crayon];
+        $content = array();
+        if ($_POST['fields_'.$crayon]) {
+          foreach (explode(',', $_POST['fields_'.$crayon]) as $field) {
+            // cas particulier d'un envoi de fichier
+            if (isset($_FILES['content_'.$crayon.'_'.$field])) {
+               if ($_FILES['content_'.$crayon.'_'.$field]['size']>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!)
+               */
+               $content[$field] = is_array($_POST['content_'.$crayon.'_'.$field])?implode(',',$_POST['content_'.$crayon.'_'.$field]):$_POST['content_'.$crayon.'_'.$field];
+            }
+          }
+        }
+
+        // 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;
+
+               // MODELE
+               $fun = '';
+               if (function_exists($f = $type.'_'. $modele . "_revision")
+               OR function_exists($f = $modele . "_revision")
+               OR function_exists($f = $type . "_revision"))
+                       $fun = $f;
+               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;
+                       // cas geres de la maniere la plus standard
+                       case 'auteur':
+                       case 'document':
+                       case 'mot':
+                       case 'signature':
+                       case 'petition':
+                       default:
+                               include_spip('inc/modifier');
+                               $fun = 'revision_'.$type;
+                               break;
+               }
+               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);
+               }
+       }
+}
+
+//
+// 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 "<h4 class='status'>".$r['$erreur']."</h4>\n";
+
+                       foreach ($r as $wid => $v) {
+                               if ($wid !== '$erreur')
+                                       echo "<div id='$wid'>$v</div><hr />\n";
+                       }
+                       echo "<a href='".quote_amp(_request('redirect'))."'>"
+                               .quote_amp(_request('redirect'))
+                               ."</a>\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 (file)
index 0000000..e43140b
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// upload d'images
+/*
+ * Cette action recoit des fichiers ($_FILES)
+ * et les affecte a l'objet courant ;
+ * puis renvoie la liste des documents joints
+ *
+ */
+
+function action_crayons_upload() {
+
+       $type = preg_replace('/\W+/', '', strval(_request('type')));
+       $id = intval(_request('id'));
+
+       // check securite :-)
+       include_spip('inc/autoriser');
+       if (!autoriser('joindredocument',$type,$id)) {
+               echo "Erreur: upload interdit";
+               return false;
+       }
+
+       // on n'accepte qu'un seul document à la fois, dans la variable 'upss'
+       if ($file = $_FILES['upss']
+       AND $file['error'] == 0) {
+       
+               $source = $file['tmp_name'];  # /tmp/php/phpxxx
+               $nom_envoye = $file['name'];  # mon-image.jpg   
+               
+               include_spip('plugins/installer'); // spip_version_compare dans SPIP 3.x 
+               include_spip('inc/plugin'); // spip_version_compare dans SPIP 2.x 
+               if (function_exists(spip_version_compare)) { // gerer son absence dans les branche precedente a SPIP 2.x
+                       if (spip_version_compare($GLOBALS['spip_version_branche'], '3.0.0alpha', '>=')) 
+                                       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 (file)
index 0000000..87a4d05
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Controleur pour le crayon 'article_intro' , uniquement html
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+<textarea class="crayon-active" name="#ENV{name_descriptif}"
+ style="width:#ENV{largeur}px; height:#ENV{hauteur}px;#ENV{style}">
+[(#DESCRIPTIF**|sinon{#INTRODUCTION|textebrut|trim}|entites_html)]</textarea>
+</BOUCLE_a>
diff --git a/www/plugins/crayons/controleurs/article_intro2.html b/www/plugins/crayons/controleurs/article_intro2.html
new file mode 100644 (file)
index 0000000..803dd07
--- /dev/null
@@ -0,0 +1,17 @@
+[(#REM)
+
+       Controleur pour le crayon 'article_intro2' , uniquement html
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+<fieldset style="width:#ENV{largeur}px;#ENV{style}">
+<legend>Introduction</legend>
+<label>Descriptif</label><textarea class="crayon-active" name="#ENV{name_descriptif}"
+ style="width:100%; height:#ENV{hauteur}px;">
+[(#DESCRIPTIF**|entites_html)]</textarea>
+<label>Chapo</label><textarea class="crayon-active" name="#ENV{name_chapo}"
+ style="width:100%; height:#ENV{hauteur}|mul{2}px;">
+[(#CHAPO**|entites_html)]</textarea>
+</fieldset>
+</BOUCLE_a>
diff --git a/www/plugins/crayons/controleurs/article_intro3.php b/www/plugins/crayons/controleurs/article_intro3.php
new file mode 100644 (file)
index 0000000..491cb70
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// un controleur qui n'utilise que php et les inputs défauts
+function controleurs_article_intro3_dist($regs) {
+    list(,$crayon,$type,$champ,$id) = $regs;
+    $valeur = valeur_colonne_table($type, array('descriptif', 'chapo', 'texte'), $id);
+    if ($valeur === false) {
+           return array("$type $id $champ: " . _U('crayons:pas_de_valeur'), 6);
+    }
+
+       $n = new Crayon('article-intro3-' . $id, $valeur,
+                       array('hauteurMini' => 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 (file)
index 0000000..75bb5bf
--- /dev/null
@@ -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}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+<ul>
+       <li class="fieldset" style="width:#ENV{largeur}px;#ENV{style}">
+               <h3 class="legend"><:crayons:legend_introduction_article:></h3>
+               <p class="explication"><:crayons:explication_introduction_article:></p>
+               <ul>
+                       <li class="editer_descriptif">
+                               <label for="descriptif"><:texte_descriptif_rapide:></label>
+                               <textarea class="crayon-active maxheight150" 
+                                       name="#ENV{name_descriptif}"
+                                       id="descriptif"
+                                       style="width:100%;
+                                       height:#ENV{h_descriptif}px;">[(#DESCRIPTIF**|entites_html)]</textarea>
+                       </li>
+                       [(#CONFIG{articles_chapeau}|=={oui}|oui)
+                       <li class="editer_chapo">
+                               <label for="chapo"><:info_chapeau:></label>
+                               <textarea class="crayon-active"
+                                       name="#ENV{name_chapo}"
+                                       id="chapo"
+                                       style="width:100%;
+                                       height:#ENV{h_chapo}px;">[(#CHAPO**|entites_html)]</textarea>
+                       </li>]
+                       <li class="editer_texte">
+                               <label for="text_area"><:info_texte:></label>
+                               <textarea class="crayon-active"
+                                       name="#ENV{name_texte}"
+                                       id="text_area"
+                                       style="width:100%;
+                                       height:#ENV{h_texte}px;">[(#TEXTE**|entites_html)]</textarea>
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_a>
diff --git a/www/plugins/crayons/controleurs/article_introduction.php b/www/plugins/crayons/controleurs/article_introduction.php
new file mode 100644 (file)
index 0000000..4768534
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// un controleur php + html
+// html == avec un modele, controleurs/article_introduction.html)
+function controleurs_article_introduction_dist($regs) {
+    list(,$crayon,$type,$champ,$id) = $regs;
+    $valeur = valeur_colonne_table($type, array('descriptif', 'chapo', 'texte'), $id);
+    if ($valeur === false) {
+           return array("$type $id $champ: " . _U('crayons:pas_de_valeur'), 6);
+    }
+
+       $n = new Crayon('article-introduction-' . $id, $valeur,
+                       array('hauteurMini' => 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 (file)
index 0000000..03e8303
--- /dev/null
@@ -0,0 +1,17 @@
+[(#REM)
+
+       Controleur pour le crayon 'article_intro' , uniquement html
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+<textarea class="crayon-active" name="#ENV{name_texte}"
+ style="width:#ENV{largeur}px; height:#ENV{hauteur}px;#ENV{style}">
+[(#TEXTE**|entites_html)]</textarea>
+
+[(#CONFIG{crayons/upload}|?{
+       #MODELE{uploader_liste,id_article}
+
+})<INCLURE{fond=js/uploader.js,id_article=#ID_ARTICLE}>]
+</BOUCLE_a>
+
diff --git a/www/plugins/crayons/controleurs/auteur_email.html b/www/plugins/crayons/controleurs/auteur_email.html
new file mode 100644 (file)
index 0000000..2272130
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Controleur pour le crayon 'auteur_email', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_a(AUTEURS){id_auteur}{tous}>
+<input class="crayon-active" name="#ENV{name_email}"
+ style="width:#ENV{largeur}px;#ENV{style}" value="[(#EMAIL**|entites_html)]" />
+</BOUCLE_a>
diff --git a/www/plugins/crayons/controleurs/auteur_nom.html b/www/plugins/crayons/controleurs/auteur_nom.html
new file mode 100644 (file)
index 0000000..d1ad82f
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Controleur pour le crayon 'auteur_nom', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_a(AUTEURS){id_auteur}{tous}>
+<input class="crayon-active" name="#ENV{name_nom}"
+ style="width:#ENV{largeur}px;#ENV{style}" value="[(#NOM**|entites_html)]" />
+</BOUCLE_a>
diff --git a/www/plugins/crayons/controleurs/auteur_qui.html b/www/plugins/crayons/controleurs/auteur_qui.html
new file mode 100644 (file)
index 0000000..b10d005
--- /dev/null
@@ -0,0 +1,26 @@
+[(#REM)
+
+       Controleur pour le crayon 'auteur_qui', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_a(AUTEURS){id_auteur}{tous}>
+<ul>
+       <li class="fieldset" style="#ENV{style}">
+               <h3 class="legend"><:crayons:legend_controleur_qui:></h3>
+               <ul>
+                       <li class="editer_nom">
+                               <label for="nom"><:ecrire:info_nom:> :</label>
+                               <input type="text" class="crayon-active text" name="#ENV{name_nom}" id="nom"
+                                       size="40" value="[(#NOM**|entites_html)]" />
+                       </li>
+                       <li class="editer_email">
+                               <label for="email"><:ecrire:email_2|ucfirst:></label>
+                               <input type="text" class="crayon-active text" name="#ENV{name_email}" id="email"
+                                       size="40" value="[(#EMAIL**|entites_html)]" />
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_a>
diff --git a/www/plugins/crayons/controleurs/breve_hyperlien.html b/www/plugins/crayons/controleurs/breve_hyperlien.html
new file mode 100644 (file)
index 0000000..1dd1401
--- /dev/null
@@ -0,0 +1,9 @@
+<BOUCLE_f(BREVES){id_breve}{statut==.}>
+<fieldset style="#ENV{largeur}px;#ENV{style}"><legend>Hyperlien</legend>
+<label><:form_prop_nom_site:></label> <input class="crayon-active" name="#ENV{name_lien_titre}"
+ style="width:100%;" value="[(#NOM_SITE**|entites_html)]" />
+ <br />
+ <label><:forum_url:></label> <input class="crayon-active" name="#ENV{name_lien_url}"
+ style="width:100%;" value="[(#URL_SITE**|entites_html)]" />
+</fieldset>
+</BOUCLE_f>
diff --git a/www/plugins/crayons/controleurs/document_fichier.html b/www/plugins/crayons/controleurs/document_fichier.html
new file mode 100644 (file)
index 0000000..1d0efdf
--- /dev/null
@@ -0,0 +1,46 @@
+[(#REM)
+
+       Controleur pour le crayon 'document'
+
+]
+#CACHE{0}
+
+
+[(#REM) En fonction de du contexte, choisir un logo ]
+
+<BOUCLE_d(DOCUMENTS){id_document}>
+
+[(#SET{image,[<img src="(#LOGO_DOCUMENT||extraire_attribut{src})" />]})]
+
+<fieldset[ style="(#ENV{style});"]>
+<legend>
+       [(#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()}})]})]
+
+       <small>[(#GET{logo}|inserer_attribut{src,#GET{url}}
+               |inserer_attribut{style,vertical-align:middle;})]
+       &nbsp; remplacer ce document #EXTENSION
+       [((#GET{image}
+               |extraire_attribut{width})&times;[(#GET{image}
+               |extraire_attribut{height})]px)]&nbsp;:</small>
+
+</legend>
+
+<input class="crayon-active" name="#ENV{name_document}" type="file"[
+onchange="(#MODE|=={vignette}|?{' '})if (this.value && !this.value.match(/\.(png|jpeg|jpg|gif)$/i)) { alert('Il faut choisir une image :-)'); this.value=''; };"] />
+
+[(#REM)
+
+TODO: document distant (cf. document_fichier_revision dans inc/crayons)
+
+<br />
+<input class="crayon-active" name="#ENV{name_fichier}" type="text" value="#FICHIER" />
+
+]
+
+</fieldset>
+
+</BOUCLE_d>
diff --git a/www/plugins/crayons/controleurs/extra.html b/www/plugins/crayons/controleurs/extra.html
new file mode 100644 (file)
index 0000000..1863ec4
--- /dev/null
@@ -0,0 +1,38 @@
+[(#REM)
+
+       Controleur pour le crayon 'extra'
+
+]
+#CACHE{0}
+
+<fieldset[ style="(#ENV{style});"]>
+<legend>extra</legend>
+
+<input class="crayon-active" name="#ENV{name_extra}" type="hidden" value="go" />
+
+<BOUCLE_a(AUTEURS){id_auteur}{tous}>
+[(#EXTRA**|extra_saisie{auteurs,#STATUT})]
+</BOUCLE_a>
+
+<BOUCLE_b(ARTICLES){id_article}{statut==.}>
+[(#EXTRA**|extra_saisie{articles,#ID_RUBRIQUE})]
+</BOUCLE_b>
+
+<BOUCLE_c(BREVES){id_breve}{statut==.}>
+[(#EXTRA**|extra_saisie{breves,#ID_RUBRIQUE})]
+</BOUCLE_c>
+
+<BOUCLE_d(RUBRIQUES){id_rubrique}{statut==.}>
+[(#EXTRA**|extra_saisie{rubriques,#ID_SECTEUR})]
+</BOUCLE_d>
+
+<BOUCLE_e(SITES){id_syndic=#ENV{id_site}}{statut==.}>
+[(#EXTRA**|extra_saisie{sites,#ID_RUBRIQUE})]
+</BOUCLE_e>
+
+<//B_d>
+<//B_c>
+<//B_b>
+<//B_a>
+
+</fieldset>
\ 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 (file)
index 0000000..9dacf6e
--- /dev/null
@@ -0,0 +1,7 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+       include_spip('inc/extra');
+       include_spip('inc/presentation');
+
+?>
\ 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 (file)
index 0000000..ec7cc13
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Controleur pour le crayon 'forum-email', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_b(FORUMS){id_forum}{statut==.}>
+<input class="crayon-active" name="#ENV{name_email_auteur}"
+ style="width:#ENV{largeur}px;#ENV{style}" value="[(#EMAIL**|entites_html)]" />
+</BOUCLE_b>
diff --git a/www/plugins/crayons/controleurs/forum_id_article.html b/www/plugins/crayons/controleurs/forum_id_article.html
new file mode 100644 (file)
index 0000000..703cce7
--- /dev/null
@@ -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 \8da.
+
+]
+#CACHE{0}
+
+<BOUCLE_f(FORUMS){id_forum}{statut==.}{id_parent=0}{id_article>0}>
+
+<B_a>
+<fieldset style="#ENV{style}">
+Associer ce forum &#224; l'article :
+<select class="crayon-active" name="#ENV{name_id_article}"
+       onchange="cQuery(this).parents('form.formulaire_spip').submit();">
+<option value="0"[
+       (#ID_ARTICLE|?{'',selected})]>&gt;&gt;</option>
+<BOUCLE_a(ARTICLES)>
+<option value="#ID_ARTICLE"[
+       (#ID_ARTICLE|=={#_f:ID_ARTICLE}|?{selected})]>#ID_ARTICLE - [(#TITRE|couper{30})]</option>
+</BOUCLE_a>
+</select>
+</fieldset>
+</B_a>
+
+
+</BOUCLE_f>
diff --git a/www/plugins/crayons/controleurs/forum_nom.html b/www/plugins/crayons/controleurs/forum_nom.html
new file mode 100644 (file)
index 0000000..d40980b
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Controleur pour le crayon 'forum-nom', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_b(FORUMS){id_forum}{statut==.}>
+<input class="crayon-active" name="#ENV{name_auteur}"
+ style="width:#ENV{largeur}px;#ENV{style}" value="[(#NOM**|entites_html)]" />
+</BOUCLE_b>
diff --git a/www/plugins/crayons/controleurs/forum_qui.html b/www/plugins/crayons/controleurs/forum_qui.html
new file mode 100644 (file)
index 0000000..933a329
--- /dev/null
@@ -0,0 +1,15 @@
+[(#REM)
+
+       Controleur pour le crayon 'forum_qui', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_d(FORUMS){id_forum}{statut==.}>
+<fieldset style="#ENV{style};text-align:right;"><legend>Qui ?</legend>
+<label><:ecrire:info_nom:> : <input class="crayon-active" name="#ENV{name_auteur}"
+ style="width:#ENV{largeur}px;" value="[(#NOM**|entites_html)]" /></label><br />
+ <label><:ecrire:email_2:> <input class="crayon-active" name="#ENV{name_email_auteur}"
+ style="width:#ENV{largeur}px;" value="[(#EMAIL**|entites_html)]" /></label>
+</fieldset>
+</BOUCLE_d>
diff --git a/www/plugins/crayons/controleurs/hyperlien.html b/www/plugins/crayons/controleurs/hyperlien.html
new file mode 100644 (file)
index 0000000..175db3e
--- /dev/null
@@ -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}
+
+<BOUCLE_a(AUTEURS){id_auteur}{tous}>
+<ul>
+       <li class="fieldset" style="#ENV{largeur}px;#ENV{style}">
+               <h3 class="legend"><:crayons:legend_controleur_hyperlien:></h3>
+               <ul>
+                       <li class="editer_nom_site">
+                               <label for="nom_site"><:form_prop_nom_site:></label>
+                               <input class="crayon-active text" name="#ENV{name_nom_site}" id="nom_site"
+                                       size="40" value="[(#NOM_SITE**|entites_html)]" />
+                       </li>
+                       <li class="editer_url_site">
+                               <label for="url_site"><:forum_url:></label>
+                               <input class="crayon-active text" name="#ENV{name_url_site}" id="url_site"
+                                       size="40" value="[(#URL_SITE**|entites_html)]" />
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_a>
+
+<BOUCLE_b(ARTICLES){id_article}{statut==.}>
+<ul>
+       <li class="fieldset" style="#ENV{largeur}px;#ENV{style}">
+               <h3 class="legend"><:crayons:legend_controleur_hyperlien:></h3>
+               <ul>
+                       <li class="editer_nom_site">
+                               <label for="nom_site"><:form_prop_nom_site:></label>
+                               <input class="crayon-active text" name="#ENV{name_nom_site}" id="nom_site"
+                                       size="40" value="[(#NOM_SITE**|entites_html)]" />
+                       </li>
+                       <li class="editer_url_site">
+                               <label for="url_site"><:forum_url:></label>
+                               <input class="crayon-active text" name="#ENV{name_url_site}" id="url_site"
+                                       size="40" value="[(#URL_SITE**|entites_html)]" />
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_b>
+
+<BOUCLE_c(SIGNATURES){id_signature}{statut==.}>
+<ul>
+       <li class="fieldset" style="#ENV{largeur}px;#ENV{style}">
+               <h3 class="legend"><:crayons:legend_controleur_hyperlien:></h3>
+               <ul>
+                       <li class="editer_nom_site">
+                               <label for="nom_site"><:form_prop_nom_site:></label>
+                               <input class="crayon-active text" name="#ENV{name_nom_site}" id="nom_site"
+                                       size="40" value="[(#NOM_SITE**|entites_html)]" />
+                       </li>
+                       <li class="editer_url_site">
+                               <label for="url_site"><:forum_url:></label>
+                               <input class="crayon-active text" name="#ENV{name_url_site}" id="url_site"
+                                       size="40" value="[(#URL_SITE**|entites_html)]" />
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_c>
+
+<BOUCLE_d(FORUMS){id_forum}{statut==.}>
+<ul>
+       <li class="fieldset" style="#ENV{largeur}px;#ENV{style}">
+               <h3 class="legend"><:crayons:legend_controleur_hyperlien:></h3>
+               <ul>
+                       <li class="editer_nom_site">
+                               <label for="nom_site"><:form_prop_nom_site:></label>
+                               <input class="crayon-active text" name="#ENV{name_nom_site}" id="nom_site"
+                                       size="40" value="[(#NOM_SITE**|entites_html)]" />
+                       </li>
+                       <li class="editer_url_site">
+                               <label for="url_site"><:forum_url:></label>
+                               <input class="crayon-active text" name="#ENV{name_url_site}" id="url_site"
+                                       size="40" value="[(#URL_SITE**|entites_html)]" />
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_d>
+
+<BOUCLE_e(SITES){id_syndic=#ENV{id_site}}{statut==.}>
+<ul>
+       <li class="fieldset" style="#ENV{largeur}px;#ENV{style}">
+               <h3 class="legend"><:crayons:legend_controleur_hyperlien:></h3>
+               <ul>
+                       <li class="editer_nom_site">
+                               <label for="nom_site"><:form_prop_nom_site:></label>
+                               <input class="crayon-active text" name="#ENV{name_nom_site}" id="nom_site"
+                                       size="40" value="[(#NOM_SITE**|entites_html)]" />
+                       </li>
+                       <li class="editer_url_site">
+                               <label for="url_site"><:forum_url:></label>
+                               <input class="crayon-active text" name="#ENV{name_url_site}" id="url_site"
+                                       size="40" value="[(#URL_SITE**|entites_html)]" />
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_e>
+
+<//B_d>
+<//B_c>
+<//B_b>
+<//B_a>
diff --git a/www/plugins/crayons/controleurs/id_parent.html b/www/plugins/crayons/controleurs/id_parent.html
new file mode 100644 (file)
index 0000000..6961863
--- /dev/null
@@ -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}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+#SET{id,#ID_RUBRIQUE}
+</BOUCLE_a>
+<BOUCLE_r(RUBRIQUES){id_rubrique}{tout}>
+#SET{id,#ID_PARENT}
+</BOUCLE_r>
+<//B_a>
+<B_rubriques>
+<select class="crayon-active" name="#ENV{name_id_rubrique}"
+       style="width:#ENV{largeur}px;#ENV{style}" >
+       <BOUCLE_rubriques(RUBRIQUES){racine}{par num titre, titre}{tout}>
+               [(#SET{separateur_[(#ID_RUBRIQUE)],''})]
+               <option value="#ID_RUBRIQUE"[(#GET{id}|=={#ID_RUBRIQUE}|?{selected})]>[(#TITRE)]</option>
+               <BOUCLE_ss_rub(RUBRIQUES){id_parent}{tout}>
+                       [(#SET{separateur_[(#ID_RUBRIQUE)],[(#GET{separateur_[(#ID_PARENT)]}|concat{&nbsp;&rsaquo;&nbsp;})]})]
+                       <option value="#ID_RUBRIQUE"[(#GET{id}|=={#ID_RUBRIQUE}|?{selected})]>[(#GET{separateur_[(#ID_RUBRIQUE)]})][(#TITRE)]</option>
+                       <BOUCLE_ss_ss_rub(BOUCLE_ss_rub) />
+               </BOUCLE_ss_rub>
+       </BOUCLE_rubriques>
+</select>
+</B_rubriques>
\ 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 (file)
index 0000000..324ae9c
--- /dev/null
@@ -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})&times;[(#GET{image}
+               |extraire_attribut{height})]px)]&nbsp;:
+       })]
+       [(#SET{supprimer,
+               [<div class="choix">
+                       <input type="checkbox" name="(#ENV{name_logo})_supprimer" id="#ENV{name_logo}_supprimer" /><label for="#ENV{name_logo}_supprimer"> <:crayons:bouton_supprimer:></label>
+               <div>]
+       })]
+})]
+
+<ul>
+       <li class="fieldset" [ style="(#ENV{style}); border:none;"]>
+               <h3 class="legend">
+                       [(#GET{legend}|sinon{<:crayons:legend_controleur_logo:>})]
+                       [<div style="float:#LANG_RIGHT">(#GET{logo}|inserer_attribut{src,#GET{url}}
+                               |inserer_attribut{style,vertical-align:middle;})</div>]
+               </h3>
+               <ul>
+                       <li class="editer_logo">
+                               <div class="choix">
+                                       <input class="crayon-active file" name="#ENV{name_logo}" type="file"
+                                               onchange="if (this.value && !this.value.match(/\.(png|jpeg|jpg|gif)$/i)) { alert('<:crayons:message_image_obligatoire:>'); this.value=''; }; var q=cQuery('##ENV{name_logo}_supprimer').parent(); this.value ? q.hide() : q.show();" size="1" />
+                               </div>
+                               #GET{supprimer} 
+                       </li>
+               </ul>
+       </li>
+</ul>
\ 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 (file)
index 0000000..159cc16
--- /dev/null
@@ -0,0 +1,20 @@
+[(#REM)
+
+       Controleur pour le crayon 'mots_article_brut'
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+<fieldset style="#ENV{style}"><legend>Mots-clé pour #TITRE (#ID_ARTICLE)</legend>
+<B_moex>
+<label>Existants</label>
+<select class="crayon-active" name="#ENV{name_existants}" style="width:#ENV{largeur}px; height:#ENV{hauteur}px;">
+<BOUCLE_moex(MOTS){id_article}{doublons}>
+       <option value="#ID_GROUPE:#ID_MOT">[(#TITRE|entites_html)]</option>
+</BOUCLE_moex>
+</select>
+</B_moex>
+Pas d'existant
+<//B_moex>
+</fieldset>
+</BOUCLE_a>
diff --git a/www/plugins/crayons/controleurs/portfolio.php b/www/plugins/crayons/controleurs/portfolio.php
new file mode 100644 (file)
index 0000000..19e3c8f
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// un controleur php (TODO -- NE FONCTIONNE PAS DU TOUT)
+
+function controleurs_portfolio_dist($regs) {
+    list(,$crayon,$type,$champ,$id) = $regs;
+
+       include_spip('inc/minipres'); # pour aide()
+       include_spip('inc/presentation'); # pour debut_cadre()
+       include_spip('inc/layer'); # pour le js des fleches
+       include_spip('inc/documents'); # pour aide()
+
+       $html =
+               http_script("\nvar ajax_image_searching = \n'<div style=\"float: ".$GLOBALS['spip_lang_right'].";\"><img src=\"".url_absolue(_DIR_IMG_PACK."searching.gif")."\" alt=\"\" /></div>';")
+               . 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 (file)
index 0000000..ec501bb
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Controleur pour le crayon 'signature-email', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_c(SIGNATURES){id_signature}{statut==.}>
+<input class="crayon-active" name="#ENV{name_ad_email}"
+ style="width:#ENV{largeur}px;#ENV{style}" value="[(#EMAIL**|entites_html)]" />
+</BOUCLE_c>
diff --git a/www/plugins/crayons/controleurs/signature_nom.html b/www/plugins/crayons/controleurs/signature_nom.html
new file mode 100644 (file)
index 0000000..1f8136c
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM)
+
+       Controleur pour le crayon 'signature-nom', uniquement html
+]
+#CACHE{0}
+
+<BOUCLE_c(SIGNATURES){id_signature}{statut==.}>
+<input class="crayon-active" name="#ENV{name_nom_email}"
+ style="width:#ENV{largeur}px;#ENV{style}" value="[(#NOM**|entites_html)]" />
+</BOUCLE_c>
diff --git a/www/plugins/crayons/controleurs/signature_qui.html b/www/plugins/crayons/controleurs/signature_qui.html
new file mode 100644 (file)
index 0000000..fbb208c
--- /dev/null
@@ -0,0 +1,16 @@
+[(#REM)
+
+       Controleur pour le crayon 'signature_qui', uniquement html
+
+]
+#CACHE{0}
+
+<BOUCLE_c(SIGNATURES){id_signature}{statut==.}>
+<fieldset style="width:#ENV{largeur}px;#ENV{style}"><legend>Qui ?</legend>
+<label><:ecrire:info_nom:> :</label> <input class="crayon-active" name="#ENV{name_nom_email}"
+ style="width:100%;" value="[(#NOM**|entites_html)]" />
+ <br />
+ <label><:ecrire:email_2:></label> <input class="crayon-active" name="#ENV{name_ad_email}"
+ style="width:100%;" value="[(#EMAIL**|entites_html)]" />
+</fieldset>
+</BOUCLE_c>
diff --git a/www/plugins/crayons/controleurs/statut.html b/www/plugins/crayons/controleurs/statut.html
new file mode 100644 (file)
index 0000000..e532361
--- /dev/null
@@ -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).
+
+]
+
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+#SET{id,#STATUT}
+<select class="crayon-active" name="#ENV{name_statut}"
+ style="width:#ENV{largeur}px;">
+       <option value="publie"[
+               (#GET{id}|=={publie}?{selected})="selected"]>publi&#233;</option>
+       <option value="prop"[
+               (#GET{id}|=={prop}?{selected})="selected"]>propos&#233;</option>
+       <option value="prepa"[
+               (#GET{id}|=={prepa}?{selected})="selected"]>en pr&#233;paration</option>
+</select>
+
+</BOUCLE_a>
+
+
+
diff --git a/www/plugins/crayons/controleurs/syndic_article_hyperlien.html b/www/plugins/crayons/controleurs/syndic_article_hyperlien.html
new file mode 100644 (file)
index 0000000..ac2ef20
--- /dev/null
@@ -0,0 +1,17 @@
+[(#REM)
+
+       Controleur pour le crayon 'hyperlien' des articles syndiques
+
+]
+#CACHE{0}
+
+<BOUCLE_f(SYNDIC_ARTICLES){id_syndic_article=#ENV{id_syndic_article}}
+       {statut==.}>
+<fieldset style="#ENV{largeur}px;#ENV{style}"><legend>Hyperlien</legend>
+<label><:forum_titre:></label> <input class="crayon-active" name="#ENV{name_titre}"
+ style="width:100%;" value="[(#TITRE**|entites_html)]" />
+ <br />
+ <label><:forum_url:></label> <input class="crayon-active" name="#ENV{name_url}"
+ style="width:100%;" value="[(#URL_ARTICLE**|sinon{http://}|entites_html)]" />
+</fieldset>
+</BOUCLE_f>
diff --git a/www/plugins/crayons/controleurs/vignette.html b/www/plugins/crayons/controleurs/vignette.html
new file mode 100644 (file)
index 0000000..db99f92
--- /dev/null
@@ -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}
+
+<BOUCLE_document(DOCUMENTS){id_document}{tous}>
+[(#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})&times;[(#GET{image}
+               |extraire_attribut{height})]px)]&nbsp;:
+       })]
+       [(#SET{supprimer,
+               [<div class="choix">
+                       <input type="checkbox" name="(#ENV{name_vignette})_supprimer" id="#ENV{name_vignette}_supprimer" /><label for="#ENV{name_vignette}_supprimer"> <:crayons:bouton_supprimer:></label>
+               <div>]
+       })]
+})]
+
+<ul>
+       <li class="fieldset" [ style="(#ENV{style}); border:none;"]>
+               <h3 class="legend">
+                       [(#GET{legend}|sinon{<:crayons:legend_controleur_vignette:>})]
+                       [<div style="float:#LANG_RIGHT">(#GET{vignette}|inserer_attribut{src,#GET{url}}
+                               |inserer_attribut{style,vertical-align:middle;})</div>]
+               </h3>
+               <ul>
+                       <li class="editer_vignette">
+                               <div class="choix">
+                                       <input class="crayon-active file" name="#ENV{name_vignette}" type="file"
+                                               onchange="if (this.value && !this.value.match(/\.(png|jpeg|jpg|gif)$/i)) { alert('<:crayons:message_image_obligatoire:>'); this.value=''; }; var q=cQuery('##ENV{name_vignette}_supprimer').parent(); this.value ? q.hide() : q.show();" size="10" />
+                               </div>
+                               #GET{supprimer} 
+                       </li>
+               </ul>
+       </li>
+</ul>
+</BOUCLE_document>
\ No newline at end of file
diff --git a/www/plugins/crayons/crayons.css b/www/plugins/crayons/crayons.css
new file mode 100644 (file)
index 0000000..4c62420
--- /dev/null
@@ -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 (file)
index 0000000..748b8e9
--- /dev/null
@@ -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 (file)
index 0000000..4b66711
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+//
+// Les crayons ont leur propre copie du pack de Dean Edwards
+// pour compatibilite avec SPIP < [9717]
+//
+
+function pack_cQuery($chemin) {
+       $flux = spip_file_get_contents($chemin);
+       $flux = str_replace('jQuery', 'cQuery', $flux);
+       $flux = str_replace('cQuery.spip', 'jQuery.spip', $flux);
+
+       // On ne compacte PAS deux fois (c'est inutile et en plus ca bugge)
+       if (!strlen($flux)
+       // mode debug des crayons
+       OR _request('debug_crayons')
+       // le vieil auto_compress_js
+       OR ($GLOBALS['meta']['auto_compress_js'] == 'oui'
+         AND @file_exists(_DIR_RESTREINT.'inc/compacte_js.php'))
+       // ou l'espace prive
+       OR !function_exists('test_espace_prive')
+       OR test_espace_prive())
+               return $flux;
+
+       include_spip('lib/JavaScriptPacker/class.JavaScriptPacker');
+       $packer = new JavaScriptPacker($flux, 0, true, false);
+
+       // en cas d'echec (?) renvoyer l'original
+       if (strlen($t = $packer->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 (file)
index 0000000..0c0484b
--- /dev/null
@@ -0,0 +1,373 @@
+<?php\r
+/** \r
+ * Crayons plugin for spip (c) Fil, toggg 2006-2013 -- licence GPL\r
+ * \r
+ * @package SPIP\Crayons\Fonctions\r
+ */\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * Débuguer les crayons\r
+ * mettre a true dans mes_options pour avoir les crayons non compresses\r
+ */\r
+if(!defined('_DEBUG_CRAYONS'))\r
+       define('_DEBUG_CRAYONS', false);\r
+\r
+// Dire rapidement si ca vaut le coup de chercher des droits\r
+function analyse_droits_rapide_dist() {\r
+       return isset($GLOBALS['auteur_session']['statut']);\r
+}\r
+\r
+// Le pipeline header_prive (pour y tester les crayons)\r
+function Crayons_insert_head($head) {\r
+       // verifie la presence d'une meta crayons, si c'est vide\r
+       // on ne cherche meme pas a traiter l'espace prive\r
+       $config_espace_prive = @unserialize($GLOBALS['meta']['crayons']);\r
+       if (empty($config_espace_prive)) {\r
+               return $head;\r
+       }\r
+\r
+       // verifie que l'edition de l'espace prive est autorisee\r
+       if ($config_espace_prive['espaceprive'] == 'on') {\r
+               // determine les pages (exec) crayonnables\r
+               if (($config_espace_prive['exec_autorise'] == '*') ||\r
+              in_array(_request('exec'),explode(',',$config_espace_prive['exec_autorise']))) {\r
+                       // Calcul des droits\r
+                       include_spip('inc/crayons');\r
+                       $head = Crayons_preparer_page($head, '*', wdgcfg(), 'head');\r
+               }\r
+       }\r
+\r
+       // retourne l'entete modifiee\r
+       return $head;\r
+}\r
+\r
+// Le pipeline affichage_final, execute a chaque hit sur toute la page\r
+function &Crayons_affichage_final(&$page) {\r
+\r
+       // ne pas se fatiguer si le visiteur n'a aucun droit\r
+       if (!(function_exists('analyse_droits_rapide')?analyse_droits_rapide():analyse_droits_rapide_dist()))\r
+               return $page;\r
+\r
+       // sinon regarder rapidement si la page a des classes crayon\r
+       if (strpos($page, 'crayon')===FALSE)\r
+               return $page;\r
+\r
+       // voir un peu plus precisement lesquelles\r
+       include_spip('inc/crayons');\r
+       if (!preg_match_all(_PREG_CRAYON, $page, $regs, PREG_SET_ORDER))\r
+               return $page;\r
+       $wdgcfg = wdgcfg();\r
+\r
+       // calculer les droits sur ces crayons\r
+       include_spip('inc/autoriser');\r
+       $droits = array();\r
+       $droits_accordes = 0;\r
+       foreach ($regs as $reg) {\r
+               list(,$crayon,$type,$champ,$id) = $reg;\r
+               if (_DEBUG_CRAYONS) spip_log("autoriser('modifier', $type, $id, NULL, array('champ'=>$champ))","crayons_distant");\r
+               if (autoriser('modifier', $type, $id, NULL, array('champ'=>$champ))) {\r
+                       if(!isset($droits['.' . $crayon]))\r
+                               $droits['.' . $crayon] = 0;\r
+                       $droits['.' . $crayon]++;\r
+                       $droits_accordes ++;\r
+               }\r
+       }\r
+       // et les signaler dans la page\r
+       if ($droits_accordes == count($regs)) // tous les droits\r
+               $page = Crayons_preparer_page($page, '*', $wdgcfg);\r
+       else if ($droits) // seulement certains droits, preciser lesquels\r
+               $page = Crayons_preparer_page($page, join(',',array_keys($droits)), $wdgcfg);\r
+\r
+       return $page;\r
+}\r
+\r
+function &Crayons_preparer_page(&$page, $droits, $wdgcfg = array(), $mode='page') {\r
+       /**\r
+        * Si pas forcer_lang, on charge le contrôleur dans la langue que l'utilisateur a dans le privé\r
+        */\r
+       if(!isset($GLOBALS['forcer_lang']) OR !$GLOBALS['forcer_lang'] OR ($GLOBALS['forcer_lang'] === 'non'))\r
+               lang_select($GLOBALS['auteur_session']['lang']);\r
+       \r
+       $jsFile = generer_url_public('crayons.js');\r
+       if (_DEBUG_CRAYONS)\r
+               $jsFile = parametre_url($jsFile,'debug_crayons',1,'&');\r
+       include_spip('inc/filtres'); // rien que pour direction_css() :(\r
+       $cssFile = direction_css(find_in_path('crayons.css'));\r
+\r
+       $config = crayons_var2js(array(\r
+               'imgPath' => dirname(find_in_path('images/crayon.png')),\r
+               'droits' => $droits,\r
+               'dir_racine' => _DIR_RACINE,\r
+               'self' => self('&'),\r
+               'txt' => array(\r
+                       'error' => _U('crayons:svp_copier_coller'),\r
+                       'sauvegarder' => $wdgcfg['msgAbandon'] ? _U('crayons:sauvegarder') : ''\r
+               ),\r
+               'img' => array(\r
+                       'searching' => array(\r
+                               'txt' => _U('crayons:veuillez_patienter')\r
+                       ),\r
+                       'crayon' => array(\r
+                               'txt' => _U('crayons:editer')\r
+                       ),\r
+                       'edit' => array(\r
+                               'txt' => _U('crayons:editer_tout')\r
+                       ),\r
+                       'img-changed' => array(\r
+                               'txt' => _U('crayons:deja_modifie')\r
+                       )\r
+               ),\r
+               'cfg' => $wdgcfg\r
+       ));\r
+\r
+\r
+       // Est-ce que PortePlume est la ?\r
+       $meta_crayon = isset($GLOBALS['meta']['crayons']) ? unserialize($GLOBALS['meta']['crayons']): array();\r
+       $pp = '';\r
+       if (isset($meta_crayon['barretypo']) && $meta_crayon['barretypo']) {\r
+               if (function_exists('chercher_filtre')\r
+               AND $f = chercher_filtre('info_plugin')\r
+               AND $f('PORTE_PLUME','est_actif')) {\r
+\r
+               $pp = <<<EOF\r
+cQuery(function() {\r
+       if (typeof onAjaxLoad == 'function') {\r
+               function barrebouilles_crayons() {\r
+                       $('.formulaire_crayon textarea.crayon-active')\r
+                       .barre_outils('edition');\r
+               }\r
+               onAjaxLoad(barrebouilles_crayons);\r
+       }\r
+});\r
+EOF;\r
+\r
+               }\r
+       }\r
+\r
+\r
+       $incCSS = "<link rel=\"stylesheet\" href=\"{$cssFile}\" type=\"text/css\" media=\"all\" />";\r
+       $incJS = <<<EOH\r
+<script type="text/javascript">/* <![CDATA[ */\r
+var configCrayons;\r
+function startCrayons() {\r
+       configCrayons = new cQuery.prototype.cfgCrayons({$config});\r
+       cQuery.fn.crayonsstart();\r
+{$pp}\r
+}\r
+var cr = document.createElement('script');\r
+cr.type = 'text/javascript'; cr.async = true;\r
+cr.src = '{$jsFile}\x26callback=startCrayons';\r
+var s = document.getElementsByTagName('script')[0];\r
+s.parentNode.insertBefore(cr, s);\r
+/* ]]> */</script>\r
+\r
+EOH;\r
+\r
+       if ($mode == 'head')\r
+               return $page . $incJS . $incCSS; //js inline avant les css, sinon ca bloque le chargement\r
+\r
+       $pos_head = strpos($page, '</head>');\r
+       if ($pos_head === false)\r
+               return $page;\r
+\r
+       // js inline avant la premiere css, ou sinon avant la fin du head\r
+       $pos_link = strpos($page, '<link ');\r
+       if (!$pos_link)\r
+               $pos_link = $pos_head;\r
+       $page = substr_replace($page, $incJS, $pos_link, 0);\r
+\r
+       // css avant la fin du head\r
+       $pos_head = strpos($page, '</head>');\r
+               $page = substr_replace($page, $incCSS, $pos_head, 0);\r
+       \r
+       return $page;\r
+}\r
+\r
+\r
+/**\r
+ * Balise indiquant un champ SQL crayonnable\r
+ *\r
+ * @note\r
+ *   Si cette fonction est absente, balise_EDIT_dist() déclarée par SPIP\r
+ *   ne retourne rien\r
+ * \r
+ * @example\r
+ *   <div class="#EDIT{texte}">#TEXTE</div>\r
+ *   <div class="#EDIT{ps}">#PS</div>\r
+ *\r
+ * @param Champ $p\r
+ *   Pile au niveau de la balise\r
+ * @return Champ\r
+ *   Pile complétée par le code à générer\r
+**/\r
+function balise_EDIT($p) {\r
+\r
+       // le code compile de ce qui se trouve entre les {} de la balise\r
+       $label = interprete_argument_balise(1,$p);\r
+\r
+       // Verification si l'on est dans le cas d'une meta\r
+       // #EDIT{meta-descriptif_site} ou #EDIT{meta-demo/truc}\r
+       if (preg_match('/meta-(.*)\'/',$label,$meta)) {\r
+               $type = 'meta';\r
+               $label= 'valeur';\r
+               $primary = $meta[1];\r
+               $p->code = "classe_boucle_crayon('"\r
+                       . $type\r
+                       ."',"\r
+                       .sinon($label,"''")\r
+                       .","\r
+                       . "str_replace('/', '__', '$primary')" # chaque / doit être remplacé pour CSS.\r
+                       .").' '";\r
+               $p->interdire_scripts = false;\r
+               return $p;\r
+       }\r
+\r
+       $i_boucle = $p->nom_boucle ? $p->nom_boucle : $p->id_boucle;\r
+       // #EDIT hors boucle? ne rien faire\r
+       if (!$type = ($p->boucles[$i_boucle]->type_requete)) {\r
+               $p->code = "''";\r
+               $p->interdire_scripts = false;\r
+               return $p;\r
+       }\r
+\r
+       // crayon sur une base distante 'nua:article-intro-5'\r
+       if ($distant = $p->boucles[$i_boucle]->sql_serveur)\r
+               $type = $distant.'__'.$type;\r
+\r
+       // le compilateur 1.9.2 ne calcule pas primary pour les tables secondaires\r
+       // il peut aussi arriver une table sans primary (par ex: une vue)\r
+       if(!($primary = $p->boucles[$i_boucle]->primary)){\r
+               include_spip('inc/vieilles_defs'); # 1.9.2 pour trouver_def_table\r
+               list($nom, $desc) = trouver_def_table(\r
+                       $p->boucles[$i_boucle]->type_requete, $p->boucles[$i_boucle]);\r
+               $primary = $desc['key']['PRIMARY KEY'];\r
+       }\r
+\r
+       $primary = explode(',',$primary);\r
+       $id = array();\r
+       foreach($primary as $key) {\r
+               $id[] = champ_sql(trim($key),$p);\r
+       }\r
+       $primary = implode(".'-'.",$id);\r
+\r
+       $p->code = "classe_boucle_crayon('"\r
+               . $type\r
+               ."',"\r
+               .sinon($label,"''")\r
+               .","\r
+               . $primary\r
+               .").' '";\r
+       $p->interdire_scripts = false;\r
+       return $p;\r
+}\r
+\r
+\r
+/**\r
+ * Balise indiquant une configuration crayonnable\r
+ *\r
+ * @example\r
+ *   <div class="#EDIT_CONFIG{descriptif_site}">#DESCRIPTIF_SITE_SPIP</div>\r
+ *   <div class="#EDIT_CONFIG{demo/truc}">#CONFIG{demo/truc}</div>\r
+ *\r
+ * @param Champ $p\r
+ *   Pile au niveau de la balise\r
+ * @return Champ\r
+ *   Pile complétée par le code à générer\r
+**/\r
+function balise_EDIT_CONFIG_dist($p) {\r
+\r
+       // le code compile de ce qui se trouve entre les {} de la balise\r
+       $config = interprete_argument_balise(1,$p);\r
+       if (!$config) return $p;\r
+\r
+       // chaque / du nom de config doit être transformé pour css.\r
+       // nous utiliserons '__' à la place.\r
+\r
+       $type = 'meta';\r
+       $label= 'valeur';\r
+\r
+       $p->code = "classe_boucle_crayon('"\r
+               . $type\r
+               . "','"\r
+               . $label\r
+               . "',"\r
+               . "str_replace('/', '__', $config)" \r
+               . ").' '";\r
+       $p->interdire_scripts = false;\r
+       return $p;\r
+}\r
+\r
+/**\r
+ * Crée le controleur du crayon indiqué par la classe CSS\r
+ *\r
+ * @param string $class\r
+ *   Class CSS de crayon tel que créé par #EDIT\r
+ * @return string\r
+ *   HTML du crayon, sinon texte d'erreur\r
+**/\r
+function creer_le_crayon($class) {\r
+       include_spip('inc/crayons');\r
+       include_spip('action/crayons_html');\r
+       $a = affiche_controleur($class, array('w' => 485, 'h' => 300, 'wh' => 500));\r
+       return $a['$erreur'] ? $a['$erreur'] : $a['$html'];\r
+}\r
+\r
+/**\r
+ * Balise #CRAYON affichant un formulaire de crayon\r
+ * SI ?edit=1;\r
+ *\r
+ * @example\r
+ *   #CRAYON{ps}\r
+ *\r
+ * @param Champ $p\r
+ *   Pile au niveau de la balise\r
+ * @return Champ\r
+ *   Pile complétée par le code à générer\r
+**/\r
+function balise_CRAYON($p) {\r
+       $p = balise_EDIT($p);\r
+       $p->code = 'creer_le_crayon('.$p->code.')';\r
+       return $p;\r
+}\r
+\r
+\r
+/**\r
+ * Donne la classe CSS crayon en fonction\r
+ * - du type de la boucle\r
+ *   (attention aux exceptions pour #EDIT dans les boucles HIERARCHIE et SITES)\r
+ * - du champ demande (vide, + ou se terminant par + : (+)classe type--id)\r
+ * - de l'id courant\r
+ * \r
+ * @param string $type\r
+ *   Type d'objet, ou "meta" pour un champ de configuration\r
+ * @param string $champ\r
+ *   Champ SQL concerné\r
+ * @param int|string $id\r
+ *   Identifiant de la ligne sql\r
+ * @return string\r
+ *   Classes CSS (à ajouter dans le HTML à destination du javascript de Crayons)\r
+**/\r
+function classe_boucle_crayon($type, $champ, $id) {\r
+       // $type = objet_type($type);\r
+       $type = $type[strlen($type) - 1] == 's' ?\r
+               substr($type, 0, -1) :\r
+               str_replace(\r
+                       array('hierarchie', 'syndication'),\r
+                       array('rubrique',   'site'),\r
+               $type);\r
+\r
+       $plus = (substr($champ, -1) == '+' AND $champ = substr($champ, 0, -1))\r
+               ? " $type--$id"\r
+               : '';\r
+       \r
+       // test rapide pour verifier que l'id est valide (a-zA-Z0-9)\r
+       if (false !== strpos($id, ' ')) {\r
+               spip_log("L'identifiant ($id) ne pourra être géré ($type | $champ)", 'crayons');\r
+               return 'crayon_id_ingerable';\r
+       }\r
+       \r
+       return 'crayon ' . $type . '-' . $champ . '-' . $id . $plus;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/crayons/fonds/cfg_crayons.html b/www/plugins/crayons/fonds/cfg_crayons.html
new file mode 100644 (file)
index 0000000..df6eef9
--- /dev/null
@@ -0,0 +1,11 @@
+<!-- descriptif=
+       <a href="http://www.spip-contrib.net/Les-Crayons" class="spip_out">Cf. documentation</a>
+ -->
+<!-- titre=<:crayons:titre_crayons:> -->
+<!-- icone=images/crayon-24.png -->
+<!-- logo=images/crayon-128.png -->
+
+#CACHE{0}
+<div class="ajax">
+#FORMULAIRE_CONFIGURER_CRAYONS
+</div>
diff --git a/www/plugins/crayons/formulaires/configurer_crayons.html b/www/plugins/crayons/formulaires/configurer_crayons.html
new file mode 100644 (file)
index 0000000..fa8d014
--- /dev/null
@@ -0,0 +1,112 @@
+<!-- autoriser=configurer -->
+<!-- refus=<:cfg:refus_configuration_administrateur:> -->
+<!-- nom=crayons -->
+
+<div class="formulaire_spip formulaire_cfg formulaire_#FORM">
+
+<h3 class='titrem'>[(#CHEMIN{images/crayon-24.png}|image_reduire{24}|inserer_attribut{class,cadre-icone}|inserer_attribut{alt,''})]<:crayons:titre_config_crayons:></h3>
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+<div>
+#ACTION_FORMULAIRE{#ENV{action}}
+<ul>
+#SET{erreurs,#ENV**{erreurs}|table_valeur{barretypo}}
+<li class="editer editer_barretypo[ (#GET{erreurs}|oui)erreur]">
+       <label for="barretypo"><:crayons:label_barre_typo:></label>
+       [<span class='erreur_message'>(#GET{erreurs})</span>]
+       <div class="choix">
+               <input type="checkbox" name="barretypo" class="checkbox"  value='on' id='barretypo'[ (#ENV{barretypo}|oui)checked="checked"] />
+               <label for='barretypo'><:crayons:label_activer_barre_typo:></label>
+               [(#PLUGIN{porte_plume,version}|version_compare{'1.5','>='}|oui)[<p class="attention">(#EVAL{PORTE_PLUME_PUBLIC}|non|ou{#CONFIG{barre_outils_public}|=={non}|oui})<:crayons:activation_barre_impossible:></p>]]
+       </div>
+</li>
+
+#SET{erreurs,#ENV**{erreurs}|table_valeur{msgNoChange}}
+<li class="editer editer_messages[ (#GET{erreurs}|oui)erreur]">
+       <label><:crayons:label_message:></label>
+       [<span class='erreur_message'>(#GET{erreurs})</span>]
+       <div class="choix">
+               <input type="checkbox" name="msgNoChange" class="checkbox" value='on' id='msgNoChange'[ (#ENV{msgNoChange}|oui)checked="checked"] />
+               <label for='msgNoChange'><:crayons:label_msg_no_change:></label>
+       </div>
+       <div class="choix">
+               <input type="checkbox" name="msgAbandon" class="checkbox" value='on' id='msgAbandon'[ (#ENV{msgAbandon}|oui)checked="checked"] />
+               <label for='msgAbandon'><:crayons:label_msg_abandon:></label>
+       </div>
+</li>
+
+#SET{erreurs,#ENV**{erreurs}|table_valeur{filet}}
+<li class="editer editer_effets[ (#GET{erreurs}|oui)erreur]">
+       <label><:crayons:label_effets:></label>
+       [<span class='erreur_message'>(#GET{erreurs})</span>]
+       <div class="choix">
+               <input type="checkbox" name="filet" class="checkbox" value='on' id='filet'[ (#ENV{filet}|oui)checked="checked"] />
+               <label for='filet'><:crayons:label_filet:></label>
+       </div>
+       <div class="choix">
+               <input type="checkbox" name="yellow_fade" class="checkbox" value='on' id='yellow_fade'[ (#ENV{yellow_fade}|oui)checked="checked"] />
+               <label for='yellow_fade'><:crayons:label_yellow_fade:></label>
+       </div>
+       <div class="choix">
+               <input type="checkbox" name="clickhide" class="checkbox" value='on' id='clickhide'[ (#ENV{clickhide}|oui)checked="checked"] />
+               <label for='clickhide'><:crayons:label_clickhide:></label>
+       </div>
+</li>
+
+
+#SET{erreurs,#ENV**{erreurs}|table_valeur{reduire_logo}}
+<li class="editer editer_reduire_logo[ (#GET{erreurs}|oui)erreur]">
+       <label><:crayons:label_reduire_logo:></label>
+       [<span class='erreur_message'>(#GET{erreurs})</span>]
+       <p class='explication'><:crayons:explication_reduire_logo:></p>
+       <input type="text" name="reduire_logo" class="text" size="3" id='reduire_logo' value="[(#ENV{reduire_logo}|intval)]" />
+</li>
+
+<li class="fieldset fieldset_crayons_prive">
+       <h3 class="legend"><:crayons:legend_editer_prive:></h3>
+       <ul>
+               #SET{erreurs,#ENV**{erreurs}|table_valeur{espaceprive}}
+               <li class="editer editer_reduire_logo[ (#GET{erreurs}|oui)erreur]">
+                       <label><:crayons:label_espaceprive:></label>
+                       [<span class='erreur_message'>(#GET{erreurs})</span>]
+                       <div class="choix">
+                               <input type="checkbox" name="espaceprive" class="checkbox"  value='on' id='espaceprive'[ (#ENV{espaceprive}|oui)checked="checked"] />
+                               <label for='espaceprive'><:crayons:label_activer_crayons_prive:></label>
+                       </div>
+               </li>
+               #SET{erreurs,#ENV**{erreurs}|table_valeur{exec_autorise}}
+               <li class="editer editer_exec_autorise[ (#GET{erreurs}|oui)erreur]">
+                       <label><:crayons:label_exec_autorise:></label>
+                       [<span class='erreur_message'>(#GET{erreurs})</span>]
+                       <p class='explication'><:crayons:explication_exec_autorise:></p>
+                       <input type="text" name="exec_autorise" class="text"  id='exec_autorise' value="[(#ENV{exec_autorise}|attribut_html)]" />
+               </li>
+       </ul>
+</li>
+
+
+<li class="fieldset fieldset_crayons_upload experimental">
+       <h3 class="legend"><:crayons:legend_documents:></h3>
+       <ul>
+               <li class="editer editer_reduire_logo[ (#GET{erreurs}|oui)erreur]">
+                       <label><:crayons:info_experimental:></label>
+                       [<span class='erreur_message'>(#GET{erreurs})</span>]
+                       <div class="choix">
+                               <input type="checkbox" name="upload" class="checkbox"  value='on' id='upload'[ (#ENV{upload}|oui)checked="checked"] />
+                               <label for='upload'><:crayons:label_upload_document:></label>
+                       </div>
+               </li>
+       </ul>
+</li>
+
+
+</ul>
+<p class="boutons">
+       <input type="submit" name="_cfg_ok" value="<:bouton_enregistrer:>" class="submit" />
+</p>
+</div>
+</form>
+</div>
diff --git a/www/plugins/crayons/images/annuler-16.png b/www/plugins/crayons/images/annuler-16.png
new file mode 100644 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (executable)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..2bcdf51
--- /dev/null
@@ -0,0 +1,94 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+## ceci n'est pas l'original mais la copie pour crayons\r
+\r
+// Module de compatibilite pour les plugins qui veulent passer en 1.9.3\r
+// tout en restant compatibles avec 1.9.2 voire 1.9.1 : il permet de faire\r
+// tourner sur ces versions du code prevu pour 1.9.3\r
+\r
+// C'est l'inverse de vieilles_defs (lequel vise a permettre a du code\r
+// fait pour 1.9.2 de tourner sur 1.9.3)\r
+\r
+// Ce module doit etre appele par le plugin ("nouveau code") de la\r
+// maniere suivante :\r
+/*\r
+\r
+// Si SPIP est vieux, charger les fonctions de compat\r
+if ($GLOBALS['spip_version_code'] < '1.93'\r
+AND $f = charger_fonction('compat', 'inc'))\r
+       $f();\r
+\r
+qui charge toutes les defs de compat connues\r
+\r
+ou plus precis :\r
+\r
+// Si SPIP est vieux, charger les fonctions de compat\r
+if ($GLOBALS['spip_version_code'] < '1.93'\r
+AND $f = charger_fonction('compat', 'inc'))\r
+       $f('sql_fetch');\r
+\r
+ou encore :\r
+\r
+// Si SPIP est vieux, charger les fonctions de compat\r
+if ($GLOBALS['spip_version_code'] < '1.93'\r
+AND $f = charger_fonction('compat', 'inc'))\r
+       $f(array('sql_fetch', '_q'));\r
+\r
+\r
+*/\r
+\r
+// En termes de distribution ce fichier PEUT etre recopie dans chaque plugin\r
+// qui desire en avoir une version autonome (voire forkee), A CONDITION DE\r
+// RENOMMER le fichier et ses deux fonctions ; c'est un peu lourd a maintenir\r
+// mais c'est le prix a payer pour l'independance des plugins entre eux :-(\r
+\r
+// la version commune a tous est developpee sur\r
+// svn://zone.spip.org/spip-zone/_dev_/compat/\r
+\r
+\r
+function inc_compat_crayons_dist($quoi = NULL) {\r
+       if (!function_exists($f = 'compat_crayons_defs')) $f .= '_dist';\r
+       $defs = $f();\r
+\r
+       if (is_string($quoi))\r
+               $quoi = array($quoi);\r
+       else if (is_null($quoi))\r
+               $quoi = array_keys($defs);\r
+\r
+       foreach ($quoi as $d) {\r
+               if (!function_exists($d)\r
+               AND isset($defs[$d])) {\r
+                       eval ("function $d".$defs[$d]);\r
+               }\r
+       }\r
+}\r
+\r
+function compat_crayons_defs_dist() {\r
+       $defs = array();\r
+\r
+       // http://trac.rezo.net/trac/spip/changeset/9919\r
+       if ($GLOBALS['spip_version_code'] < '1.9259')\r
+       $defs['sql_fetch'] = '($res, $serveur=\'\') {\r
+               return spip_fetch_array($res);\r
+       }';
+       
+       $defs['table_objet_sql'] = '($type) {
+               global $table_des_tables;
+               $nom = table_objet($type);
+               include_spip(\'public/interfaces\');
+               if (isset($table_des_tables[$nom])) {
+                       $t = $table_des_tables[$nom];
+                       $nom = \'spip_\' . $t;
+               }
+               return $nom ;
+       }';\r
+\r
+       // Contourner un bug du plugin CFG\r
+       include_spip('base/abstract_sql');\r
+\r
+       return $defs;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/crayons/inc/crayons-json.php b/www/plugins/crayons/inc/crayons-json.php
new file mode 100644 (file)
index 0000000..d9da53e
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2010                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// Les fonctions de toggg pour faire du JSON
+
+/**
+ * Transform a variable into its javascript equivalent (recursive)
+ * @access private
+ * @param mixed the variable
+ * @return string js script | boolean false if error
+ */
+
+// http://doc.spip.org/@var2js
+function crayons_var2js($var) {
+       $asso = false;
+       switch (true) {
+               case is_null($var) :
+                       return 'null';
+               case is_string($var) :
+                       return '"' .addcslashes($var, "\"\\\n\r\t/") . '"';
+               case is_bool($var) :
+                       return $var ? 'true' : 'false';
+               case is_scalar($var) :
+                       return (string)$var;
+               case is_object( $var) :
+                       $var = get_object_vars($var);
+                       $asso = true;
+               case is_array($var) :
+                       $keys = array_keys($var);
+                       $ikey = count($keys);
+                       while (!$asso && $ikey--) {
+                               $asso = $ikey !== $keys[$ikey];
+                       }
+                       $sep = '';
+                       if ($asso) {
+                               $ret = '{';
+                               foreach ($var as $key => $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 <textarea> ; attention $_FILES a ete vide par array_pop
+       if (defined('FILE_UPLOAD'))
+               return "<textarea>".htmlspecialchars($var)."</textarea>";
+       else
+               return $var;
+*/
+
+}
+
+
+
+?>
diff --git a/www/plugins/crayons/inc/crayons.php b/www/plugins/crayons/inc/crayons.php
new file mode 100644 (file)
index 0000000..6bf5b4b
--- /dev/null
@@ -0,0 +1,599 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+define('_PREG_CRAYON', ',crayon\b[^<>\'"]+?\b((\w+)-(\w+)-(\w+(?:-\w+)*))\b,');\r
+\r
+// Compatibilite pour 1.92 : on a besoin de sql_fetch et table_objet_sql\r
+if ($GLOBALS['spip_version_code'] < '1.93' AND $f = charger_fonction('compat_crayons', 'inc'))\r
+       $f();\r
+\r
+// Autoriser les crayons sur les tables non SPIP ?\r
+// Par defaut : oui (pour les admins complets, si autoriser_defaut_dist()) ;\r
+// mettre a false en cas de mutualisation par prefixe de table,\r
+// sinon on ne peut pas garantir que les sites sont hermetiques\r
+define('_CRAYONS_TABLES_EXTERNES', true);\r
+\r
+// Autorisations non prevues par le core\r
+include_spip('inc/autoriser');\r
+\r
+include_spip('inc/crayons-json');\r
+\r
+\r
+if (!function_exists('autoriser_meta_modifier_dist')) {\r
+/**\r
+ * Autorisation d'éditer les configurations dans spip_meta\r
+ *\r
+ * Les admins complets OK pour certains champs,\r
+ * Sinon, il faut être webmestre\r
+ *\r
+ * @note\r
+ *  Attention sur les SPIP < 11515 (avant 04/2008) inc/autoriser\r
+ *  passe seulement intval($id) alors qu'ici la cle est une chaine...\r
+ *\r
+ * @param  string $faire Action demandée\r
+ * @param  string $type  Type d'objet sur lequel appliquer l'action\r
+ * @param  int    $id    Identifiant de l'objet\r
+ * @param  array  $qui   Description de l'auteur demandant l'autorisation\r
+ * @param  array  $opt   Options de cette autorisation\r
+ * @return bool          true s'il a le droit, false sinon\r
+**/\r
+function autoriser_meta_modifier_dist($faire, $type, $id, $qui, $opt) {\r
+       // Certaines cles de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})\r
+       // $id = str_replace('__', '/', $id);\r
+       if (in_array("$id", array(\r
+               'nom_site', 'slogan_site', 'descriptif_site', 'email_webmaster'\r
+       )))\r
+               return autoriser('configurer', null, null, $qui);\r
+       else\r
+               return autoriser('webmestre', null, null, $qui);\r
+}\r
+}\r
+\r
+// table spip_messages, la c'est tout simplement non (peut mieux faire,\r
+// mais c'est a voir dans le core/organiseur ou dans autorite)\r
+if (defined('_DIR_PLUGIN_ORGANISEUR'))\r
+       include_spip('organiseur_autoriser');\r
+if (!function_exists('autoriser_message_modifier_dist')) {\r
+       function autoriser_message_modifier_dist($faire, $type, $id, $qui, $opt) {\r
+               return false;\r
+       }\r
+}\r
+//compat 192 documents\r
+if ($GLOBALS['spip_version_code'] < '1.93'){\r
+       if (!function_exists('get_spip_doc')){\r
+                       function get_spip_doc($fichier) {\r
+                                       // fichier distant\r
+                                       if (preg_match(',^\w+://,', $fichier))\r
+                                                       return $fichier;\r
+\r
+                                       // gestion d'erreurs, fichier=''\r
+                                       if (!strlen($fichier))\r
+                                                       return false;\r
+\r
+                                       // fichier normal\r
+                                       return (strpos($fichier, _DIR_IMG) === false)\r
+                                       ? _DIR_IMG . $fichier\r
+                                       : $fichier;\r
+                  }\r
+       }\r
+}\r
+\r
+// Autoriser l'usage des crayons ?\r
+function autoriser_crayonner_dist($faire, $type, $id, $qui, $opt) {\r
+       // Le type pouvant etre une table, verifier les autoriser('modifier')\r
+       // correspondant ; ils demandent le nom de l'objet: spip_articles => article\r
+       // ex: spip_articles => 'article'\r
+       $type = preg_replace(',^spip_(.*?)s?$,', '\1', $type);\r
+       if (strlen($GLOBALS['table_prefix']))\r
+               $type = preg_replace(',^'.$GLOBALS['table_prefix'].'_(.*?)s?$,', '\1', $type);\r
+\r
+       // Tables non SPIP ? Si elles sont interdites il faut regarder\r
+       // quelle table on appelle, et verifier si elle est "interne"\r
+       if (!_CRAYONS_TABLES_EXTERNES) {\r
+               include_spip('base/serial');\r
+               include_spip('base/auxiliaires');\r
+               include_spip('public/parametrer');\r
+               if (!isset($GLOBALS['tables_principales']['spip_'.table_objet($type)])\r
+               AND !isset($GLOBALS['tables_auxiliaires']['spip_'.table_objet($type)]))\r
+                       return false;\r
+       }\r
+\r
+       // Traduire le modele en liste de champs\r
+       if (isset($opt['modele']))\r
+               $opt['champ'] = $opt['modele'];\r
+\r
+       // Pour un auteur, si le champ est statut ou email, signaler l'option\r
+       // ad hoc (cf. inc/autoriser)\r
+       if ($type == 'auteur'\r
+       AND in_array($opt['champ'], array('statut', 'email')))\r
+               $opt[$opt['champ']] = true;\r
+\r
+       return (\r
+                autoriser('modifier', $type, $id, $qui, $opt)\r
+       );\r
+}\r
+\r
+// Si un logo est demande, on renvoie la date dudit logo (permettra de gerer\r
+// un "modifie par ailleurs" si la date a change, rien de plus)\r
+function valeur_champ_logo($table, $id, $champ) {\r
+       $chercher_logo = charger_fonction('chercher_logo', 'inc');\r
+       $on = $chercher_logo($id, id_table_objet($table), 'on');\r
+       return $on ? filemtime($on[0]) : false;\r
+}\r
+\r
+// Idem : si un doc est demande, on renvoie la date du doc\r
+function valeur_champ_document($table, $id, $champ) {\r
+       $s = spip_query("SELECT date FROM spip_documents WHERE id_document="._q($id));\r
+       if ($t = sql_fetch($s))\r
+               return $t['date'];\r
+}\r
+\r
+function valeur_champ_vignette($table, $id, $champ) {\r
+       $vignette = sql_getfetsel('id_vignette','spip_documents','id_document='.intval($id));\r
+       if(is_numeric($vignette) && ($vignette > 0)){\r
+               $date = sql_getfetsel('date','spip_documents','id_document='.intval($vignette));\r
+       }\r
+       return $date ? $date : false;\r
+}\r
+// cette fonction de revision recoit le fichier upload a passer en logo\r
+// en reference : le nom du widget, pour aller chercher d'autres donnees\r
+// (ex: supprimer)\r
+function logo_revision($id, $file, $type, $ref) {\r
+\r
+       $chercher_logo = charger_fonction('chercher_logo', 'inc');\r
+       $_id_objet = id_table_objet($type);\r
+\r
+       // Chargement d'un nouveau logo ?\r
+       if ($file['logo']) {\r
+               define('FILE_UPLOAD', true); // message pour crayons_json_export :(\r
+\r
+               // supprimer l'ancien logo\r
+               $on = $chercher_logo($id, $_id_objet, 'on');\r
+               if ($on) @unlink($on[0]);\r
+\r
+               // ajouter le nouveau\r
+               include_spip('action/iconifier');\r
+               action_spip_image_ajouter_dist(\r
+                       type_du_logo($_id_objet).'on'.$id, false, false\r
+               ); // beurk\r
+       }\r
+\r
+       else\r
+\r
+       // Suppression du logo ?\r
+       if ($wid = array_pop($ref)\r
+       AND $_POST['content_'.$wid.'_logo_supprimer'] == 'on') {\r
+               if ($on = $chercher_logo($id, $_id_objet, 'on'))\r
+                       @unlink($on[0]);\r
+       }\r
+\r
+\r
+       // Reduire le logo ?\r
+       if (is_array($cfg = @unserialize($GLOBALS['meta']['crayons']))\r
+       AND $max = intval($cfg['reduire_logo'])) {\r
+               $on = $chercher_logo($id, $_id_objet, 'on');\r
+               include_spip('inc/filtres');\r
+               @copy($on[0], $temp = _DIR_VAR.'tmp'.rand(0,999).'.'.$on[3]);\r
+               $img1 = filtrer('image_reduire', $temp, $max);\r
+               $img2 = preg_replace(',[?].*,', '', extraire_attribut($img1, 'src'));\r
+               if (@file_exists($img2)\r
+               AND $img2 !=  $temp) {\r
+                       @unlink($on[0]);\r
+                       $dest = $on[1].$on[2].'.'\r
+                               .preg_replace(',^.*\.(gif|jpg|png)$,', '\1', $img2);\r
+                       @rename($img2,$dest);\r
+               }\r
+               @unlink($temp);\r
+       }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+// cette fonction de revision recoit le fichier upload a passer en document\r
+function document_fichier_revision($id, $data, $type, $ref) {\r
+\r
+       $s = spip_query("SELECT * FROM spip_documents WHERE id_document="._q($id));\r
+       if (!$t = sql_fetch($s))\r
+               return false;\r
+\r
+       /*\r
+       // Envoi d'une URL de document distant ?\r
+       // TODO: verifier l'extension distante, sinon tout explose\r
+       if ($data['fichier']\r
+       AND preg_match(',^(https?|ftp)://.+,', $data['fichier'])) {\r
+               include_spip('inc/modifier');\r
+               modifier_contenu('document', $id,\r
+                       array('champs' => array('fichier', 'distant')),\r
+                       array('fichier' => $data['fichier'], 'distant' => 'oui')\r
+               );\r
+               return true;\r
+       }\r
+       else\r
+       */\r
+\r
+       // Chargement d'un nouveau doc ?\r
+       if ($data['document']) {\r
+\r
+               $ajouter_documents = charger_fonction('ajouter_documents', 'inc');\r
+               $arg = $data['document'];\r
+               check_upload_error($arg['error']);\r
+               $x = $ajouter_documents($arg['tmp_name'], $arg['name'],\r
+                       'article', 0, 'document', null, $actifs);\r
+\r
+               // $actifs contient l'id_document nouvellement cree\r
+               // on recopie les donnees interessantes dans l'ancien\r
+               $extension=", extension ";\r
+               //compat 192\r
+               if ($GLOBALS['spip_version_code'] < '1.93')\r
+                       $extension="";\r
+\r
+               if ($id_new = array_pop($actifs)\r
+               AND $s = spip_query("SELECT fichier, taille, largeur, hauteur $extension, distant FROM spip_documents\r
+                       WHERE id_document="._q($id_new))\r
+               AND $new = sql_fetch($s)) {\r
+                       define('FILE_UPLOAD', true); // message pour crayons_json_export :(\r
+\r
+                       // Une vignette doit rester une image\r
+                       if ($t['mode'] == 'vignette'\r
+                       AND !in_array($new['extension'], array('jpg', 'gif', 'png')))\r
+                               return false;\r
+\r
+                       // Maintenant on est bon, on recopie les nouvelles donnees\r
+                       // dans l'ancienne ligne spip_documents\r
+                       include_spip('inc/modifier');\r
+                       modifier_contenu('document', $id,\r
+                               # 'champs' inutile a partir de SPIP 11348\r
+                               array('champs' => array_keys($new)),\r
+                               $new);\r
+\r
+                       // supprimer l'ancien document (sauf s'il etait distant)\r
+                       if ($t['distant'] != 'oui'\r
+                       AND file_exists(get_spip_doc($t['fichier'])))\r
+                               supprimer_fichier(get_spip_doc($t['fichier']));\r
+\r
+                       // Effacer la ligne temporaire de spip_document\r
+                       spip_query("DELETE FROM spip_documents WHERE id_document="._q($id_new));\r
+\r
+                       // oublier id_document temporaire (ca marche chez moi, sinon bof)\r
+                       spip_query("ALTER TABLE spip_documents AUTO_INCREMENT="._q($id_new));\r
+\r
+                       return true;\r
+               }\r
+       }\r
+\r
+}\r
+\r
+// cette fonction de revision soit supprime la vignette d'un document,\r
+// soit recoit le fichier upload a passer ou remplacer la vignette du document\r
+function vignette_revision($id, $data, $type, $ref) {\r
+       $s = sql_fetsel("*","spip_documents","id_document=".intval($id));\r
+       if (!is_array($s))\r
+               return false;\r
+\r
+       include_spip('inc/modifier');\r
+       include_spip('inc/documents');\r
+       // Chargement d'un nouveau doc ?\r
+       if ($data['vignette']) {\r
+               define('FILE_UPLOAD', true);\r
+               if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){\r
+                       spip_log('suppression de la vignette');\r
+                       // Suppression du document\r
+                       $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));\r
+                       if (@file_exists($f = get_spip_doc($vignette))) { \r
+                               spip_log("efface $f"); \r
+                               supprimer_fichier($f); \r
+                       }\r
+                       sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));\r
+                       sql_delete('spip_documents_liens',  'id_document='.intval($s['id_vignette']));\r
+\r
+                       pipeline('post_edition',\r
+                               array(\r
+                                       'args' => array(\r
+                                               'operation' => 'supprimer_document',\r
+                                               'table' => 'spip_documents',\r
+                                               'id_objet' => $s['id_vignette']\r
+                                       ),\r
+                                       'data' => null\r
+                               )\r
+                       );\r
+                       \r
+                       // On remet l'id_vignette a 0\r
+                       revision_document($s['id_document'], array('id_vignette'=>0));\r
+               }\r
+               // Ajout du document comme vignette\r
+               $ajouter_documents = charger_fonction('ajouter_documents', 'inc');\r
+               $arg = $data['vignette'];\r
+               check_upload_error($arg['error']);\r
+               $x = $ajouter_documents($arg['tmp_name'], $arg['name'],'','', 'vignette', $id, $actifs);\r
+       }else\r
+               // Suppression de la vignette ?\r
+               if ($wid = array_pop($ref)\r
+                       AND $_POST['content_'.$wid.'_vignette_supprimer'] == 'on') {\r
+                       if(is_numeric($s['id_vignette']) && ($s['id_vignette']>0)){\r
+                               // Suppression du document\r
+                               $vignette = sql_getfetsel('fichier', 'spip_documents', 'id_document='.intval($s['id_vignette']));\r
+                               if (@file_exists($f = get_spip_doc($vignette))) { \r
+                                       spip_log("efface $f"); \r
+                                       supprimer_fichier($f); \r
+                               }\r
+                               sql_delete('spip_documents', 'id_document='.intval($s['id_vignette']));\r
+                               sql_delete('spip_documents_liens',  'id_document='.intval($s['id_vignette']));\r
+                               \r
+                               pipeline('post_edition',\r
+                                       array(\r
+                                               'args' => array(\r
+                                                       'operation' => 'supprimer_document',\r
+                                                       'table' => 'spip_documents',\r
+                                                       'id_objet' => $s['id_vignette']\r
+                                               ),\r
+                                               'data' => null\r
+                                       )\r
+                               );\r
+                               \r
+                               // On remet l'id_vignette a 0\r
+                               revision_document($s['id_document'], array('id_vignette'=>0));\r
+                       }\r
+               }\r
+       return true;\r
+}\r
+\r
+function colonne_table($type, $col) {\r
+       list($distant,$table) = distant_table($type);\r
+       $nom_table = '';\r
+       if (!(($tabref = &crayons_get_table($table, $nom_table)) && ($brut = $tabref['field'][$col]))) {\r
+               return false;\r
+       }\r
+       $ana = explode(' ', $brut);\r
+       $sta = 0;\r
+       $sep = '';\r
+       $ret = array('brut' => $brut,\r
+               'type' => '', 'notnull' => false, 'long' => 0, 'def' => '');\r
+       foreach ($ana as $mot) {\r
+               switch ($sta) {\r
+                       case 0: $ret['type'] = ($mot = strtolower($mot));\r
+                       case 1: if ($mot[strlen($mot) - 1] == ')') {\r
+                                       $pos = strpos($mot, '(');\r
+                                       $ret['type'] = strtolower(substr($mot, 0, $pos++));\r
+                                       $vir = explode(',', substr($mot, $pos, -1));\r
+                                       if ($ret['type'] == 'enum') {\r
+                                               $ret['enum'] = $vir;\r
+                                       } elseif (count($vir) > 1) {\r
+                                               $ret['long'] = $vir;\r
+                                       } else {\r
+                                               $ret['long'] = $vir[0];\r
+                                       }\r
+                                       $sta = 1;\r
+                                       continue;\r
+                               }\r
+                               if (!$sta) {\r
+                                       $sta = 1;\r
+                                       continue;\r
+                               }\r
+                       case 2: switch (strtolower($mot)) {\r
+                               case 'not':\r
+                                       $sta = 3;\r
+                                       continue;\r
+                               case 'default':\r
+                                       $sta = 4;\r
+                                       continue;\r
+                               }\r
+                               continue;\r
+                       case 3:         $ret['notnull'] = strtolower($mot) == 'null';\r
+                               $sta = 2;\r
+                               continue;\r
+                       case 4: $df1 = strpos('"\'', $mot[0]) !== false? $mot[0] : '';\r
+                               $sta = 5;\r
+                       case 5: $ret['def'] .= $sep . $mot;\r
+                               if (!$df1) {\r
+                                       $sta = 2;\r
+                                       continue;\r
+                               }\r
+                               if ($df1 == $mot[strlen($mot) - 1]) {\r
+                                       $ret['def'] = substr($ret['def'], 1, -1);\r
+                                       $sta = 2;\r
+                               }\r
+                               $sep = ' ';\r
+                               continue;\r
+               }\r
+       }\r
+       return $ret;\r
+}\r
+//     var_dump(colonne_table('forum', 'id_syndic')); die();\r
+\r
+function table_where($type, $id, $where_en_tableau = false)\r
+{\r
+       list($distant,$table) = distant_table($type);\r
+       $nom_table = '';\r
+       if (!(($tabref = &crayons_get_table($type, $nom_table))\r
+                       && ($tabid = explode(',', $tabref['key']['PRIMARY KEY'])))) {\r
+               spip_log('crayons: table ' . $table . ' inconnue');\r
+               return array(false, false);\r
+       }\r
+       if (is_scalar($id)) {\r
+               $id = explode('-', $id);\r
+       }\r
+       // sortie tableau pour sql_updateq\r
+       if ($where_en_tableau) {\r
+               $where = array();\r
+               foreach ($id as $idcol => $idval) {\r
+                       $where[] = '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . sql_quote($idval);\r
+               }\r
+       // sinon sortie texte pour sql_query\r
+       } else {\r
+               $where = $and = '';\r
+               foreach ($id as $idcol => $idval) {\r
+                       $where .= $and . '`' . (is_int($idcol) ? trim($tabid[$idcol]) : $idcol) . '`=' . _q($idval);\r
+                       $and = ' AND ';\r
+               }\r
+       }\r
+       return array($nom_table, $where);\r
+}\r
+//     var_dump(colonne_table('forum', 'id_syndic')); die();\r
+\r
+function valeur_colonne_table_dist($type, $col, $id) {\r
+       list($distant,$table) = distant_table($type);\r
+       list($nom_table, $where) = table_where($type, $id);\r
+\r
+       if (!$nom_table)\r
+               return false;\r
+\r
+       $r = array();\r
+\r
+       // valeurs non SQL\r
+       foreach ($col as $champ) {\r
+               if (function_exists($f = 'valeur_champ_'.$table.'_'.$champ) OR function_exists($f = 'valeur_champ_'.$champ)) {\r
+                       $r[$champ] = $f($table, $id, $champ);\r
+                       $col = array_diff($col, array($champ));\r
+               }\r
+       }\r
+\r
+       // valeurs SQL\r
+       if (count($col)\r
+       AND $s = spip_query(\r
+                       'SELECT `' . implode($col, '`, `') .\r
+                       '` FROM ' . $nom_table . ' WHERE ' . $where, $distant)\r
+       AND $t = sql_fetch($s))\r
+               $r = array_merge($r, $t);\r
+\r
+       return $r;\r
+}\r
+\r
+/**\r
+ * Extrait la valeur d'une ou plusieurs colonnes d'une table\r
+ *\r
+ * @param string $table\r
+ *   Type d'objet de la table (article)\r
+ * @param string|array $col\r
+ *   Nom de la ou des colonnes (ps)\r
+ * @param string $id\r
+ *   Identifiant de l'objet\r
+ * @return array\r
+ *   Couples Nom de la colonne => Contenu de la colonne\r
+**/\r
+function valeur_colonne_table($table, $col, $id) {\r
+       if (!is_array($col))\r
+               $col = array($col);\r
+\r
+       if (function_exists($f = $table.'_valeur_colonne_table_dist')\r
+       OR function_exists($f = $table.'_valeur_colonne_table')\r
+       OR $f = 'valeur_colonne_table_dist')\r
+               return $f($table, $col, $id);\r
+}\r
+\r
+/**\r
+ * Extrait la valeur d'une configuration en meta\r
+ *\r
+ * Pour ces données, il n'y a toujours qu'une colonne (valeur),\r
+ * mais on gère l'enregistrement et la lecture via lire_config ou ecrire_config\r
+ * dès que l'on demande des sous parties d'une configuration.\r
+ *\r
+ * On ne retourne alors ici dans 'valeur' que la sous-partie demandée si\r
+ * c'est le cas.\r
+ *\r
+ * @param string $table\r
+ *   Nom de la table (meta)\r
+ * @param array $col\r
+ *   Nom des colonnes (valeur)\r
+ * @param string $id\r
+ *   Nom ou clé de configuration (descriptif_site ou demo__truc pour demo/truc)\r
+ * @return array\r
+ *   Couple valeur => Contenu de la configuration\r
+**/\r
+function meta_valeur_colonne_table_dist($table, $col, $id) {\r
+       // Certaines clés de configuration sont echapées ici (cf #EDIT_CONFIG{demo/truc})\r
+       $id = str_replace('__', '/', $id);\r
+\r
+       // Éviter de planter les vieux SPIP\r
+       if (false === strpos($id, '/')) {\r
+               $config = isset($GLOBALS['meta'][$id]) ? $GLOBALS['meta'][$id] : '';\r
+       // SPIP 3 ou Bonux 2 ou CFG\r
+       } else {\r
+               include_spip('inc/config');\r
+               $config =  lire_config($id, '');\r
+       }\r
+       return array('valeur' => $config);\r
+}\r
+\r
+\r
+function return_log($var) {\r
+       die(crayons_json_export(array('$erreur'=> var_export($var,true))));\r
+}\r
+\r
+function _U($texte, $params=array())\r
+{\r
+    include_spip('inc/charsets');\r
+    return unicode2charset(html2unicode(_T($texte, $params)));\r
+}\r
+\r
+// wdgcfg = widget config :-)\r
+function wdgcfg() {\r
+       $php = function_exists('crayons_config') ? crayons_config() : array();\r
+       include_spip('inc/meta');\r
+       lire_metas();\r
+       global $meta;\r
+       $metacrayons = empty($meta['crayons']) ? array() : unserialize($meta['crayons']);\r
+       $wdgcfg = array();\r
+       foreach (array(\r
+               'msgNoChange' => false,\r
+               'msgAbandon' => false,  /* etait: true */\r
+               'filet' => false,\r
+               'yellow_fade' => false,\r
+               'clickhide' => false /* etait: true */\r
+       )\r
+       as $cfgi => $def) {\r
+               $wdgcfg[$cfgi] = isset($php[$cfgi]) ? $php[$cfgi] :\r
+                       isset($metacrayons[$cfgi]) ? $metacrayons[$cfgi] : $def;\r
+       }\r
+       return $wdgcfg;\r
+}\r
+\r
+function &crayons_get_table($type, &$nom_table) {\r
+       list($distant,$table) = distant_table($type);\r
+       static $return = array();\r
+       static $noms = array();\r
+       if (!isset($return[$table])) {\r
+               $try = array(table_objet_sql($table), 'spip_'.table_objet($table), 'spip_' . $table . 's', $table . 's', 'spip_' . $table, $table);\r
+\r
+               // premiere possibilite (à partir de 1.9.3) : regarder directement la base\r
+               if (function_exists('sql_showtable')) {\r
+                       foreach ($try as $nom) {\r
+                               if ($q = sql_showtable($nom , !$distant , $distant)) {\r
+                                       $noms[$table] = $nom;\r
+                                       $return[$table] = $q;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
+               // seconde, une heuristique 1.9.2\r
+               if (!isset($return[$table])) {\r
+                       include_spip('base/serial');\r
+                       include_spip('base/auxiliaires');\r
+                       include_spip('public/parametrer');\r
+                       foreach(array('tables_principales', 'tables_auxiliaires') as $categ)\r
+                       {\r
+                               foreach ($try as $nom) {\r
+                                       if (isset($GLOBALS[$categ][$nom])) {\r
+                                               $noms[$table] = $nom;\r
+                                               $return[$table] = & $GLOBALS[$categ][$nom];\r
+                                               break 2;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+       }\r
+\r
+       $nom_table = $noms[$table];\r
+       return $return[$table];\r
+}\r
+\r
+function distant_table($type) {\r
+       //separation $type en $distant $table\r
+       //separateur double underscore "__"\r
+       strstr($type,'__')? list($distant,$table) = explode('__',$type) : list($distant,$table) = array(False,$type);\r
+       return array($distant,$table);\r
+}\r
+?>\r
diff --git a/www/plugins/crayons/js/crayons-fade.js b/www/plugins/crayons/js/crayons-fade.js
new file mode 100644 (file)
index 0000000..47f5b88
--- /dev/null
@@ -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('<div></div>');
+                               jQuery(this)
+                                       .find('div')
+                                               .html(contenu)
+                                               .css('position','absolute')
+                                               .css('width',this.offsetWidth + 'px');
+                               jQuery(this)
+                                       .prepend('<div class="survol"></div>')
+                                       .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 (file)
index 0000000..c216829
--- /dev/null
@@ -0,0 +1,561 @@
+(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 '<em class="crayon-'+what+'" title="'+ txt + (extra ? extra : '') + '"></em>';
+};
+
+$.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 ?
+               '<a href="ecrire/?exec=' + link[1] + 's_edit&id_' + link[1] + '=' + link[2] +
+               '">' + this.mkimg('edit', ' (' + link[1] + ' ' + link[2] + ')') + '</a>' : '';
+
+       // 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 "<span class='crayon-icones'><span>" + boite +
+                       this.mkimg('img-changed', cray ? ' (' + cray[1] + ')': '') +
+                       link +"</span></span>";
+};
+
+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();
+                                       $('<div class="crayon-html" id="crayon_'+id_crayon+'"></div>')
+                                       .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) {
+       this
+       .crayon()
+       .click(function(e){
+               e.stopPropagation();
+       });
+       this
+       .each(function(){
+               var me = $(this);
+               var crayon = $(this).crayon();
+               crayon
+               .find('form')
+                       .append(
+                               $('<input type="hidden" name="self" />')
+                               .attr('value',configCrayons.self)
+                       )
+                       .ajaxForm({
+                       "dataType":"json",
+                       "error": function(d) {
+                               uniAlert('erreur de communication');
+                               crayon
+                               .empty()
+                               .append(
+                                       $('<div class="error">')
+                                       .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 <pre>...</pre>
+                               if (typeof d == "string") {
+                                       try {
+                                               d = $.parseJSON(d.replace(/^<pre>/,'').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("<span class=\"crayon-invalide\"></span>")
+                                                   .parent()
+                                                   .append("<p>"
+                                                               + retour
+                                                               + " "
+                                                               + msg
+                                                               + "</p>"
+                                                       );
+                                               }
+
+                               }
+
+                               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: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
+                                       // 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) {
+                                               this.focus();
+                                               // premiere approximation, en fonction de la hauteur du clic
+                                               var position = parseInt(percent * this.textLength);
+                                               this.selectionStart=position;
+                                               this.selectionEnd=position;
+                                       }
+                               })
+                       .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)) {
+               $('.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 (file)
index 0000000..c0fba53
--- /dev/null
@@ -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 = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />');
+               var io = $io[0];
+
+               $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+
+               var xhr = { // mock object
+                       aborted: 0,
+                       responseText: null,
+                       responseXML: null,
+                       status: 0,
+                       statusText: 'n/a',
+                       getAllResponseHeaders: function() {},
+                       getResponseHeader: function() {},
+                       setRequestHeader: function() {},
+                       abort: function(status) {
+                               var e = (status === 'timeout' ? 'timeout' : 'aborted');
+                               log('aborting upload... ' + e);
+                               this.aborted = 1;
+                               $io.attr('src', s.iframeSrc); // abort op in progress
+                               xhr.error = e;
+                               s.error && s.error.call(s.context, xhr, e, e);
+                               g && $.event.trigger("ajaxError", [xhr, s, e]);
+                               s.complete && s.complete.call(s.context, xhr, e);
+                       }
+               };
+
+               var g = s.global;
+               // trigger ajax global events so that activity/block indicators work like normal
+               if (g && ! $.active++) {
+                       $.event.trigger("ajaxStart");
+               }
+               if (g) {
+                       $.event.trigger("ajaxSend", [xhr, s]);
+               }
+
+               if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
+                       if (s.global) { 
+                               $.active--;
+                       }
+                       return;
+               }
+               if (xhr.aborted) {
+                       return;
+               }
+
+               var timedOut = 0, timeoutHandle;
+
+               // add submitting element to data if we know it
+               var sub = form.clk;
+               if (sub) {
+                       var n = sub.name;
+                       if (n && !sub.disabled) {
+                               s.extraData = s.extraData || {};
+                               s.extraData[n] = sub.value;
+                               if (sub.type == "image") {
+                                       s.extraData[n+'.x'] = form.clk_x;
+                                       s.extraData[n+'.y'] = form.clk_y;
+                               }
+                       }
+               }
+
+               // take a breath so that pending repaints get some cpu time before the upload starts
+               function doSubmit() {
+                       // make sure form attrs are set
+                       var t = $form.attr('target'), a = $form.attr('action');
+
+                       // update form attrs in IE friendly way
+                       form.setAttribute('target',id);
+                       if (form.getAttribute('method') != 'POST') {
+                               form.setAttribute('method', 'POST');
+                       }
+                       if (form.getAttribute('action') != s.url) {
+                               form.setAttribute('action', s.url);
+                       }
+
+                       // ie borks in some cases when setting encoding
+                       if (! s.skipEncodingOverride) {
+                               $form.attr({
+                                       encoding: 'multipart/form-data',
+                                       enctype:  'multipart/form-data'
+                               });
+                       }
+
+                       // support timout
+                       if (s.timeout) {
+                               timeoutHandle = setTimeout(function() { timedOut = true; cb(true); }, s.timeout);
+                       }
+
+                       // add "extra" data to form if provided in options
+                       var extraInputs = [];
+                       try {
+                               if (s.extraData) {
+                                       for (var n in s.extraData) {
+                                               extraInputs.push(
+                                                       $('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
+                                                               .appendTo(form)[0]);
+                                       }
+                               }
+
+                               // add iframe to doc and submit the form
+                               $io.appendTo('body');
+                io.attachEvent ? io.attachEvent('onload', cb) : io.addEventListener('load', cb, false);
+                               form.submit();
+                       }
+                       finally {
+                               // reset attrs and remove "extra" input elements
+                               form.setAttribute('action',a);
+                               if(t) {
+                                       form.setAttribute('target', t);
+                               } else {
+                                       $form.removeAttr('target');
+                               }
+                               $(extraInputs).remove();
+                       }
+               }
+
+               if (s.forceSync) {
+                       doSubmit();
+               }
+               else {
+                       setTimeout(doSubmit, 10); // this lets dom updates render
+               }
+       
+               var data, doc, domCheckCount = 50, callbackProcessed;
+
+               function cb(e) {
+                       if (xhr.aborted || callbackProcessed) {
+                               return;
+                       }
+                       if (e === true && xhr) {
+                               xhr.abort('timeout');
+                               return;
+                       }
+                       
+                       var doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
+                       if (!doc || doc.location.href == s.iframeSrc) {
+                               // response not received yet
+                               if (!timedOut)
+                                       return;
+                       }
+            io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
+
+                       var ok = true;
+                       try {
+                               if (timedOut) {
+                                       throw 'timeout';
+                               }
+
+                               var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
+                               log('isXml='+isXml);
+                               if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
+                                       if (--domCheckCount) {
+                                               // in some browsers (Opera) the iframe DOM is not always traversable when
+                                               // the onload callback fires, so we loop a bit to accommodate
+                                               log('requeing onLoad callback, DOM not available');
+                                               setTimeout(cb, 250);
+                                               return;
+                                       }
+                                       // let this fall through because server response could be an empty document
+                                       //log('Could not access iframe DOM after mutiple tries.');
+                                       //throw 'DOMException: not available';
+                               }
+
+                               //log('response detected');
+                               xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null; 
+                               xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+                               if (isXml)
+                                       s.dataType = 'xml';
+                               xhr.getResponseHeader = function(header){
+                                       var headers = {'content-type': s.dataType};
+                                       return headers[header];
+                               };
+
+                               var scr = /(json|script|text)/.test(s.dataType);
+                               if (scr || s.textarea) {
+                                       // see if user embedded response in textarea
+                                       var ta = doc.getElementsByTagName('textarea')[0];
+                                       if (ta) {
+                                               xhr.responseText = ta.value;
+                                       }
+                                       else if (scr) {
+                                               // account for browsers injecting pre around json response
+                                               var pre = doc.getElementsByTagName('pre')[0];
+                                               var b = doc.getElementsByTagName('body')[0];
+                                               if (pre) {
+                                                       xhr.responseText = pre.textContent;
+                                               }
+                                               else if (b) {
+                                                       xhr.responseText = b.innerHTML;
+                                               }
+                                       }                         
+                               }
+                               else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
+                                       xhr.responseXML = toXml(xhr.responseText);
+                               }
+                               
+                               data = httpData(xhr, s.dataType, s);
+                       }
+                       catch(e){
+                               log('error caught:',e);
+                               ok = false;
+                               xhr.error = e;
+                               s.error && s.error.call(s.context, xhr, 'error', e);
+                               g && $.event.trigger("ajaxError", [xhr, s, e]);
+                       }
+                       
+                       if (xhr.aborted) {
+                               log('upload aborted');
+                               ok = false;
+                       }
+
+                       // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
+                       if (ok) {
+                               s.success && s.success.call(s.context, data, 'success', xhr);
+                               g && $.event.trigger("ajaxSuccess", [xhr, s]);
+                       }
+                       
+                       g && $.event.trigger("ajaxComplete", [xhr, s]);
+
+                       if (g && ! --$.active) {
+                               $.event.trigger("ajaxStop");
+                       }
+                       
+                       s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error');
+
+                       callbackProcessed = true;
+                       if (s.timeout)
+                               clearTimeout(timeoutHandle);
+
+                       // clean up
+                       setTimeout(function() {
+                               $io.removeData('form-plugin-onload');
+                               $io.remove();
+                               xhr.responseXML = null;
+                       }, 100);
+               }
+
+               var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
+                       if (window.ActiveXObject) {
+                               doc = new ActiveXObject('Microsoft.XMLDOM');
+                               doc.async = 'false';
+                               doc.loadXML(s);
+                       }
+                       else {
+                               doc = (new DOMParser()).parseFromString(s, 'text/xml');
+                       }
+                       return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+               };
+               var parseJSON = $.parseJSON || function(s) {
+                       return window['eval']('(' + s + ')');
+               };
+               
+               var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+                       var ct = xhr.getResponseHeader('content-type') || '',
+                               xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+                               data = xml ? xhr.responseXML : xhr.responseText;
+
+                       if (xml && data.documentElement.nodeName === 'parsererror') {
+                               $.error && $.error('parsererror');
+                       }
+                       if (s && s.dataFilter) {
+                               data = s.dataFilter(data, type);
+                       }
+                       if (typeof data === 'string') {
+                               if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+                                       data = parseJSON(data);
+                               } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+                                       $.globalEval(data);
+                               }
+                       }
+                       return data;
+               };
+       }
+};
+
+/**
+ * ajaxForm() provides a mechanism for fully automating form submission.
+ *
+ * The advantages of using this method instead of ajaxSubmit() are:
+ *
+ * 1: This method will include coordinates for <input type="image" /> elements (if the element
+ *     is used to submit the form).
+ * 2. This method will include the submit element's name/value data (for the element that was
+ *     used to submit the form).
+ * 3. This method binds the submit() method to the form for you.
+ *
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit.  ajaxForm merely
+ * passes the options argument along after properly binding events for submit elements and
+ * the form itself.
+ */
+$.fn.ajaxForm = function(options) {
+       // in jQuery 1.3+ we can fix mistakes with the ready state
+       if (this.length === 0) {
+               var o = { s: this.selector, c: this.context };
+               if (!$.isReady && o.s) {
+                       log('DOM not ready, queuing ajaxForm');
+                       $(function() {
+                               $(o.s,o.c).ajaxForm(options);
+                       });
+                       return this;
+               }
+               // is your DOM ready?  http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+               log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+               return this;
+       }
+       
+       return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
+               if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
+                       e.preventDefault();
+                       $(this).ajaxSubmit(options);
+               }
+       }).bind('click.form-plugin', function(e) {
+               var target = e.target;
+               var $el = $(target);
+               if (!($el.is(":submit,input:image"))) {
+                       // is this a child element of the submit el?  (ex: a span within a button)
+                       var t = $el.closest(':submit');
+                       if (t.length == 0) {
+                               return;
+                       }
+                       target = t[0];
+               }
+               var form = this;
+               form.clk = target;
+               if (target.type == 'image') {
+                       if (e.offsetX != undefined) {
+                               form.clk_x = e.offsetX;
+                               form.clk_y = e.offsetY;
+                       } else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
+                               var offset = $el.offset();
+                               form.clk_x = e.pageX - offset.left;
+                               form.clk_y = e.pageY - offset.top;
+                       } else {
+                               form.clk_x = e.pageX - target.offsetLeft;
+                               form.clk_y = e.pageY - target.offsetTop;
+                       }
+               }
+               // clear form vars
+               setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
+       });
+};
+
+// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
+$.fn.ajaxFormUnbind = function() {
+       return this.unbind('submit.form-plugin click.form-plugin');
+};
+
+/**
+ * formToArray() gathers form element data into an array of objects that can
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
+ * Each object in the array has both a 'name' and 'value' property.  An example of
+ * an array for a simple login form might be:
+ *
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
+ *
+ * It is this array that is passed to pre-submit callback functions provided to the
+ * ajaxSubmit() and ajaxForm() methods.
+ */
+$.fn.formToArray = function(semantic) {
+       var a = [];
+       if (this.length === 0) {
+               return a;
+       }
+
+       var form = this[0];
+       var els = semantic ? form.getElementsByTagName('*') : form.elements;
+       if (!els) {
+               return a;
+       }
+       
+       var i,j,n,v,el,max,jmax;
+       for(i=0, max=els.length; i < max; i++) {
+               el = els[i];
+               n = el.name;
+               if (!n) {
+                       continue;
+               }
+
+               if (semantic && form.clk && el.type == "image") {
+                       // handle image inputs on the fly when semantic == true
+                       if(!el.disabled && form.clk == el) {
+                               a.push({name: n, value: $(el).val()});
+                               a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+                       }
+                       continue;
+               }
+
+               v = $.fieldValue(el, true);
+               if (v && v.constructor == Array) {
+                       for(j=0, jmax=v.length; j < jmax; j++) {
+                               a.push({name: n, value: v[j]});
+                       }
+               }
+               else if (v !== null && typeof v != 'undefined') {
+                       a.push({name: n, value: v});
+               }
+       }
+
+       if (!semantic && form.clk) {
+               // input type=='image' are not found in elements array! handle it here
+               var $input = $(form.clk), input = $input[0];
+               n = input.name;
+               if (n && !input.disabled && input.type == 'image') {
+                       a.push({name: n, value: $input.val()});
+                       a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+               }
+       }
+       return a;
+};
+
+/**
+ * Serializes form data into a 'submittable' string. This method will return a string
+ * in the format: name1=value1&amp;name2=value2
+ */
+$.fn.formSerialize = function(semantic) {
+       //hand off to jQuery.param for proper encoding
+       return $.param(this.formToArray(semantic));
+};
+
+/**
+ * Serializes all field elements in the jQuery object into a query string.
+ * This method will return a string in the format: name1=value1&amp;name2=value2
+ */
+$.fn.fieldSerialize = function(successful) {
+       var a = [];
+       this.each(function() {
+               var n = this.name;
+               if (!n) {
+                       return;
+               }
+               var v = $.fieldValue(this, successful);
+               if (v && v.constructor == Array) {
+                       for (var i=0,max=v.length; i < max; i++) {
+                               a.push({name: n, value: v[i]});
+                       }
+               }
+               else if (v !== null && typeof v != 'undefined') {
+                       a.push({name: this.name, value: v});
+               }
+       });
+       //hand off to jQuery.param for proper encoding
+       return $.param(a);
+};
+
+/**
+ * Returns the value(s) of the element in the matched set.  For example, consider the following form:
+ *
+ *  <form><fieldset>
+ *       <input name="A" type="text" />
+ *       <input name="A" type="text" />
+ *       <input name="B" type="checkbox" value="B1" />
+ *       <input name="B" type="checkbox" value="B2"/>
+ *       <input name="C" type="radio" value="C1" />
+ *       <input name="C" type="radio" value="C2" />
+ *  </fieldset></form>
+ *
+ *  var v = $(':text').fieldValue();
+ *  // if no values are entered into the text inputs
+ *  v == ['','']
+ *  // if values entered into the text inputs are 'foo' and 'bar'
+ *  v == ['foo','bar']
+ *
+ *  var v = $(':checkbox').fieldValue();
+ *  // if neither checkbox is checked
+ *  v === undefined
+ *  // if both checkboxes are checked
+ *  v == ['B1', 'B2']
+ *
+ *  var v = $(':radio').fieldValue();
+ *  // if neither radio is checked
+ *  v === undefined
+ *  // if first radio is checked
+ *  v == ['C1']
+ *
+ * The successful argument controls whether or not the field element must be 'successful'
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
+ * The default value of the successful argument is true.  If this value is false the value(s)
+ * for each element is returned.
+ *
+ * Note: This method *always* returns an array.  If no valid value can be determined the
+ *        array will be empty, otherwise it will contain one or more values.
+ */
+$.fn.fieldValue = function(successful) {
+       for (var val=[], i=0, max=this.length; i < max; i++) {
+               var el = this[i];
+               var v = $.fieldValue(el, successful);
+               if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
+                       continue;
+               }
+               v.constructor == Array ? $.merge(val, v) : val.push(v);
+       }
+       return val;
+};
+
+/**
+ * Returns the value of the field element.
+ */
+$.fieldValue = function(el, successful) {
+       var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
+       if (successful === undefined) {
+               successful = true;
+       }
+
+       if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
+               (t == 'checkbox' || t == 'radio') && !el.checked ||
+               (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
+               tag == 'select' && el.selectedIndex == -1)) {
+                       return null;
+       }
+
+       if (tag == 'select') {
+               var index = el.selectedIndex;
+               if (index < 0) {
+                       return null;
+               }
+               var a = [], ops = el.options;
+               var one = (t == 'select-one');
+               var max = (one ? index+1 : ops.length);
+               for(var i=(one ? index : 0); i < max; i++) {
+                       var op = ops[i];
+                       if (op.selected) {
+                               var v = op.value;
+                               if (!v) { // extra pain for IE...
+                                       v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
+                               }
+                               if (one) {
+                                       return v;
+                               }
+                               a.push(v);
+                       }
+               }
+               return a;
+       }
+       return $(el).val();
+};
+
+/**
+ * Clears the form data.  Takes the following actions on the form's input fields:
+ *  - input text fields will have their 'value' property set to the empty string
+ *  - select elements will have their 'selectedIndex' property set to -1
+ *  - checkbox and radio inputs will have their 'checked' property set to false
+ *  - inputs of type submit, button, reset, and hidden will *not* be effected
+ *  - button elements will *not* be effected
+ */
+$.fn.clearForm = function() {
+       return this.each(function() {
+               $('input,select,textarea', this).clearFields();
+       });
+};
+
+/**
+ * Clears the selected form elements.
+ */
+$.fn.clearFields = $.fn.clearInputs = function() {
+       return this.each(function() {
+               var t = this.type, tag = this.tagName.toLowerCase();
+               if (t == 'text' || t == 'password' || tag == 'textarea') {
+                       this.value = '';
+               }
+               else if (t == 'checkbox' || t == 'radio') {
+                       this.checked = false;
+               }
+               else if (tag == 'select') {
+                       this.selectedIndex = -1;
+               }
+       });
+};
+
+/**
+ * Resets the form data.  Causes all form elements to be reset to their original value.
+ */
+$.fn.resetForm = function() {
+       return this.each(function() {
+               // guard against an input with the name of 'reset'
+               // note that IE reports the reset function as an 'object'
+               if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
+                       this.reset();
+               }
+       });
+};
+
+/**
+ * Enables or disables any matching elements.
+ */
+$.fn.enable = function(b) {
+       if (b === undefined) {
+               b = true;
+       }
+       return this.each(function() {
+               this.disabled = !b;
+       });
+};
+
+/**
+ * Checks/unchecks any matching checkboxes or radio buttons and
+ * selects/deselects and matching option elements.
+ */
+$.fn.selected = function(select) {
+       if (select === undefined) {
+               select = true;
+       }
+       return this.each(function() {
+               var t = this.type;
+               if (t == 'checkbox' || t == 'radio') {
+                       this.checked = select;
+               }
+               else if (this.tagName.toLowerCase() == 'option') {
+                       var $sel = $(this).parent('select');
+                       if (select && $sel[0] && $sel[0].type == 'select-one') {
+                               // deselect all other options
+                               $sel.find('option').selected(false);
+                       }
+                       this.selected = select;
+               }
+       });
+};
+
+// helper fn for console logging
+// set $.fn.ajaxSubmit.debug to true to enable debug logging
+function log() {
+       if ($.fn.ajaxSubmit.debug) {
+               var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+               if (window.console && window.console.log) {
+                       window.console.log(msg);
+               }
+               else if (window.opera && window.opera.postError) {
+                       window.opera.postError(msg);
+               }
+       }
+};
+
+})(jQuery);
diff --git a/www/plugins/crayons/js/jquery.html5uploader.min.js b/www/plugins/crayons/js/jquery.html5uploader.min.js
new file mode 100644 (file)
index 0000000..3e18698
--- /dev/null
@@ -0,0 +1,17 @@
+/*!
+* jQuery HTML5 Uploader 1.0b
+*
+* http://www.igloolab.com/jquery-html5-uploader
+*/
+(function($){$.fn.html5Uploader=function(options){var crlf='\r\n';var boundary="iloveigloo";var dashes="--";var settings={"name":"uploadedFile","postUrl":"Upload.aspx","onClientAbort":null,"onClientError":null,"onClientLoad":null,"onClientLoadEnd":null,"onClientLoadStart":null,"onClientProgress":null,"onServerAbort":null,"onServerError":null,"onServerLoad":null,"onServerLoadStart":null,"onServerProgress":null,"onServerReadyStateChange":null};if(options){$.extend(settings,options);}
+return this.each(function(options){var $this=$(this);if($this.is("[type='file']")){$this
+.bind("change",function(){var files=this.files;for(var i=0;i<files.length;i++){fileHandler(files[i]);}});}else{$this
+.bind("dragenter dragover",function(){return false;})
+.bind("drop",function(e){var files=e.originalEvent.dataTransfer.files;for(var i=0;i<files.length;i++){fileHandler(files[i]);}
+return false;});}});function fileHandler(file){var fileReader=new FileReader();fileReader.onabort=function(e){if(settings.onClientAbort){settings.onClientAbort(e,file);}};fileReader.onerror=function(e){if(settings.onClientError){settings.onClientError(e,file);}};fileReader.onload=function(e){if(settings.onClientLoad){settings.onClientLoad(e,file);}};fileReader.onloadend=function(e){if(settings.onClientLoadEnd){settings.onClientLoadEnd(e,file);}};fileReader.onloadstart=function(e){if(settings.onClientLoadStart){settings.onClientLoadStart(e,file);}};fileReader.onprogress=function(e){if(settings.onClientProgress){settings.onClientProgress(e,file);}};fileReader.readAsDataURL(file);var xmlHttpRequest=new XMLHttpRequest();xmlHttpRequest.upload.onabort=function(e){if(settings.onServerAbort){settings.onServerAbort(e,file);}};xmlHttpRequest.upload.onerror=function(e){if(settings.onServerError){settings.onServerError(e,file);}};xmlHttpRequest.upload.onload=function(e){if(settings.onServerLoad){settings.onServerLoad(e,file);}};xmlHttpRequest.upload.onloadstart=function(e){if(settings.onServerLoadStart){settings.onServerLoadStart(e,file);}};xmlHttpRequest.upload.onprogress=function(e){if(settings.onServerProgress){settings.onServerProgress(e,file);}};xmlHttpRequest.onreadystatechange=function(e){if(settings.onServerReadyStateChange){settings.onServerReadyStateChange(e,file);}};xmlHttpRequest.open("POST",settings.postUrl,true);if(file.getAsBinary){var data=dashes+boundary+crlf+
+"Content-Disposition: form-data;"+
+"name=\""+settings.name+"\";"+
+"filename=\""+unescape(encodeURIComponent(file.name))+"\""+crlf+
+"Content-Type: application/octet-stream"+crlf+crlf+
+file.getAsBinary()+crlf+
+dashes+boundary+dashes;xmlHttpRequest.setRequestHeader("Content-Type","multipart/form-data;boundary="+boundary);xmlHttpRequest.sendAsBinary(data);}else if(window.FormData){var formData=new FormData();formData.append(settings.name,file);xmlHttpRequest.send(formData);}}};})(jQuery);
diff --git a/www/plugins/crayons/js/jquery.js b/www/plugins/crayons/js/jquery.js
new file mode 100644 (file)
index 0000000..9a13ab9
--- /dev/null
@@ -0,0 +1,8865 @@
+/*!
+ * jQuery JavaScript Library v1.6
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Mon May 2 13:50:00 2011 -0400
+ */
+(function( window, undefined ) {
+
+// Use the correct document accordingly with window argument (sandbox)
+var document = window.document,
+       navigator = window.navigator,
+       location = window.location;
+var jQuery = (function() {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+               // The jQuery object is actually just the init constructor 'enhanced'
+               return new jQuery.fn.init( selector, context, rootjQuery );
+       },
+
+       // Map over jQuery in case of overwrite
+       _jQuery = window.jQuery,
+
+       // Map over the $ in case of overwrite
+       _$ = window.$,
+
+       // A central reference to the root jQuery(document)
+       rootjQuery,
+
+       // A simple way to check for HTML strings or ID strings
+       // (both of which we optimize for)
+       quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+       // Check if a string has a non-whitespace character in it
+       rnotwhite = /\S/,
+
+       // Used for trimming whitespace
+       trimLeft = /^\s+/,
+       trimRight = /\s+$/,
+
+       // Check for digits
+       rdigit = /\d/,
+
+       // Match a standalone tag
+       rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+       // JSON RegExp
+       rvalidchars = /^[\],:{}\s]*$/,
+       rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+       rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+       rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+       // Useragent RegExp
+       rwebkit = /(webkit)[ \/]([\w.]+)/,
+       ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+       rmsie = /(msie) ([\w.]+)/,
+       rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
+       // Keep a UserAgent string for use with jQuery.browser
+       userAgent = navigator.userAgent,
+
+       // For matching the engine and version of the browser
+       browserMatch,
+
+       // The deferred used on DOM ready
+       readyList,
+
+       // The ready event handler
+       DOMContentLoaded,
+
+       // Save a reference to some core methods
+       toString = Object.prototype.toString,
+       hasOwn = Object.prototype.hasOwnProperty,
+       push = Array.prototype.push,
+       slice = Array.prototype.slice,
+       trim = String.prototype.trim,
+       indexOf = Array.prototype.indexOf,
+
+       // [[Class]] -> type pairs
+       class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+       constructor: jQuery,
+       init: function( selector, context, rootjQuery ) {
+               var match, elem, ret, doc;
+
+               // Handle $(""), $(null), or $(undefined)
+               if ( !selector ) {
+                       return this;
+               }
+
+               // Handle $(DOMElement)
+               if ( selector.nodeType ) {
+                       this.context = this[0] = selector;
+                       this.length = 1;
+                       return this;
+               }
+
+               // The body element only exists once, optimize finding it
+               if ( selector === "body" && !context && document.body ) {
+                       this.context = document;
+                       this[0] = document.body;
+                       this.selector = selector;
+                       this.length = 1;
+                       return this;
+               }
+
+               // Handle HTML strings
+               if ( typeof selector === "string" ) {
+                       // Are we dealing with HTML string or an ID?
+                       if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+                               // Assume that strings that start and end with <> are HTML and skip the regex check
+                               match = [ null, selector, null ];
+
+                       } else {
+                               match = quickExpr.exec( selector );
+                       }
+
+                       // Verify a match, and that no context was specified for #id
+                       if ( match && (match[1] || !context) ) {
+
+                               // HANDLE: $(html) -> $(array)
+                               if ( match[1] ) {
+                                       context = context instanceof jQuery ? context[0] : context;
+                                       doc = (context ? context.ownerDocument || context : document);
+
+                                       // If a single string is passed in and it's a single tag
+                                       // just do a createElement and skip the rest
+                                       ret = rsingleTag.exec( selector );
+
+                                       if ( ret ) {
+                                               if ( jQuery.isPlainObject( context ) ) {
+                                                       selector = [ document.createElement( ret[1] ) ];
+                                                       jQuery.fn.attr.call( selector, context, true );
+
+                                               } else {
+                                                       selector = [ doc.createElement( ret[1] ) ];
+                                               }
+
+                                       } else {
+                                               ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+                                               selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;
+                                       }
+
+                                       return jQuery.merge( this, selector );
+
+                               // HANDLE: $("#id")
+                               } else {
+                                       elem = document.getElementById( match[2] );
+
+                                       // Check parentNode to catch when Blackberry 4.6 returns
+                                       // nodes that are no longer in the document #6963
+                                       if ( elem && elem.parentNode ) {
+                                               // Handle the case where IE and Opera return items
+                                               // by name instead of ID
+                                               if ( elem.id !== match[2] ) {
+                                                       return rootjQuery.find( selector );
+                                               }
+
+                                               // Otherwise, we inject the element directly into the jQuery object
+                                               this.length = 1;
+                                               this[0] = elem;
+                                       }
+
+                                       this.context = document;
+                                       this.selector = selector;
+                                       return this;
+                               }
+
+                       // HANDLE: $(expr, $(...))
+                       } else if ( !context || context.jquery ) {
+                               return (context || rootjQuery).find( selector );
+
+                       // HANDLE: $(expr, context)
+                       // (which is just equivalent to: $(context).find(expr)
+                       } else {
+                               return this.constructor( context ).find( selector );
+                       }
+
+               // HANDLE: $(function)
+               // Shortcut for document ready
+               } else if ( jQuery.isFunction( selector ) ) {
+                       return rootjQuery.ready( selector );
+               }
+
+               if (selector.selector !== undefined) {
+                       this.selector = selector.selector;
+                       this.context = selector.context;
+               }
+
+               return jQuery.makeArray( selector, this );
+       },
+
+       // Start with an empty selector
+       selector: "",
+
+       // The current version of jQuery being used
+       jquery: "1.6",
+
+       // The default length of a jQuery object is 0
+       length: 0,
+
+       // The number of elements contained in the matched element set
+       size: function() {
+               return this.length;
+       },
+
+       toArray: function() {
+               return slice.call( this, 0 );
+       },
+
+       // Get the Nth element in the matched element set OR
+       // Get the whole matched element set as a clean array
+       get: function( num ) {
+               return num == null ?
+
+                       // Return a 'clean' array
+                       this.toArray() :
+
+                       // Return just the object
+                       ( num < 0 ? this[ this.length + num ] : this[ num ] );
+       },
+
+       // Take an array of elements and push it onto the stack
+       // (returning the new matched element set)
+       pushStack: function( elems, name, selector ) {
+               // Build a new jQuery matched element set
+               var ret = this.constructor();
+
+               if ( jQuery.isArray( elems ) ) {
+                       push.apply( ret, elems );
+
+               } else {
+                       jQuery.merge( ret, elems );
+               }
+
+               // Add the old object onto the stack (as a reference)
+               ret.prevObject = this;
+
+               ret.context = this.context;
+
+               if ( name === "find" ) {
+                       ret.selector = this.selector + (this.selector ? " " : "") + selector;
+               } else if ( name ) {
+                       ret.selector = this.selector + "." + name + "(" + selector + ")";
+               }
+
+               // Return the newly-formed element set
+               return ret;
+       },
+
+       // Execute a callback for every element in the matched set.
+       // (You can seed the arguments with an array of args, but this is
+       // only used internally.)
+       each: function( callback, args ) {
+               return jQuery.each( this, callback, args );
+       },
+
+       ready: function( fn ) {
+               // Attach the listeners
+               jQuery.bindReady();
+
+               // Add the callback
+               readyList.done( fn );
+
+               return this;
+       },
+
+       eq: function( i ) {
+               return i === -1 ?
+                       this.slice( i ) :
+                       this.slice( i, +i + 1 );
+       },
+
+       first: function() {
+               return this.eq( 0 );
+       },
+
+       last: function() {
+               return this.eq( -1 );
+       },
+
+       slice: function() {
+               return this.pushStack( slice.apply( this, arguments ),
+                       "slice", slice.call(arguments).join(",") );
+       },
+
+       map: function( callback ) {
+               return this.pushStack( jQuery.map(this, function( elem, i ) {
+                       return callback.call( elem, i, elem );
+               }));
+       },
+
+       end: function() {
+               return this.prevObject || this.constructor(null);
+       },
+
+       // For internal use only.
+       // Behaves like an Array's method, not like a jQuery method.
+       push: push,
+       sort: [].sort,
+       splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+       var options, name, src, copy, copyIsArray, clone,
+               target = arguments[0] || {},
+               i = 1,
+               length = arguments.length,
+               deep = false;
+
+       // Handle a deep copy situation
+       if ( typeof target === "boolean" ) {
+               deep = target;
+               target = arguments[1] || {};
+               // skip the boolean and the target
+               i = 2;
+       }
+
+       // Handle case when target is a string or something (possible in deep copy)
+       if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+               target = {};
+       }
+
+       // extend jQuery itself if only one argument is passed
+       if ( length === i ) {
+               target = this;
+               --i;
+       }
+
+       for ( ; i < length; i++ ) {
+               // Only deal with non-null/undefined values
+               if ( (options = arguments[ i ]) != null ) {
+                       // Extend the base object
+                       for ( name in options ) {
+                               src = target[ name ];
+                               copy = options[ name ];
+
+                               // Prevent never-ending loop
+                               if ( target === copy ) {
+                                       continue;
+                               }
+
+                               // Recurse if we're merging plain objects or arrays
+                               if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+                                       if ( copyIsArray ) {
+                                               copyIsArray = false;
+                                               clone = src && jQuery.isArray(src) ? src : [];
+
+                                       } else {
+                                               clone = src && jQuery.isPlainObject(src) ? src : {};
+                                       }
+
+                                       // Never move original objects, clone them
+                                       target[ name ] = jQuery.extend( deep, clone, copy );
+
+                               // Don't bring in undefined values
+                               } else if ( copy !== undefined ) {
+                                       target[ name ] = copy;
+                               }
+                       }
+               }
+       }
+
+       // Return the modified object
+       return target;
+};
+
+jQuery.extend({
+       noConflict: function( deep ) {
+               if ( window.$ === jQuery ) {
+                       window.$ = _$;
+               }
+
+               if ( deep && window.jQuery === jQuery ) {
+                       window.jQuery = _jQuery;
+               }
+
+               return jQuery;
+       },
+
+       // Is the DOM ready to be used? Set to true once it occurs.
+       isReady: false,
+
+       // A counter to track how many items to wait for before
+       // the ready event fires. See #6781
+       readyWait: 1,
+
+       // Hold (or release) the ready event
+       holdReady: function( hold ) {
+               if ( hold ) {
+                       jQuery.readyWait++;
+               } else {
+                       jQuery.ready( true );
+               }
+       },
+
+       // Handle when the DOM is ready
+       ready: function( wait ) {
+               // Either a released hold or an DOMready/load event and not yet ready
+               if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
+                       // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+                       if ( !document.body ) {
+                               return setTimeout( jQuery.ready, 1 );
+                       }
+
+                       // Remember that the DOM is ready
+                       jQuery.isReady = true;
+
+                       // If a normal DOM Ready event fired, decrement, and wait if need be
+                       if ( wait !== true && --jQuery.readyWait > 0 ) {
+                               return;
+                       }
+
+                       // If there are functions bound, to execute
+                       readyList.resolveWith( document, [ jQuery ] );
+
+                       // Trigger any bound ready events
+                       if ( jQuery.fn.trigger ) {
+                               jQuery( document ).trigger( "ready" ).unbind( "ready" );
+                       }
+               }
+       },
+
+       bindReady: function() {
+               if ( readyList ) {
+                       return;
+               }
+
+               readyList = jQuery._Deferred();
+
+               // Catch cases where $(document).ready() is called after the
+               // browser event has already occurred.
+               if ( document.readyState === "complete" ) {
+                       // Handle it asynchronously to allow scripts the opportunity to delay ready
+                       return setTimeout( jQuery.ready, 1 );
+               }
+
+               // Mozilla, Opera and webkit nightlies currently support this event
+               if ( document.addEventListener ) {
+                       // Use the handy event callback
+                       document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+                       // A fallback to window.onload, that will always work
+                       window.addEventListener( "load", jQuery.ready, false );
+
+               // If IE event model is used
+               } else if ( document.attachEvent ) {
+                       // ensure firing before onload,
+                       // maybe late but safe also for iframes
+                       document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+                       // A fallback to window.onload, that will always work
+                       window.attachEvent( "onload", jQuery.ready );
+
+                       // If IE and not a frame
+                       // continually check to see if the document is ready
+                       var toplevel = false;
+
+                       try {
+                               toplevel = window.frameElement == null;
+                       } catch(e) {}
+
+                       if ( document.documentElement.doScroll && toplevel ) {
+                               doScrollCheck();
+                       }
+               }
+       },
+
+       // See test/unit/core.js for details concerning isFunction.
+       // Since version 1.3, DOM methods and functions like alert
+       // aren't supported. They return false on IE (#2968).
+       isFunction: function( obj ) {
+               return jQuery.type(obj) === "function";
+       },
+
+       isArray: Array.isArray || function( obj ) {
+               return jQuery.type(obj) === "array";
+       },
+
+       // A crude way of determining if an object is a window
+       isWindow: function( obj ) {
+               return obj && typeof obj === "object" && "setInterval" in obj;
+       },
+
+       isNaN: function( obj ) {
+               return obj == null || !rdigit.test( obj ) || isNaN( obj );
+       },
+
+       type: function( obj ) {
+               return obj == null ?
+                       String( obj ) :
+                       class2type[ toString.call(obj) ] || "object";
+       },
+
+       isPlainObject: function( obj ) {
+               // Must be an Object.
+               // Because of IE, we also have to check the presence of the constructor property.
+               // Make sure that DOM nodes and window objects don't pass through, as well
+               if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+                       return false;
+               }
+
+               // Not own constructor property must be Object
+               if ( obj.constructor &&
+                       !hasOwn.call(obj, "constructor") &&
+                       !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+                       return false;
+               }
+
+               // Own properties are enumerated firstly, so to speed up,
+               // if last one is own, then all properties are own.
+
+               var key;
+               for ( key in obj ) {}
+
+               return key === undefined || hasOwn.call( obj, key );
+       },
+
+       isEmptyObject: function( obj ) {
+               for ( var name in obj ) {
+                       return false;
+               }
+               return true;
+       },
+
+       error: function( msg ) {
+               throw msg;
+       },
+
+       parseJSON: function( data ) {
+               if ( typeof data !== "string" || !data ) {
+                       return null;
+               }
+
+               // Make sure leading/trailing whitespace is removed (IE can't handle it)
+               data = jQuery.trim( data );
+
+               // Attempt to parse using the native JSON parser first
+               if ( window.JSON && window.JSON.parse ) {
+                       return window.JSON.parse( data );
+               }
+
+               // Make sure the incoming data is actual JSON
+               // Logic borrowed from http://json.org/json2.js
+               if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+                       .replace( rvalidtokens, "]" )
+                       .replace( rvalidbraces, "")) ) {
+
+                       return (new Function( "return " + data ))();
+
+               }
+               jQuery.error( "Invalid JSON: " + data );
+       },
+
+       // Cross-browser xml parsing
+       // (xml & tmp used internally)
+       parseXML: function( data , xml , tmp ) {
+
+               if ( window.DOMParser ) { // Standard
+                       tmp = new DOMParser();
+                       xml = tmp.parseFromString( data , "text/xml" );
+               } else { // IE
+                       xml = new ActiveXObject( "Microsoft.XMLDOM" );
+                       xml.async = "false";
+                       xml.loadXML( data );
+               }
+
+               tmp = xml.documentElement;
+
+               if ( ! tmp || ! tmp.nodeName || tmp.nodeName === "parsererror" ) {
+                       jQuery.error( "Invalid XML: " + data );
+               }
+
+               return xml;
+       },
+
+       noop: function() {},
+
+       // Evaluates a script in a global context
+       // Workarounds based on findings by Jim Driscoll
+       // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+       globalEval: function( data ) {
+               if ( data && rnotwhite.test( data ) ) {
+                       // We use execScript on Internet Explorer
+                       // We use an anonymous function so that context is window
+                       // rather than jQuery in Firefox
+                       ( window.execScript || function( data ) {
+                               window[ "eval" ].call( window, data );
+                       } )( data );
+               }
+       },
+
+       nodeName: function( elem, name ) {
+               return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+       },
+
+       // args is for internal usage only
+       each: function( object, callback, args ) {
+               var name, i = 0,
+                       length = object.length,
+                       isObj = length === undefined || jQuery.isFunction( object );
+
+               if ( args ) {
+                       if ( isObj ) {
+                               for ( name in object ) {
+                                       if ( callback.apply( object[ name ], args ) === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( ; i < length; ) {
+                                       if ( callback.apply( object[ i++ ], args ) === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+
+               // A special, fast, case for the most common use of each
+               } else {
+                       if ( isObj ) {
+                               for ( name in object ) {
+                                       if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+                                               break;
+                                       }
+                               }
+                       } else {
+                               for ( ; i < length; ) {
+                                       if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               return object;
+       },
+
+       // Use native String.trim function wherever possible
+       trim: trim ?
+               function( text ) {
+                       return text == null ?
+                               "" :
+                               trim.call( text );
+               } :
+
+               // Otherwise use our own trimming functionality
+               function( text ) {
+                       return text == null ?
+                               "" :
+                               text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+               },
+
+       // results is for internal usage only
+       makeArray: function( array, results ) {
+               var ret = results || [];
+
+               if ( array != null ) {
+                       // The window, strings (and functions) also have 'length'
+                       // The extra typeof function check is to prevent crashes
+                       // in Safari 2 (See: #3039)
+                       // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+                       var type = jQuery.type( array );
+
+                       if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
+                               push.call( ret, array );
+                       } else {
+                               jQuery.merge( ret, array );
+                       }
+               }
+
+               return ret;
+       },
+
+       inArray: function( elem, array ) {
+
+               if ( indexOf ) {
+                       return indexOf.call( array, elem );
+               }
+
+               for ( var i = 0, length = array.length; i < length; i++ ) {
+                       if ( array[ i ] === elem ) {
+                               return i;
+                       }
+               }
+
+               return -1;
+       },
+
+       merge: function( first, second ) {
+               var i = first.length,
+                       j = 0;
+
+               if ( typeof second.length === "number" ) {
+                       for ( var l = second.length; j < l; j++ ) {
+                               first[ i++ ] = second[ j ];
+                       }
+
+               } else {
+                       while ( second[j] !== undefined ) {
+                               first[ i++ ] = second[ j++ ];
+                       }
+               }
+
+               first.length = i;
+
+               return first;
+       },
+
+       grep: function( elems, callback, inv ) {
+               var ret = [], retVal;
+               inv = !!inv;
+
+               // Go through the array, only saving the items
+               // that pass the validator function
+               for ( var i = 0, length = elems.length; i < length; i++ ) {
+                       retVal = !!callback( elems[ i ], i );
+                       if ( inv !== retVal ) {
+                               ret.push( elems[ i ] );
+                       }
+               }
+
+               return ret;
+       },
+
+       // arg is for internal usage only
+       map: function( elems, callback, arg ) {
+               var value, key, ret = [],
+                       i = 0,
+                       length = elems.length,
+                       // jquery objects are treated as arrays
+                       isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+               // Go through the array, translating each of the items to their
+               if ( isArray ) {
+                       for ( ; i < length; i++ ) {
+                               value = callback( elems[ i ], i, arg );
+
+                               if ( value != null ) {
+                                       ret[ ret.length ] = value;
+                               }
+                       }
+
+               // Go through every key on the object,
+               } else {
+                       for ( key in elems ) {
+                               value = callback( elems[ key ], key, arg );
+
+                               if ( value != null ) {
+                                       ret[ ret.length ] = value;
+                               }
+                       }
+               }
+
+               // Flatten any nested arrays
+               return ret.concat.apply( [], ret );
+       },
+
+       // A global GUID counter for objects
+       guid: 1,
+
+       // Bind a function to a context, optionally partially applying any
+       // arguments.
+       proxy: function( fn, context ) {
+               if ( typeof context === "string" ) {
+                       var tmp = fn[ context ];
+                       context = fn;
+                       fn = tmp;
+               }
+
+               // Quick check to determine if target is callable, in the spec
+               // this throws a TypeError, but we will just return undefined.
+               if ( !jQuery.isFunction( fn ) ) {
+                       return undefined;
+               }
+
+               // Simulated bind
+               var args = slice.call( arguments, 2 ),
+                       proxy = function() {
+                               return fn.apply( context, args.concat( slice.call( arguments ) ) );
+                       };
+
+               // Set the guid of unique handler to the same of original handler, so it can be removed
+               proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+
+               return proxy;
+       },
+
+       // Mutifunctional method to get and set values to a collection
+       // The value/s can be optionally by executed if its a function
+       access: function( elems, key, value, exec, fn, pass ) {
+               var length = elems.length;
+
+               // Setting many attributes
+               if ( typeof key === "object" ) {
+                       for ( var k in key ) {
+                               jQuery.access( elems, k, key[k], exec, fn, value );
+                       }
+                       return elems;
+               }
+
+               // Setting one attribute
+               if ( value !== undefined ) {
+                       // Optionally, function values get executed if exec is true
+                       exec = !pass && exec && jQuery.isFunction(value);
+
+                       for ( var i = 0; i < length; i++ ) {
+                               fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+                       }
+
+                       return elems;
+               }
+
+               // Getting an attribute
+               return length ? fn( elems[0], key ) : undefined;
+       },
+
+       now: function() {
+               return (new Date()).getTime();
+       },
+
+       // Use of jQuery.browser is frowned upon.
+       // More details: http://docs.jquery.com/Utilities/jQuery.browser
+       uaMatch: function( ua ) {
+               ua = ua.toLowerCase();
+
+               var match = rwebkit.exec( ua ) ||
+                       ropera.exec( ua ) ||
+                       rmsie.exec( ua ) ||
+                       ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+                       [];
+
+               return { browser: match[1] || "", version: match[2] || "0" };
+       },
+
+       sub: function() {
+               function jQuerySub( selector, context ) {
+                       return new jQuerySub.fn.init( selector, context );
+               }
+               jQuery.extend( true, jQuerySub, this );
+               jQuerySub.superclass = this;
+               jQuerySub.fn = jQuerySub.prototype = this();
+               jQuerySub.fn.constructor = jQuerySub;
+               jQuerySub.sub = this.sub;
+               jQuerySub.fn.init = function init( selector, context ) {
+                       if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+                               context = jQuerySub( context );
+                       }
+
+                       return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+               };
+               jQuerySub.fn.init.prototype = jQuerySub.fn;
+               var rootjQuerySub = jQuerySub(document);
+               return jQuerySub;
+       },
+
+       browser: {}
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+       class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+       jQuery.browser[ browserMatch.browser ] = true;
+       jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+       jQuery.browser.safari = true;
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+       trimLeft = /^[\s\xA0]+/;
+       trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+       DOMContentLoaded = function() {
+               document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+               jQuery.ready();
+       };
+
+} else if ( document.attachEvent ) {
+       DOMContentLoaded = function() {
+               // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+               if ( document.readyState === "complete" ) {
+                       document.detachEvent( "onreadystatechange", DOMContentLoaded );
+                       jQuery.ready();
+               }
+       };
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+       if ( jQuery.isReady ) {
+               return;
+       }
+
+       try {
+               // If IE is used, use the trick by Diego Perini
+               // http://javascript.nwbox.com/IEContentLoaded/
+               document.documentElement.doScroll("left");
+       } catch(e) {
+               setTimeout( doScrollCheck, 1 );
+               return;
+       }
+
+       // and execute any waiting functions
+       jQuery.ready();
+}
+
+// Expose jQuery to the global object
+return jQuery;
+
+})();
+
+
+var // Promise methods
+       promiseMethods = "done fail isResolved isRejected promise then always pipe".split( " " ),
+       // Static reference to slice
+       sliceDeferred = [].slice;
+
+jQuery.extend({
+       // Create a simple deferred (one callbacks list)
+       _Deferred: function() {
+               var // callbacks list
+                       callbacks = [],
+                       // stored [ context , args ]
+                       fired,
+                       // to avoid firing when already doing so
+                       firing,
+                       // flag to know if the deferred has been cancelled
+                       cancelled,
+                       // the deferred itself
+                       deferred  = {
+
+                               // done( f1, f2, ...)
+                               done: function() {
+                                       if ( !cancelled ) {
+                                               var args = arguments,
+                                                       i,
+                                                       length,
+                                                       elem,
+                                                       type,
+                                                       _fired;
+                                               if ( fired ) {
+                                                       _fired = fired;
+                                                       fired = 0;
+                                               }
+                                               for ( i = 0, length = args.length; i < length; i++ ) {
+                                                       elem = args[ i ];
+                                                       type = jQuery.type( elem );
+                                                       if ( type === "array" ) {
+                                                               deferred.done.apply( deferred, elem );
+                                                       } else if ( type === "function" ) {
+                                                               callbacks.push( elem );
+                                                       }
+                                               }
+                                               if ( _fired ) {
+                                                       deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );
+                                               }
+                                       }
+                                       return this;
+                               },
+
+                               // resolve with given context and args
+                               resolveWith: function( context, args ) {
+                                       if ( !cancelled && !fired && !firing ) {
+                                               // make sure args are available (#8421)
+                                               args = args || [];
+                                               firing = 1;
+                                               try {
+                                                       while( callbacks[ 0 ] ) {
+                                                               callbacks.shift().apply( context, args );
+                                                       }
+                                               }
+                                               finally {
+                                                       fired = [ context, args ];
+                                                       firing = 0;
+                                               }
+                                       }
+                                       return this;
+                               },
+
+                               // resolve with this as context and given arguments
+                               resolve: function() {
+                                       deferred.resolveWith( this, arguments );
+                                       return this;
+                               },
+
+                               // Has this deferred been resolved?
+                               isResolved: function() {
+                                       return !!( firing || fired );
+                               },
+
+                               // Cancel
+                               cancel: function() {
+                                       cancelled = 1;
+                                       callbacks = [];
+                                       return this;
+                               }
+                       };
+
+               return deferred;
+       },
+
+       // Full fledged deferred (two callbacks list)
+       Deferred: function( func ) {
+               var deferred = jQuery._Deferred(),
+                       failDeferred = jQuery._Deferred(),
+                       promise;
+               // Add errorDeferred methods, then and promise
+               jQuery.extend( deferred, {
+                       then: function( doneCallbacks, failCallbacks ) {
+                               deferred.done( doneCallbacks ).fail( failCallbacks );
+                               return this;
+                       },
+                       always: function() {
+                               return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments );
+                       },
+                       fail: failDeferred.done,
+                       rejectWith: failDeferred.resolveWith,
+                       reject: failDeferred.resolve,
+                       isRejected: failDeferred.isResolved,
+                       pipe: function( fnDone, fnFail ) {
+                               return jQuery.Deferred(function( newDefer ) {
+                                       jQuery.each( {
+                                               done: [ fnDone, "resolve" ],
+                                               fail: [ fnFail, "reject" ]
+                                       }, function( handler, data ) {
+                                               var fn = data[ 0 ],
+                                                       action = data[ 1 ],
+                                                       returned;
+                                               if ( jQuery.isFunction( fn ) ) {
+                                                       deferred[ handler ](function() {
+                                                               returned = fn.apply( this, arguments );
+                                                               if ( jQuery.isFunction( returned.promise ) ) {
+                                                                       returned.promise().then( newDefer.resolve, newDefer.reject );
+                                                               } else {
+                                                                       newDefer[ action ]( returned );
+                                                               }
+                                                       });
+                                               } else {
+                                                       deferred[ handler ]( newDefer[ action ] );
+                                               }
+                                       });
+                               }).promise();
+                       },
+                       // Get a promise for this deferred
+                       // If obj is provided, the promise aspect is added to the object
+                       promise: function( obj ) {
+                               if ( obj == null ) {
+                                       if ( promise ) {
+                                               return promise;
+                                       }
+                                       promise = obj = {};
+                               }
+                               var i = promiseMethods.length;
+                               while( i-- ) {
+                                       obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];
+                               }
+                               return obj;
+                       }
+               });
+               // Make sure only one callback list will be used
+               deferred.done( failDeferred.cancel ).fail( deferred.cancel );
+               // Unexpose cancel
+               delete deferred.cancel;
+               // Call given func if any
+               if ( func ) {
+                       func.call( deferred, deferred );
+               }
+               return deferred;
+       },
+
+       // Deferred helper
+       when: function( firstParam ) {
+               var args = arguments,
+                       i = 0,
+                       length = args.length,
+                       count = length,
+                       deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+                               firstParam :
+                               jQuery.Deferred();
+               function resolveFunc( i ) {
+                       return function( value ) {
+                               args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+                               if ( !( --count ) ) {
+                                       // Strange bug in FF4:
+                                       // Values changed onto the arguments object sometimes end up as undefined values
+                                       // outside the $.when method. Cloning the object into a fresh array solves the issue
+                                       deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );
+                               }
+                       };
+               }
+               if ( length > 1 ) {
+                       for( ; i < length; i++ ) {
+                               if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {
+                                       args[ i ].promise().then( resolveFunc(i), deferred.reject );
+                               } else {
+                                       --count;
+                               }
+                       }
+                       if ( !count ) {
+                               deferred.resolveWith( deferred, args );
+                       }
+               } else if ( deferred !== firstParam ) {
+                       deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+               }
+               return deferred.promise();
+       }
+});
+
+
+
+jQuery.support = (function() {
+
+       var div = document.createElement( "div" ),
+               all,
+               a,
+               select,
+               opt,
+               input,
+               marginDiv,
+               support,
+               fragment,
+               body,
+               bodyStyle,
+               tds,
+               events,
+               eventName,
+               i,
+               isSupported;
+
+       // Preliminary tests
+       div.setAttribute("className", "t");
+       div.innerHTML = "   <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+       all = div.getElementsByTagName( "*" );
+       a = div.getElementsByTagName( "a" )[ 0 ];
+
+       // Can't get basic test support
+       if ( !all || !all.length || !a ) {
+               return {};
+       }
+
+       // First batch of supports tests
+       select = document.createElement( "select" );
+       opt = select.appendChild( document.createElement("option") );
+       input = div.getElementsByTagName( "input" )[ 0 ];
+
+       support = {
+               // IE strips leading whitespace when .innerHTML is used
+               leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+               // Make sure that tbody elements aren't automatically inserted
+               // IE will insert them into empty tables
+               tbody: !div.getElementsByTagName( "tbody" ).length,
+
+               // Make sure that link elements get serialized correctly by innerHTML
+               // This requires a wrapper element in IE
+               htmlSerialize: !!div.getElementsByTagName( "link" ).length,
+
+               // Get the style information from getAttribute
+               // (IE uses .cssText instead)
+               style: /top/.test( a.getAttribute("style") ),
+
+               // Make sure that URLs aren't manipulated
+               // (IE normalizes it by default)
+               hrefNormalized: ( a.getAttribute( "href" ) === "/a" ),
+
+               // Make sure that element opacity exists
+               // (IE uses filter instead)
+               // Use a regex to work around a WebKit issue. See #5145
+               opacity: /^0.55$/.test( a.style.opacity ),
+
+               // Verify style float existence
+               // (IE uses styleFloat instead of cssFloat)
+               cssFloat: !!a.style.cssFloat,
+
+               // Make sure that if no value is specified for a checkbox
+               // that it defaults to "on".
+               // (WebKit defaults to "" instead)
+               checkOn: ( input.value === "on" ),
+
+               // Make sure that a selected-by-default option has a working selected property.
+               // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+               optSelected: opt.selected,
+
+               // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+               getSetAttribute: div.className !== "t",
+
+               // Will be defined later
+               submitBubbles: true,
+               changeBubbles: true,
+               focusinBubbles: false,
+               deleteExpando: true,
+               noCloneEvent: true,
+               inlineBlockNeedsLayout: false,
+               shrinkWrapBlocks: false,
+               reliableMarginRight: true
+       };
+
+       // Make sure checked status is properly cloned
+       input.checked = true;
+       support.noCloneChecked = input.cloneNode( true ).checked;
+
+       // Make sure that the options inside disabled selects aren't marked as disabled
+       // (WebKit marks them as disabled)
+       select.disabled = true;
+       support.optDisabled = !opt.disabled;
+
+       // Test to see if it's possible to delete an expando from an element
+       // Fails in Internet Explorer
+       try {
+               delete div.test;
+       } catch( e ) {
+               support.deleteExpando = false;
+       }
+
+       if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+               div.attachEvent( "onclick", function click() {
+                       // Cloning a node shouldn't copy over any
+                       // bound event handlers (IE does this)
+                       support.noCloneEvent = false;
+                       div.detachEvent( "onclick", click );
+               });
+               div.cloneNode( true ).fireEvent( "onclick" );
+       }
+
+       // Check if a radio maintains it's value
+       // after being appended to the DOM
+       input = document.createElement("input");
+       input.value = "t";
+       input.setAttribute("type", "radio");
+       support.radioValue = input.value === "t";
+
+       input.setAttribute("checked", "checked");
+       div.appendChild( input );
+       fragment = document.createDocumentFragment();
+       fragment.appendChild( div.firstChild );
+
+       // WebKit doesn't clone checked state correctly in fragments
+       support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+       div.innerHTML = "";
+
+       // Figure out if the W3C box model works as expected
+       div.style.width = div.style.paddingLeft = "1px";
+
+       // We use our own, invisible, body
+       body = document.createElement( "body" );
+       bodyStyle = {
+               visibility: "hidden",
+               width: 0,
+               height: 0,
+               border: 0,
+               margin: 0,
+               // Set background to avoid IE crashes when removing (#9028)
+               background: "none"
+       };
+       for ( i in bodyStyle ) {
+               body.style[ i ] = bodyStyle[ i ];
+       }
+       body.appendChild( div );
+       document.documentElement.appendChild( body );
+
+       // Check if a disconnected checkbox will retain its checked
+       // value of true after appended to the DOM (IE6/7)
+       support.appendChecked = input.checked;
+
+       support.boxModel = div.offsetWidth === 2;
+
+       if ( "zoom" in div.style ) {
+               // Check if natively block-level elements act like inline-block
+               // elements when setting their display to 'inline' and giving
+               // them layout
+               // (IE < 8 does this)
+               div.style.display = "inline";
+               div.style.zoom = 1;
+               support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 );
+
+               // Check if elements with layout shrink-wrap their children
+               // (IE 6 does this)
+               div.style.display = "";
+               div.innerHTML = "<div style='width:4px;'></div>";
+               support.shrinkWrapBlocks = ( div.offsetWidth !== 2 );
+       }
+
+       div.innerHTML = "<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";
+       tds = div.getElementsByTagName( "td" );
+
+       // Check if table cells still have offsetWidth/Height when they are set
+       // to display:none and there are still other visible table cells in a
+       // table row; if so, offsetWidth/Height are not reliable for use when
+       // determining if an element has been hidden directly using
+       // display:none (it is still safe to use offsets if a parent element is
+       // hidden; don safety goggles and see bug #4512 for more information).
+       // (only IE 8 fails this test)
+       isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+       tds[ 0 ].style.display = "";
+       tds[ 1 ].style.display = "none";
+
+       // Check if empty table cells still have offsetWidth/Height
+       // (IE < 8 fail this test)
+       support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+       div.innerHTML = "";
+
+       // Check if div with explicit width and no margin-right incorrectly
+       // gets computed margin-right based on width of container. For more
+       // info see bug #3333
+       // Fails in WebKit before Feb 2011 nightlies
+       // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+       if ( document.defaultView && document.defaultView.getComputedStyle ) {
+               marginDiv = document.createElement( "div" );
+               marginDiv.style.width = "0";
+               marginDiv.style.marginRight = "0";
+               div.appendChild( marginDiv );
+               support.reliableMarginRight =
+                       ( parseInt( document.defaultView.getComputedStyle( marginDiv, null ).marginRight, 10 ) || 0 ) === 0;
+       }
+
+       // Remove the body element we added
+       body.innerHTML = "";
+       document.documentElement.removeChild( body );
+
+       // Technique from Juriy Zaytsev
+       // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
+       // We only care about the case where non-standard event systems
+       // are used, namely in IE. Short-circuiting here helps us to
+       // avoid an eval call (in setAttribute) which can cause CSP
+       // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+       if ( div.attachEvent ) {
+               for( i in {
+                       submit: 1,
+                       change: 1,
+                       focusin: 1
+               } ) {
+                       eventName = "on" + i;
+                       isSupported = ( eventName in div );
+                       if ( !isSupported ) {
+                               div.setAttribute( eventName, "return;" );
+                               isSupported = ( typeof div[ eventName ] === "function" );
+                       }
+                       support[ i + "Bubbles" ] = isSupported;
+               }
+       }
+
+       return support;
+})();
+
+// Keep track of boxModel
+jQuery.boxModel = jQuery.support.boxModel;
+
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/,
+       rmultiDash = /([a-z])([A-Z])/g;
+
+jQuery.extend({
+       cache: {},
+
+       // Please use with caution
+       uuid: 0,
+
+       // Unique for each copy of jQuery on the page
+       // Non-digits removed to match rinlinejQuery
+       expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+       // The following elements throw uncatchable exceptions if you
+       // attempt to add expando properties to them.
+       noData: {
+               "embed": true,
+               // Ban all objects except for Flash (which handle expandos)
+               "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+               "applet": true
+       },
+
+       hasData: function( elem ) {
+               elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+
+               return !!elem && !isEmptyDataObject( elem );
+       },
+
+       data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+               if ( !jQuery.acceptData( elem ) ) {
+                       return;
+               }
+
+               var internalKey = jQuery.expando, getByName = typeof name === "string", thisCache,
+
+                       // We have to handle DOM nodes and JS objects differently because IE6-7
+                       // can't GC object references properly across the DOM-JS boundary
+                       isNode = elem.nodeType,
+
+                       // Only DOM nodes need the global jQuery cache; JS object data is
+                       // attached directly to the object so GC can occur automatically
+                       cache = isNode ? jQuery.cache : elem,
+
+                       // Only defining an ID for JS objects if its cache already exists allows
+                       // the code to shortcut on the same path as a DOM node with no cache
+                       id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;
+
+               // Avoid doing any more work than we need to when trying to get data on an
+               // object that has no data at all
+               if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {
+                       return;
+               }
+
+               if ( !id ) {
+                       // Only DOM nodes need a new unique ID for each element since their data
+                       // ends up in the global cache
+                       if ( isNode ) {
+                               elem[ jQuery.expando ] = id = ++jQuery.uuid;
+                       } else {
+                               id = jQuery.expando;
+                       }
+               }
+
+               if ( !cache[ id ] ) {
+                       cache[ id ] = {};
+
+                       // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+                       // metadata on plain JS objects when the object is serialized using
+                       // JSON.stringify
+                       if ( !isNode ) {
+                               cache[ id ].toJSON = jQuery.noop;
+                       }
+               }
+
+               // An object can be passed to jQuery.data instead of a key/value pair; this gets
+               // shallow copied over onto the existing cache
+               if ( typeof name === "object" || typeof name === "function" ) {
+                       if ( pvt ) {
+                               cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);
+                       } else {
+                               cache[ id ] = jQuery.extend(cache[ id ], name);
+                       }
+               }
+
+               thisCache = cache[ id ];
+
+               // Internal jQuery data is stored in a separate object inside the object's data
+               // cache in order to avoid key collisions between internal data and user-defined
+               // data
+               if ( pvt ) {
+                       if ( !thisCache[ internalKey ] ) {
+                               thisCache[ internalKey ] = {};
+                       }
+
+                       thisCache = thisCache[ internalKey ];
+               }
+
+               if ( data !== undefined ) {
+                       thisCache[ name ] = data;
+               }
+
+               // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should
+               // not attempt to inspect the internal events object using jQuery.data, as this
+               // internal data object is undocumented and subject to change.
+               if ( name === "events" && !thisCache[name] ) {
+                       return thisCache[ internalKey ] && thisCache[ internalKey ].events;
+               }
+
+               return getByName ? thisCache[ name ] : thisCache;
+       },
+
+       removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+               if ( !jQuery.acceptData( elem ) ) {
+                       return;
+               }
+
+               var internalKey = jQuery.expando, isNode = elem.nodeType,
+
+                       // See jQuery.data for more information
+                       cache = isNode ? jQuery.cache : elem,
+
+                       // See jQuery.data for more information
+                       id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
+
+               // If there is already no cache entry for this object, there is no
+               // purpose in continuing
+               if ( !cache[ id ] ) {
+                       return;
+               }
+
+               if ( name ) {
+                       var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];
+
+                       if ( thisCache ) {
+                               delete thisCache[ name ];
+
+                               // If there is no data left in the cache, we want to continue
+                               // and let the cache object itself get destroyed
+                               if ( !isEmptyDataObject(thisCache) ) {
+                                       return;
+                               }
+                       }
+               }
+
+               // See jQuery.data for more information
+               if ( pvt ) {
+                       delete cache[ id ][ internalKey ];
+
+                       // Don't destroy the parent cache unless the internal data object
+                       // had been the only thing left in it
+                       if ( !isEmptyDataObject(cache[ id ]) ) {
+                               return;
+                       }
+               }
+
+               var internalCache = cache[ id ][ internalKey ];
+
+               // Browsers that fail expando deletion also refuse to delete expandos on
+               // the window, but it will allow it on all other JS objects; other browsers
+               // don't care
+               if ( jQuery.support.deleteExpando || cache != window ) {
+                       delete cache[ id ];
+               } else {
+                       cache[ id ] = null;
+               }
+
+               // We destroyed the entire user cache at once because it's faster than
+               // iterating through each key, but we need to continue to persist internal
+               // data if it existed
+               if ( internalCache ) {
+                       cache[ id ] = {};
+                       // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery
+                       // metadata on plain JS objects when the object is serialized using
+                       // JSON.stringify
+                       if ( !isNode ) {
+                               cache[ id ].toJSON = jQuery.noop;
+                       }
+
+                       cache[ id ][ internalKey ] = internalCache;
+
+               // Otherwise, we need to eliminate the expando on the node to avoid
+               // false lookups in the cache for entries that no longer exist
+               } else if ( isNode ) {
+                       // IE does not allow us to delete expando properties from nodes,
+                       // nor does it have a removeAttribute function on Document nodes;
+                       // we must handle all of these cases
+                       if ( jQuery.support.deleteExpando ) {
+                               delete elem[ jQuery.expando ];
+                       } else if ( elem.removeAttribute ) {
+                               elem.removeAttribute( jQuery.expando );
+                       } else {
+                               elem[ jQuery.expando ] = null;
+                       }
+               }
+       },
+
+       // For internal use only.
+       _data: function( elem, name, data ) {
+               return jQuery.data( elem, name, data, true );
+       },
+
+       // A method for determining if a DOM node can handle the data expando
+       acceptData: function( elem ) {
+               if ( elem.nodeName ) {
+                       var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+                       if ( match ) {
+                               return !(match === true || elem.getAttribute("classid") !== match);
+                       }
+               }
+
+               return true;
+       }
+});
+
+jQuery.fn.extend({
+       data: function( key, value ) {
+               var data = null;
+
+               if ( typeof key === "undefined" ) {
+                       if ( this.length ) {
+                               data = jQuery.data( this[0] );
+
+                               if ( this[0].nodeType === 1 ) {
+                           var attr = this[0].attributes, name;
+                                       for ( var i = 0, l = attr.length; i < l; i++ ) {
+                                               name = attr[i].name;
+
+                                               if ( name.indexOf( "data-" ) === 0 ) {
+                                                       name = jQuery.camelCase( name.substring(5) );
+
+                                                       dataAttr( this[0], name, data[ name ] );
+                                               }
+                                       }
+                               }
+                       }
+
+                       return data;
+
+               } else if ( typeof key === "object" ) {
+                       return this.each(function() {
+                               jQuery.data( this, key );
+                       });
+               }
+
+               var parts = key.split(".");
+               parts[1] = parts[1] ? "." + parts[1] : "";
+
+               if ( value === undefined ) {
+                       data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+                       // Try to fetch any internally stored data first
+                       if ( data === undefined && this.length ) {
+                               data = jQuery.data( this[0], key );
+                               data = dataAttr( this[0], key, data );
+                       }
+
+                       return data === undefined && parts[1] ?
+                               this.data( parts[0] ) :
+                               data;
+
+               } else {
+                       return this.each(function() {
+                               var $this = jQuery( this ),
+                                       args = [ parts[0], value ];
+
+                               $this.triggerHandler( "setData" + parts[1] + "!", args );
+                               jQuery.data( this, key, value );
+                               $this.triggerHandler( "changeData" + parts[1] + "!", args );
+                       });
+               }
+       },
+
+       removeData: function( key ) {
+               return this.each(function() {
+                       jQuery.removeData( this, key );
+               });
+       }
+});
+
+function dataAttr( elem, key, data ) {
+       // If nothing was found internally, try to fetch any
+       // data from the HTML5 data-* attribute
+       if ( data === undefined && elem.nodeType === 1 ) {
+               name = "data-" + key.replace( rmultiDash, "$1-$2" ).toLowerCase();
+
+               data = elem.getAttribute( name );
+
+               if ( typeof data === "string" ) {
+                       try {
+                               data = data === "true" ? true :
+                               data === "false" ? false :
+                               data === "null" ? null :
+                               !jQuery.isNaN( data ) ? parseFloat( data ) :
+                                       rbrace.test( data ) ? jQuery.parseJSON( data ) :
+                                       data;
+                       } catch( e ) {}
+
+                       // Make sure we set the data so it isn't changed later
+                       jQuery.data( elem, key, data );
+
+               } else {
+                       data = undefined;
+               }
+       }
+
+       return data;
+}
+
+// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON
+// property to be considered empty objects; this property always exists in
+// order to make sure JSON.stringify does not expose internal metadata
+function isEmptyDataObject( obj ) {
+       for ( var name in obj ) {
+               if ( name !== "toJSON" ) {
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+
+
+
+function handleQueueMarkDefer( elem, type, src ) {
+       var deferDataKey = type + "defer",
+               queueDataKey = type + "queue",
+               markDataKey = type + "mark",
+               defer = jQuery.data( elem, deferDataKey, undefined, true );
+       if ( defer &&
+               ( src === "queue" || !jQuery.data( elem, queueDataKey, undefined, true ) ) &&
+               ( src === "mark" || !jQuery.data( elem, markDataKey, undefined, true ) ) ) {
+               // Give room for hard-coded callbacks to fire first
+               // and eventually mark/queue something else on the element
+               setTimeout( function() {
+                       if ( !jQuery.data( elem, queueDataKey, undefined, true ) &&
+                               !jQuery.data( elem, markDataKey, undefined, true ) ) {
+                               jQuery.removeData( elem, deferDataKey, true );
+                               defer.resolve();
+                       }
+               }, 0 );
+       }
+}
+
+jQuery.extend({
+
+       _mark: function( elem, type ) {
+               if ( elem ) {
+                       type = (type || "fx") + "mark";
+                       jQuery.data( elem, type, (jQuery.data(elem,type,undefined,true) || 0) + 1, true );
+               }
+       },
+
+       _unmark: function( force, elem, type ) {
+               if ( force !== true ) {
+                       type = elem;
+                       elem = force;
+                       force = false;
+               }
+               if ( elem ) {
+                       type = type || "fx";
+                       var key = type + "mark",
+                               count = force ? 0 : ( (jQuery.data( elem, key, undefined, true) || 1 ) - 1 );
+                       if ( count ) {
+                               jQuery.data( elem, key, count, true );
+                       } else {
+                               jQuery.removeData( elem, key, true );
+                               handleQueueMarkDefer( elem, type, "mark" );
+                       }
+               }
+       },
+
+       queue: function( elem, type, data ) {
+               if ( elem ) {
+                       type = (type || "fx") + "queue";
+                       var q = jQuery.data( elem, type, undefined, true );
+                       // Speed up dequeue by getting out quickly if this is just a lookup
+                       if ( data ) {
+                               if ( !q || jQuery.isArray(data) ) {
+                                       q = jQuery.data( elem, type, jQuery.makeArray(data), true );
+                               } else {
+                                       q.push( data );
+                               }
+                       }
+                       return q || [];
+               }
+       },
+
+       dequeue: function( elem, type ) {
+               type = type || "fx";
+
+               var queue = jQuery.queue( elem, type ),
+                       fn = queue.shift(),
+                       defer;
+
+               // If the fx queue is dequeued, always remove the progress sentinel
+               if ( fn === "inprogress" ) {
+                       fn = queue.shift();
+               }
+
+               if ( fn ) {
+                       // Add a progress sentinel to prevent the fx queue from being
+                       // automatically dequeued
+                       if ( type === "fx" ) {
+                               queue.unshift("inprogress");
+                       }
+
+                       fn.call(elem, function() {
+                               jQuery.dequeue(elem, type);
+                       });
+               }
+
+               if ( !queue.length ) {
+                       jQuery.removeData( elem, type + "queue", true );
+                       handleQueueMarkDefer( elem, type, "queue" );
+               }
+       }
+});
+
+jQuery.fn.extend({
+       queue: function( type, data ) {
+               if ( typeof type !== "string" ) {
+                       data = type;
+                       type = "fx";
+               }
+
+               if ( data === undefined ) {
+                       return jQuery.queue( this[0], type );
+               }
+               return this.each(function() {
+                       var queue = jQuery.queue( this, type, data );
+
+                       if ( type === "fx" && queue[0] !== "inprogress" ) {
+                               jQuery.dequeue( this, type );
+                       }
+               });
+       },
+       dequeue: function( type ) {
+               return this.each(function() {
+                       jQuery.dequeue( this, type );
+               });
+       },
+       // Based off of the plugin by Clint Helfers, with permission.
+       // http://blindsignals.com/index.php/2009/07/jquery-delay/
+       delay: function( time, type ) {
+               time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
+               type = type || "fx";
+
+               return this.queue( type, function() {
+                       var elem = this;
+                       setTimeout(function() {
+                               jQuery.dequeue( elem, type );
+                       }, time );
+               });
+       },
+       clearQueue: function( type ) {
+               return this.queue( type || "fx", [] );
+       },
+       // Get a promise resolved when queues of a certain type
+       // are emptied (fx is the type by default)
+       promise: function( type, object ) {
+               if ( typeof type !== "string" ) {
+                       object = type;
+                       type = undefined;
+               }
+               type = type || "fx";
+               var defer = jQuery.Deferred(),
+                       elements = this,
+                       i = elements.length,
+                       count = 1,
+                       deferDataKey = type + "defer",
+                       queueDataKey = type + "queue",
+                       markDataKey = type + "mark";
+               function resolve() {
+                       if ( !( --count ) ) {
+                               defer.resolveWith( elements, [ elements ] );
+                       }
+               }
+               while( i-- ) {
+                       if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
+                                       ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
+                                               jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
+                                       jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) {
+                               count++;
+                               tmp.done( resolve );
+                       }
+               }
+               resolve();
+               return defer.promise();
+       }
+});
+
+
+
+
+var rclass = /[\n\t\r]/g,
+       rspace = /\s+/,
+       rreturn = /\r/g,
+       rtype = /^(?:button|input)$/i,
+       rfocusable = /^(?:button|input|object|select|textarea)$/i,
+       rclickable = /^a(?:rea)?$/i,
+       rspecial = /^(?:data-|aria-)/,
+       rinvalidChar = /\:/,
+       formHook;
+
+jQuery.fn.extend({
+       attr: function( name, value ) {
+               return jQuery.access( this, name, value, true, jQuery.attr );
+       },
+
+       removeAttr: function( name ) {
+               return this.each(function() {
+                       jQuery.removeAttr( this, name );
+               });
+       },
+       
+       prop: function( name, value ) {
+               return jQuery.access( this, name, value, true, jQuery.prop );
+       },
+       
+       removeProp: function( name ) {
+               return this.each(function() {
+                       // try/catch handles cases where IE balks (such as removing a property on window)
+                       try {
+                               this[ name ] = undefined;
+                               delete this[ name ];
+                       } catch( e ) {}
+               });
+       },
+
+       addClass: function( value ) {
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function(i) {
+                               var self = jQuery(this);
+                               self.addClass( value.call(this, i, self.attr("class") || "") );
+                       });
+               }
+
+               if ( value && typeof value === "string" ) {
+                       var classNames = (value || "").split( rspace );
+
+                       for ( var i = 0, l = this.length; i < l; i++ ) {
+                               var elem = this[i];
+
+                               if ( elem.nodeType === 1 ) {
+                                       if ( !elem.className ) {
+                                               elem.className = value;
+
+                                       } else {
+                                               var className = " " + elem.className + " ",
+                                                       setClass = elem.className;
+
+                                               for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+                                                       if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
+                                                               setClass += " " + classNames[c];
+                                                       }
+                                               }
+                                               elem.className = jQuery.trim( setClass );
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       removeClass: function( value ) {
+               if ( jQuery.isFunction(value) ) {
+                       return this.each(function(i) {
+                               var self = jQuery(this);
+                               self.removeClass( value.call(this, i, self.attr("class")) );
+                       });
+               }
+
+               if ( (value && typeof value === "string") || value === undefined ) {
+                       var classNames = (value || "").split( rspace );
+
+                       for ( var i = 0, l = this.length; i < l; i++ ) {
+                               var elem = this[i];
+
+                               if ( elem.nodeType === 1 && elem.className ) {
+                                       if ( value ) {
+                                               var className = (" " + elem.className + " ").replace(rclass, " ");
+                                               for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
+                                                       className = className.replace(" " + classNames[c] + " ", " ");
+                                               }
+                                               elem.className = jQuery.trim( className );
+
+                                       } else {
+                                               elem.className = "";
+                                       }
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       toggleClass: function( value, stateVal ) {
+               var type = typeof value,
+                       isBool = typeof stateVal === "boolean";
+
+               if ( jQuery.isFunction( value ) ) {
+                       return this.each(function(i) {
+                               var self = jQuery(this);
+                               self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
+                       });
+               }
+
+               return this.each(function() {
+                       if ( type === "string" ) {
+                               // toggle individual class names
+                               var className,
+                                       i = 0,
+                                       self = jQuery( this ),
+                                       state = stateVal,
+                                       classNames = value.split( rspace );
+
+                               while ( (className = classNames[ i++ ]) ) {
+                                       // check each className given, space seperated list
+                                       state = isBool ? state : !self.hasClass( className );
+                                       self[ state ? "addClass" : "removeClass" ]( className );
+                               }
+
+                       } else if ( type === "undefined" || type === "boolean" ) {
+                               if ( this.className ) {
+                                       // store className if set
+                                       jQuery._data( this, "__className__", this.className );
+                               }
+
+                               // toggle whole className
+                               this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+                       }
+               });
+       },
+
+       hasClass: function( selector ) {
+               var className = " " + selector + " ";
+               for ( var i = 0, l = this.length; i < l; i++ ) {
+                       if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+                               return true;
+                       }
+               }
+
+               return false;
+       },
+
+       val: function( value ) {
+               var hooks, ret,
+                       elem = this[0];
+               
+               if ( !arguments.length ) {
+                       if ( elem ) {
+                               hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ];
+
+                               if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+                                       return ret;
+                               }
+
+                               return (elem.value || "").replace(rreturn, "");
+                       }
+
+                       return undefined;
+               }
+
+               var isFunction = jQuery.isFunction( value );
+
+               return this.each(function( i ) {
+                       var self = jQuery(this), val;
+
+                       if ( this.nodeType !== 1 ) {
+                               return;
+                       }
+
+                       if ( isFunction ) {
+                               val = value.call( this, i, self.val() );
+                       } else {
+                               val = value;
+                       }
+
+                       // Treat null/undefined as ""; convert numbers to string
+                       if ( val == null ) {
+                               val = "";
+                       } else if ( typeof val === "number" ) {
+                               val += "";
+                       } else if ( jQuery.isArray( val ) ) {
+                               val = jQuery.map(val, function ( value ) {
+                                       return value == null ? "" : value + "";
+                               });
+                       }
+
+                       hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ];
+
+                       // If set returns undefined, fall back to normal setting
+                       if ( !hooks || ("set" in hooks && hooks.set( this, val, "value" ) === undefined) ) {
+                               this.value = val;
+                       }
+               });
+       }
+});
+
+jQuery.extend({
+       valHooks: {
+               option: {
+                       get: function( elem ) {
+                               // attributes.value is undefined in Blackberry 4.7 but
+                               // uses .value. See #6932
+                               var val = elem.attributes.value;
+                               return !val || val.specified ? elem.value : elem.text;
+                       }
+               },
+               select: {
+                       get: function( elem ) {
+                               var index = elem.selectedIndex,
+                                       values = [],
+                                       options = elem.options,
+                                       one = elem.type === "select-one";
+
+                               // Nothing was selected
+                               if ( index < 0 ) {
+                                       return null;
+                               }
+
+                               // Loop through all the selected options
+                               for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+                                       var option = options[ i ];
+
+                                       // Don't return options that are disabled or in a disabled optgroup
+                                       if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+                                                       (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+                                               // Get the specific value for the option
+                                               value = jQuery( option ).val();
+
+                                               // We don't need an array for one selects
+                                               if ( one ) {
+                                                       return value;
+                                               }
+
+                                               // Multi-Selects return an array
+                                               values.push( value );
+                                       }
+                               }
+
+                               // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+                               if ( one && !values.length && options.length ) {
+                                       return jQuery( options[ index ] ).val();
+                               }
+
+                               return values;
+                       },
+
+                       set: function( elem, value ) {
+                               var values = jQuery.makeArray( value );
+
+                               jQuery(elem).find("option").each(function() {
+                                       this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+                               });
+
+                               if ( !values.length ) {
+                                       elem.selectedIndex = -1;
+                               }
+                               return values;
+                       }
+               }
+       },
+
+       attrFn: {
+               val: true,
+               css: true,
+               html: true,
+               text: true,
+               data: true,
+               width: true,
+               height: true,
+               offset: true
+       },
+       
+       attrFix: {
+               // Always normalize to ensure hook usage
+               tabindex: "tabIndex",
+               readonly: "readOnly"
+       },
+       
+       attr: function( elem, name, value, pass ) {
+               var nType = elem.nodeType;
+               
+               // don't get/set attributes on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return undefined;
+               }
+
+               if ( pass && name in jQuery.attrFn ) {
+                       return jQuery( elem )[ name ]( value );
+               }
+               
+               var ret, hooks,
+                       notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+               
+               // Normalize the name if needed
+               name = notxml && jQuery.attrFix[ name ] || name;
+
+               // Get the appropriate hook, or the formHook
+               // if getSetAttribute is not supported and we have form objects in IE6/7
+               hooks = jQuery.attrHooks[ name ] ||
+                       ( formHook && (jQuery.nodeName( elem, "form" ) || rinvalidChar.test( name )) ?
+                               formHook :
+                               undefined );
+
+               if ( value !== undefined ) {
+
+                       if ( value === null || (value === false && !rspecial.test( name )) ) {
+                               jQuery.removeAttr( elem, name );
+                               return undefined;
+
+                       } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+                               return ret;
+
+                       } else {
+
+                               // Set boolean attributes to the same name
+                               if ( value === true && !rspecial.test( name ) ) {
+                                       value = name;
+                               }
+
+                               elem.setAttribute( name, "" + value );
+                               return value;
+                       }
+
+               } else {
+
+                       if ( hooks && "get" in hooks && notxml ) {
+                               return hooks.get( elem, name );
+
+                       } else {
+
+                               ret = elem.getAttribute( name );
+
+                               // Non-existent attributes return null, we normalize to undefined
+                               return ret === null ?
+                                       undefined :
+                                       ret;
+                       }
+               }
+       },
+       
+       removeAttr: function( elem, name ) {
+               if ( elem.nodeType === 1 ) {
+                       name = jQuery.attrFix[ name ] || name;
+               
+                       if ( jQuery.support.getSetAttribute ) {
+                               // Use removeAttribute in browsers that support it
+                               elem.removeAttribute( name );
+                       } else {
+                               jQuery.attr( elem, name, "" );
+                               elem.removeAttributeNode( elem.getAttributeNode( name ) );
+                       }
+               }
+       },
+
+       attrHooks: {
+               type: {
+                       set: function( elem, value ) {
+                               // We can't allow the type property to be changed (since it causes problems in IE)
+                               if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+                                       jQuery.error( "type property can't be changed" );
+                               } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+                                       // Setting the type on a radio button after the value resets the value in IE6-9
+                                       // Reset value to it's default in case type is set after value
+                                       // This is for element creation
+                                       var val = elem.getAttribute("value");
+                                       elem.setAttribute( "type", value );
+                                       if ( val ) {
+                                               elem.value = val;
+                                       }
+                                       return value;
+                               }
+                       }
+               },
+               tabIndex: {
+                       get: function( elem ) {
+                               // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+                               // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+                               var attributeNode = elem.getAttributeNode("tabIndex");
+
+                               return attributeNode && attributeNode.specified ?
+                                       parseInt( attributeNode.value, 10 ) :
+                                       rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+                                               0 :
+                                               undefined;
+                       }
+               }
+       },
+       
+       propFix: {},
+       
+       prop: function( elem, name, value ) {
+               var nType = elem.nodeType;
+               
+               // don't get/set properties on text, comment and attribute nodes
+               if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+                       return undefined;
+               }
+               
+               var ret, hooks,
+                       notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+               
+               // Try to normalize/fix the name
+               name = notxml && jQuery.propFix[ name ] || name;
+               
+               hooks = jQuery.propHooks[ name ];
+               
+               if ( value !== undefined ) {
+                       if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+                               return ret;
+                       
+                       } else {
+                               return (elem[ name ] = value);
+                       }
+               
+               } else {
+                       if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) {
+                               return ret;
+                               
+                       } else {
+                               return elem[ name ];
+                       }
+               }
+       },
+       
+       propHooks: {}
+});
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !jQuery.support.getSetAttribute ) {
+       jQuery.attrFix = jQuery.extend( jQuery.attrFix, {
+               "for": "htmlFor",
+               "class": "className",
+               maxlength: "maxLength",
+               cellspacing: "cellSpacing",
+               cellpadding: "cellPadding",
+               rowspan: "rowSpan",
+               colspan: "colSpan",
+               usemap: "useMap",
+               frameborder: "frameBorder"
+       });
+       
+       // Use this for any attribute on a form in IE6/7
+       formHook = jQuery.attrHooks.name = jQuery.attrHooks.value = jQuery.valHooks.button = {
+               get: function( elem, name ) {
+                       var ret;
+                       if ( name === "value" && !jQuery.nodeName( elem, "button" ) ) {
+                               return elem.getAttribute( name );
+                       }
+                       ret = elem.getAttributeNode( name );
+                       // Return undefined if not specified instead of empty string
+                       return ret && ret.specified ?
+                               ret.nodeValue :
+                               undefined;
+               },
+               set: function( elem, value, name ) {
+                       // Check form objects in IE (multiple bugs related)
+                       // Only use nodeValue if the attribute node exists on the form
+                       var ret = elem.getAttributeNode( name );
+                       if ( ret ) {
+                               ret.nodeValue = value;
+                               return value;
+                       }
+               }
+       };
+
+       // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+       // This is for removals
+       jQuery.each([ "width", "height" ], function( i, name ) {
+               jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+                       set: function( elem, value ) {
+                               if ( value === "" ) {
+                                       elem.setAttribute( name, "auto" );
+                                       return value;
+                               }
+                       }
+               });
+       });
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+       jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+               jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+                       get: function( elem ) {
+                               var ret = elem.getAttribute( name, 2 );
+                               return ret === null ? undefined : ret;
+                       }
+               });
+       });
+}
+
+if ( !jQuery.support.style ) {
+       jQuery.attrHooks.style = {
+               get: function( elem ) {
+                       // Return undefined in the case of empty string
+                       // Normalize to lowercase since IE uppercases css property names
+                       return elem.style.cssText.toLowerCase() || undefined;
+               },
+               set: function( elem, value ) {
+                       return (elem.style.cssText = "" + value);
+               }
+       };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+       jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+               get: function( elem ) {
+                       var parent = elem.parentNode;
+
+                       if ( parent ) {
+                               parent.selectedIndex;
+
+                               // Make sure that it also works with optgroups, see #5701
+                               if ( parent.parentNode ) {
+                                       parent.parentNode.selectedIndex;
+                               }
+                       }
+               }
+       });
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+       jQuery.each([ "radio", "checkbox" ], function() {
+               jQuery.valHooks[ this ] = {
+                       get: function( elem ) {
+                               // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+                               return elem.getAttribute("value") === null ? "on" : elem.value;
+                       }
+               };
+       });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+       jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+               set: function( elem, value ) {
+                       if ( jQuery.isArray( value ) ) {
+                               return (elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0);
+                       }
+               }
+       });
+});
+
+
+
+
+var hasOwn = Object.prototype.hasOwnProperty,
+       rnamespaces = /\.(.*)$/,
+       rformElems = /^(?:textarea|input|select)$/i,
+       rperiod = /\./g,
+       rspaces = / /g,
+       rescape = /[^\w\s.|`]/g,
+       fcleanup = function( nm ) {
+               return nm.replace(rescape, "\\$&");
+       };
+
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code originated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+       // Bind an event to an element
+       // Original by Dean Edwards
+       add: function( elem, types, handler, data ) {
+               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                       return;
+               }
+
+               if ( handler === false ) {
+                       handler = returnFalse;
+               } else if ( !handler ) {
+                       // Fixes bug #7229. Fix recommended by jdalton
+                       return;
+               }
+
+               var handleObjIn, handleObj;
+
+               if ( handler.handler ) {
+                       handleObjIn = handler;
+                       handler = handleObjIn.handler;
+               }
+
+               // Make sure that the function being executed has a unique ID
+               if ( !handler.guid ) {
+                       handler.guid = jQuery.guid++;
+               }
+
+               // Init the element's event structure
+               var elemData = jQuery._data( elem );
+
+               // If no elemData is found then we must be trying to bind to one of the
+               // banned noData elements
+               if ( !elemData ) {
+                       return;
+               }
+
+               var events = elemData.events,
+                       eventHandle = elemData.handle;
+
+               if ( !events ) {
+                       elemData.events = events = {};
+               }
+
+               if ( !eventHandle ) {
+                       elemData.handle = eventHandle = function( e ) {
+                               // Discard the second event of a jQuery.event.trigger() and
+                               // when an event is called after a page has unloaded
+                               return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+                                       jQuery.event.handle.apply( eventHandle.elem, arguments ) :
+                                       undefined;
+                       };
+               }
+
+               // Add elem as a property of the handle function
+               // This is to prevent a memory leak with non-native events in IE.
+               eventHandle.elem = elem;
+
+               // Handle multiple events separated by a space
+               // jQuery(...).bind("mouseover mouseout", fn);
+               types = types.split(" ");
+
+               var type, i = 0, namespaces;
+
+               while ( (type = types[ i++ ]) ) {
+                       handleObj = handleObjIn ?
+                               jQuery.extend({}, handleObjIn) :
+                               { handler: handler, data: data };
+
+                       // Namespaced event handlers
+                       if ( type.indexOf(".") > -1 ) {
+                               namespaces = type.split(".");
+                               type = namespaces.shift();
+                               handleObj.namespace = namespaces.slice(0).sort().join(".");
+
+                       } else {
+                               namespaces = [];
+                               handleObj.namespace = "";
+                       }
+
+                       handleObj.type = type;
+                       if ( !handleObj.guid ) {
+                               handleObj.guid = handler.guid;
+                       }
+
+                       // Get the current list of functions bound to this event
+                       var handlers = events[ type ],
+                               special = jQuery.event.special[ type ] || {};
+
+                       // Init the event handler queue
+                       if ( !handlers ) {
+                               handlers = events[ type ] = [];
+
+                               // Check for a special event handler
+                               // Only use addEventListener/attachEvent if the special
+                               // events handler returns false
+                               if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+                                       // Bind the global event handler to the element
+                                       if ( elem.addEventListener ) {
+                                               elem.addEventListener( type, eventHandle, false );
+
+                                       } else if ( elem.attachEvent ) {
+                                               elem.attachEvent( "on" + type, eventHandle );
+                                       }
+                               }
+                       }
+
+                       if ( special.add ) {
+                               special.add.call( elem, handleObj );
+
+                               if ( !handleObj.handler.guid ) {
+                                       handleObj.handler.guid = handler.guid;
+                               }
+                       }
+
+                       // Add the function to the element's handler list
+                       handlers.push( handleObj );
+
+                       // Keep track of which events have been used, for event optimization
+                       jQuery.event.global[ type ] = true;
+               }
+
+               // Nullify elem to prevent memory leaks in IE
+               elem = null;
+       },
+
+       global: {},
+
+       // Detach an event or set of events from an element
+       remove: function( elem, types, handler, pos ) {
+               // don't do events on text and comment nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                       return;
+               }
+
+               if ( handler === false ) {
+                       handler = returnFalse;
+               }
+
+               var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,
+                       elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+                       events = elemData && elemData.events;
+
+               if ( !elemData || !events ) {
+                       return;
+               }
+
+               // types is actually an event object here
+               if ( types && types.type ) {
+                       handler = types.handler;
+                       types = types.type;
+               }
+
+               // Unbind all events for the element
+               if ( !types || typeof types === "string" && types.charAt(0) === "." ) {
+                       types = types || "";
+
+                       for ( type in events ) {
+                               jQuery.event.remove( elem, type + types );
+                       }
+
+                       return;
+               }
+
+               // Handle multiple events separated by a space
+               // jQuery(...).unbind("mouseover mouseout", fn);
+               types = types.split(" ");
+
+               while ( (type = types[ i++ ]) ) {
+                       origType = type;
+                       handleObj = null;
+                       all = type.indexOf(".") < 0;
+                       namespaces = [];
+
+                       if ( !all ) {
+                               // Namespaced event handlers
+                               namespaces = type.split(".");
+                               type = namespaces.shift();
+
+                               namespace = new RegExp("(^|\\.)" +
+                                       jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)");
+                       }
+
+                       eventType = events[ type ];
+
+                       if ( !eventType ) {
+                               continue;
+                       }
+
+                       if ( !handler ) {
+                               for ( j = 0; j < eventType.length; j++ ) {
+                                       handleObj = eventType[ j ];
+
+                                       if ( all || namespace.test( handleObj.namespace ) ) {
+                                               jQuery.event.remove( elem, origType, handleObj.handler, j );
+                                               eventType.splice( j--, 1 );
+                                       }
+                               }
+
+                               continue;
+                       }
+
+                       special = jQuery.event.special[ type ] || {};
+
+                       for ( j = pos || 0; j < eventType.length; j++ ) {
+                               handleObj = eventType[ j ];
+
+                               if ( handler.guid === handleObj.guid ) {
+                                       // remove the given handler for the given type
+                                       if ( all || namespace.test( handleObj.namespace ) ) {
+                                               if ( pos == null ) {
+                                                       eventType.splice( j--, 1 );
+                                               }
+
+                                               if ( special.remove ) {
+                                                       special.remove.call( elem, handleObj );
+                                               }
+                                       }
+
+                                       if ( pos != null ) {
+                                               break;
+                                       }
+                               }
+                       }
+
+                       // remove generic event handler if no more handlers exist
+                       if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {
+                               if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+                                       jQuery.removeEvent( elem, type, elemData.handle );
+                               }
+
+                               ret = null;
+                               delete events[ type ];
+                       }
+               }
+
+               // Remove the expando if it's no longer used
+               if ( jQuery.isEmptyObject( events ) ) {
+                       var handle = elemData.handle;
+                       if ( handle ) {
+                               handle.elem = null;
+                       }
+
+                       delete elemData.events;
+                       delete elemData.handle;
+
+                       if ( jQuery.isEmptyObject( elemData ) ) {
+                               jQuery.removeData( elem, undefined, true );
+                       }
+               }
+       },
+       
+       // Events that are safe to short-circuit if no handlers are attached.
+       // Native DOM events should not be added, they may have inline handlers.
+       customEvent: {
+               "getData": true,
+               "setData": true,
+               "changeData": true
+       },
+
+       trigger: function( event, data, elem, onlyHandlers ) {
+               // Event object or event type
+               var type = event.type || event,
+                       namespaces = [],
+                       exclusive;
+
+               if ( type.indexOf("!") >= 0 ) {
+                       // Exclusive events trigger only for the exact event (no namespaces)
+                       type = type.slice(0, -1);
+                       exclusive = true;
+               }
+
+               if ( type.indexOf(".") >= 0 ) {
+                       // Namespaced trigger; create a regexp to match event type in handle()
+                       namespaces = type.split(".");
+                       type = namespaces.shift();
+                       namespaces.sort();
+               }
+
+               if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+                       // No jQuery handlers for this event type, and it can't have inline handlers
+                       return;
+               }
+
+               // Caller can pass in an Event, Object, or just an event type string
+               event = typeof event === "object" ?
+                       // jQuery.Event object
+                       event[ jQuery.expando ] ? event :
+                       // Object literal
+                       new jQuery.Event( type, event ) :
+                       // Just the event type (string)
+                       new jQuery.Event( type );
+
+               event.type = type;
+               event.exclusive = exclusive;
+               event.namespace = namespaces.join(".");
+               event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)");
+               
+               // triggerHandler() and global events don't bubble or run the default action
+               if ( onlyHandlers || !elem ) {
+                       event.preventDefault();
+                       event.stopPropagation();
+               }
+
+               // Handle a global trigger
+               if ( !elem ) {
+                       // TODO: Stop taunting the data cache; remove global events and always attach to document
+                       jQuery.each( jQuery.cache, function() {
+                               // internalKey variable is just used to make it easier to find
+                               // and potentially change this stuff later; currently it just
+                               // points to jQuery.expando
+                               var internalKey = jQuery.expando,
+                                       internalCache = this[ internalKey ];
+                               if ( internalCache && internalCache.events && internalCache.events[ type ] ) {
+                                       jQuery.event.trigger( event, data, internalCache.handle.elem );
+                               }
+                       });
+                       return;
+               }
+
+               // Don't do events on text and comment nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+                       return;
+               }
+
+               // Clean up the event in case it is being reused
+               event.result = undefined;
+               event.target = elem;
+
+               // Clone any incoming data and prepend the event, creating the handler arg list
+               data = data ? jQuery.makeArray( data ) : [];
+               data.unshift( event );
+
+               var cur = elem,
+                       // IE doesn't like method names with a colon (#3533, #8272)
+                       ontype = type.indexOf(":") < 0 ? "on" + type : "";
+
+               // Fire event on the current element, then bubble up the DOM tree
+               do {
+                       var handle = jQuery._data( cur, "handle" );
+
+                       event.currentTarget = cur;
+                       if ( handle ) {
+                               handle.apply( cur, data );
+                       }
+
+                       // Trigger an inline bound script
+                       if ( ontype && jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) {
+                               event.result = false;
+                               event.preventDefault();
+                       }
+
+                       // Bubble up to document, then to window
+                       cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window;
+               } while ( cur && !event.isPropagationStopped() );
+
+               // If nobody prevented the default action, do it now
+               if ( !event.isDefaultPrevented() ) {
+                       var old,
+                               special = jQuery.event.special[ type ] || {};
+
+                       if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &&
+                               !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+                               // Call a native DOM method on the target with the same name name as the event.
+                               // Can't use an .isFunction)() check here because IE6/7 fails that test.
+                               // IE<9 dies on focus to hidden element (#1486), may want to revisit a try/catch.
+                               try {
+                                       if ( ontype && elem[ type ] ) {
+                                               // Don't re-trigger an onFOO event when we call its FOO() method
+                                               old = elem[ ontype ];
+
+                                               if ( old ) {
+                                                       elem[ ontype ] = null;
+                                               }
+
+                                               jQuery.event.triggered = type;
+                                               elem[ type ]();
+                                       }
+                               } catch ( ieError ) {}
+
+                               if ( old ) {
+                                       elem[ ontype ] = old;
+                               }
+
+                               jQuery.event.triggered = undefined;
+                       }
+               }
+               
+               return event.result;
+       },
+
+       handle: function( event ) {
+               event = jQuery.event.fix( event || window.event );
+               // Snapshot the handlers list since a called handler may add/remove events.
+               var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0),
+                       run_all = !event.exclusive && !event.namespace,
+                       args = Array.prototype.slice.call( arguments, 0 );
+
+               // Use the fix-ed Event rather than the (read-only) native event
+               args[0] = event;
+               event.currentTarget = this;
+
+               for ( var j = 0, l = handlers.length; j < l; j++ ) {
+                       var handleObj = handlers[ j ];
+
+                       // Triggered event must 1) be non-exclusive and have no namespace, or
+                       // 2) have namespace(s) a subset or equal to those in the bound event.
+                       if ( run_all || event.namespace_re.test( handleObj.namespace ) ) {
+                               // Pass in a reference to the handler function itself
+                               // So that we can later remove it
+                               event.handler = handleObj.handler;
+                               event.data = handleObj.data;
+                               event.handleObj = handleObj;
+
+                               var ret = handleObj.handler.apply( this, args );
+
+                               if ( ret !== undefined ) {
+                                       event.result = ret;
+                                       if ( ret === false ) {
+                                               event.preventDefault();
+                                               event.stopPropagation();
+                                       }
+                               }
+
+                               if ( event.isImmediatePropagationStopped() ) {
+                                       break;
+                               }
+                       }
+               }
+               return event.result;
+       },
+
+       props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+
+       fix: function( event ) {
+               if ( event[ jQuery.expando ] ) {
+                       return event;
+               }
+
+               // store a copy of the original event object
+               // and "clone" to set read-only properties
+               var originalEvent = event;
+               event = jQuery.Event( originalEvent );
+
+               for ( var i = this.props.length, prop; i; ) {
+                       prop = this.props[ --i ];
+                       event[ prop ] = originalEvent[ prop ];
+               }
+
+               // Fix target property, if necessary
+               if ( !event.target ) {
+                       // Fixes #1925 where srcElement might not be defined either
+                       event.target = event.srcElement || document;
+               }
+
+               // check if target is a textnode (safari)
+               if ( event.target.nodeType === 3 ) {
+                       event.target = event.target.parentNode;
+               }
+
+               // Add relatedTarget, if necessary
+               if ( !event.relatedTarget && event.fromElement ) {
+                       event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
+               }
+
+               // Calculate pageX/Y if missing and clientX/Y available
+               if ( event.pageX == null && event.clientX != null ) {
+                       var eventDocument = event.target.ownerDocument || document,
+                               doc = eventDocument.documentElement,
+                               body = eventDocument.body;
+
+                       event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
+                       event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);
+               }
+
+               // Add which for key events
+               if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {
+                       event.which = event.charCode != null ? event.charCode : event.keyCode;
+               }
+
+               // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+               if ( !event.metaKey && event.ctrlKey ) {
+                       event.metaKey = event.ctrlKey;
+               }
+
+               // Add which for click: 1 === left; 2 === middle; 3 === right
+               // Note: button is not normalized, so don't use it
+               if ( !event.which && event.button !== undefined ) {
+                       event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+               }
+
+               return event;
+       },
+
+       // Deprecated, use jQuery.guid instead
+       guid: 1E8,
+
+       // Deprecated, use jQuery.proxy instead
+       proxy: jQuery.proxy,
+
+       special: {
+               ready: {
+                       // Make sure the ready event is setup
+                       setup: jQuery.bindReady,
+                       teardown: jQuery.noop
+               },
+
+               live: {
+                       add: function( handleObj ) {
+                               jQuery.event.add( this,
+                                       liveConvert( handleObj.origType, handleObj.selector ),
+                                       jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );
+                       },
+
+                       remove: function( handleObj ) {
+                               jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );
+                       }
+               },
+
+               beforeunload: {
+                       setup: function( data, namespaces, eventHandle ) {
+                               // We only want to do this special case on windows
+                               if ( jQuery.isWindow( this ) ) {
+                                       this.onbeforeunload = eventHandle;
+                               }
+                       },
+
+                       teardown: function( namespaces, eventHandle ) {
+                               if ( this.onbeforeunload === eventHandle ) {
+                                       this.onbeforeunload = null;
+                               }
+                       }
+               }
+       }
+};
+
+jQuery.removeEvent = document.removeEventListener ?
+       function( elem, type, handle ) {
+               if ( elem.removeEventListener ) {
+                       elem.removeEventListener( type, handle, false );
+               }
+       } :
+       function( elem, type, handle ) {
+               if ( elem.detachEvent ) {
+                       elem.detachEvent( "on" + type, handle );
+               }
+       };
+
+jQuery.Event = function( src, props ) {
+       // Allow instantiation without the 'new' keyword
+       if ( !this.preventDefault ) {
+               return new jQuery.Event( src, props );
+       }
+
+       // Event object
+       if ( src && src.type ) {
+               this.originalEvent = src;
+               this.type = src.type;
+
+               // Events bubbling up the document may have been marked as prevented
+               // by a handler lower down the tree; reflect the correct value.
+               this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||
+                       src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;
+
+       // Event type
+       } else {
+               this.type = src;
+       }
+
+       // Put explicitly provided properties onto the event object
+       if ( props ) {
+               jQuery.extend( this, props );
+       }
+
+       // timeStamp is buggy for some events on Firefox(#3843)
+       // So we won't rely on the native value
+       this.timeStamp = jQuery.now();
+
+       // Mark it as fixed
+       this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+       return false;
+}
+function returnTrue() {
+       return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+       preventDefault: function() {
+               this.isDefaultPrevented = returnTrue;
+
+               var e = this.originalEvent;
+               if ( !e ) {
+                       return;
+               }
+
+               // if preventDefault exists run it on the original event
+               if ( e.preventDefault ) {
+                       e.preventDefault();
+
+               // otherwise set the returnValue property of the original event to false (IE)
+               } else {
+                       e.returnValue = false;
+               }
+       },
+       stopPropagation: function() {
+               this.isPropagationStopped = returnTrue;
+
+               var e = this.originalEvent;
+               if ( !e ) {
+                       return;
+               }
+               // if stopPropagation exists run it on the original event
+               if ( e.stopPropagation ) {
+                       e.stopPropagation();
+               }
+               // otherwise set the cancelBubble property of the original event to true (IE)
+               e.cancelBubble = true;
+       },
+       stopImmediatePropagation: function() {
+               this.isImmediatePropagationStopped = returnTrue;
+               this.stopPropagation();
+       },
+       isDefaultPrevented: returnFalse,
+       isPropagationStopped: returnFalse,
+       isImmediatePropagationStopped: returnFalse
+};
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function( event ) {
+       // Check if mouse(over|out) are still within the same parent element
+       var parent = event.relatedTarget;
+
+       // Firefox sometimes assigns relatedTarget a XUL element
+       // which we cannot access the parentNode property of
+       try {
+
+               // Chrome does something similar, the parentNode property
+               // can be accessed but is null.
+               if ( parent && parent !== document && !parent.parentNode ) {
+                       return;
+               }
+               // Traverse up the tree
+               while ( parent && parent !== this ) {
+                       parent = parent.parentNode;
+               }
+
+               if ( parent !== this ) {
+                       // set the correct event type
+                       event.type = event.data;
+
+                       // handle event if we actually just moused on to a non sub-element
+                       jQuery.event.handle.apply( this, arguments );
+               }
+
+       // assuming we've left the element since we most likely mousedover a xul element
+       } catch(e) { }
+},
+
+// In case of event delegation, we only need to rename the event.type,
+// liveHandler will take care of the rest.
+delegate = function( event ) {
+       event.type = event.data;
+       jQuery.event.handle.apply( this, arguments );
+};
+
+// Create mouseenter and mouseleave events
+jQuery.each({
+       mouseenter: "mouseover",
+       mouseleave: "mouseout"
+}, function( orig, fix ) {
+       jQuery.event.special[ orig ] = {
+               setup: function( data ) {
+                       jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
+               },
+               teardown: function( data ) {
+                       jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
+               }
+       };
+});
+
+// submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+       jQuery.event.special.submit = {
+               setup: function( data, namespaces ) {
+                       if ( !jQuery.nodeName( this, "form" ) ) {
+                               jQuery.event.add(this, "click.specialSubmit", function( e ) {
+                                       var elem = e.target,
+                                               type = elem.type;
+
+                                       if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
+                                               trigger( "submit", this, arguments );
+                                       }
+                               });
+
+                               jQuery.event.add(this, "keypress.specialSubmit", function( e ) {
+                                       var elem = e.target,
+                                               type = elem.type;
+
+                                       if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
+                                               trigger( "submit", this, arguments );
+                                       }
+                               });
+
+                       } else {
+                               return false;
+                       }
+               },
+
+               teardown: function( namespaces ) {
+                       jQuery.event.remove( this, ".specialSubmit" );
+               }
+       };
+
+}
+
+// change delegation, happens here so we have bind.
+if ( !jQuery.support.changeBubbles ) {
+
+       var changeFilters,
+
+       getVal = function( elem ) {
+               var type = elem.type, val = elem.value;
+
+               if ( type === "radio" || type === "checkbox" ) {
+                       val = elem.checked;
+
+               } else if ( type === "select-multiple" ) {
+                       val = elem.selectedIndex > -1 ?
+                               jQuery.map( elem.options, function( elem ) {
+                                       return elem.selected;
+                               }).join("-") :
+                               "";
+
+               } else if ( jQuery.nodeName( elem, "select" ) ) {
+                       val = elem.selectedIndex;
+               }
+
+               return val;
+       },
+
+       testChange = function testChange( e ) {
+               var elem = e.target, data, val;
+
+               if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {
+                       return;
+               }
+
+               data = jQuery._data( elem, "_change_data" );
+               val = getVal(elem);
+
+               // the current data will be also retrieved by beforeactivate
+               if ( e.type !== "focusout" || elem.type !== "radio" ) {
+                       jQuery._data( elem, "_change_data", val );
+               }
+
+               if ( data === undefined || val === data ) {
+                       return;
+               }
+
+               if ( data != null || val ) {
+                       e.type = "change";
+                       e.liveFired = undefined;
+                       jQuery.event.trigger( e, arguments[1], elem );
+               }
+       };
+
+       jQuery.event.special.change = {
+               filters: {
+                       focusout: testChange,
+
+                       beforedeactivate: testChange,
+
+                       click: function( e ) {
+                               var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+
+                               if ( type === "radio" || type === "checkbox" || jQuery.nodeName( elem, "select" ) ) {
+                                       testChange.call( this, e );
+                               }
+                       },
+
+                       // Change has to be called before submit
+                       // Keydown will be called before keypress, which is used in submit-event delegation
+                       keydown: function( e ) {
+                               var elem = e.target, type = jQuery.nodeName( elem, "input" ) ? elem.type : "";
+
+                               if ( (e.keyCode === 13 && !jQuery.nodeName( elem, "textarea" ) ) ||
+                                       (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
+                                       type === "select-multiple" ) {
+                                       testChange.call( this, e );
+                               }
+                       },
+
+                       // Beforeactivate happens also before the previous element is blurred
+                       // with this event you can't trigger a change event, but you can store
+                       // information
+                       beforeactivate: function( e ) {
+                               var elem = e.target;
+                               jQuery._data( elem, "_change_data", getVal(elem) );
+                       }
+               },
+
+               setup: function( data, namespaces ) {
+                       if ( this.type === "file" ) {
+                               return false;
+                       }
+
+                       for ( var type in changeFilters ) {
+                               jQuery.event.add( this, type + ".specialChange", changeFilters[type] );
+                       }
+
+                       return rformElems.test( this.nodeName );
+               },
+
+               teardown: function( namespaces ) {
+                       jQuery.event.remove( this, ".specialChange" );
+
+                       return rformElems.test( this.nodeName );
+               }
+       };
+
+       changeFilters = jQuery.event.special.change.filters;
+
+       // Handle when the input is .focus()'d
+       changeFilters.focus = changeFilters.beforeactivate;
+}
+
+function trigger( type, elem, args ) {
+       // Piggyback on a donor event to simulate a different one.
+       // Fake originalEvent to avoid donor's stopPropagation, but if the
+       // simulated event prevents default then we do the same on the donor.
+       // Don't pass args or remember liveFired; they apply to the donor event.
+       var event = jQuery.extend( {}, args[ 0 ] );
+       event.type = type;
+       event.originalEvent = {};
+       event.liveFired = undefined;
+       jQuery.event.handle.call( elem, event );
+       if ( event.isDefaultPrevented() ) {
+               args[ 0 ].preventDefault();
+       }
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+       jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+               // Attach a single capturing handler while someone wants focusin/focusout
+               var attaches = 0;
+
+               jQuery.event.special[ fix ] = {
+                       setup: function() {
+                               if ( attaches++ === 0 ) {
+                                       document.addEventListener( orig, handler, true );
+                               }
+                       },
+                       teardown: function() {
+                               if ( --attaches === 0 ) {
+                                       document.removeEventListener( orig, handler, true );
+                               }
+                       }
+               };
+
+               function handler( donor ) {
+                       // Donor event is always a native one; fix it and switch its type.
+                       // Let focusin/out handler cancel the donor focus/blur event.
+                       var e = jQuery.event.fix( donor );
+                       e.type = fix;
+                       e.originalEvent = {};
+                       jQuery.event.trigger( e, null, e.target );
+                       if ( e.isDefaultPrevented() ) {
+                               donor.preventDefault();
+                       }
+               }
+       });
+}
+
+jQuery.each(["bind", "one"], function( i, name ) {
+       jQuery.fn[ name ] = function( type, data, fn ) {
+               var handler;
+
+               // Handle object literals
+               if ( typeof type === "object" ) {
+                       for ( var key in type ) {
+                               this[ name ](key, data, type[key], fn);
+                       }
+                       return this;
+               }
+
+               if ( arguments.length === 2 || data === false ) {
+                       fn = data;
+                       data = undefined;
+               }
+
+               if ( name === "one" ) {
+                       handler = function( event ) {
+                               jQuery( this ).unbind( event, handler );
+                               return fn.apply( this, arguments );
+                       };
+                       handler.guid = fn.guid || jQuery.guid++;
+               } else {
+                       handler = fn;
+               }
+
+               if ( type === "unload" && name !== "one" ) {
+                       this.one( type, data, fn );
+
+               } else {
+                       for ( var i = 0, l = this.length; i < l; i++ ) {
+                               jQuery.event.add( this[i], type, handler, data );
+                       }
+               }
+
+               return this;
+       };
+});
+
+jQuery.fn.extend({
+       unbind: function( type, fn ) {
+               // Handle object literals
+               if ( typeof type === "object" && !type.preventDefault ) {
+                       for ( var key in type ) {
+                               this.unbind(key, type[key]);
+                       }
+
+               } else {
+                       for ( var i = 0, l = this.length; i < l; i++ ) {
+                               jQuery.event.remove( this[i], type, fn );
+                       }
+               }
+
+               return this;
+       },
+
+       delegate: function( selector, types, data, fn ) {
+               return this.live( types, data, fn, selector );
+       },
+
+       undelegate: function( selector, types, fn ) {
+               if ( arguments.length === 0 ) {
+                       return this.unbind( "live" );
+
+               } else {
+                       return this.die( types, null, fn, selector );
+               }
+       },
+
+       trigger: function( type, data ) {
+               return this.each(function() {
+                       jQuery.event.trigger( type, data, this );
+               });
+       },
+
+       triggerHandler: function( type, data ) {
+               if ( this[0] ) {
+                       return jQuery.event.trigger( type, data, this[0], true );
+               }
+       },
+
+       toggle: function( fn ) {
+               // Save reference to arguments for access in closure
+               var args = arguments,
+                       guid = fn.guid || jQuery.guid++,
+                       i = 0,
+                       toggler = function( event ) {
+                               // Figure out which function to execute
+                               var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+                               jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+                               // Make sure that clicks stop
+                               event.preventDefault();
+
+                               // and execute the function
+                               return args[ lastToggle ].apply( this, arguments ) || false;
+                       };
+
+               // link all the functions, so any of them can unbind this click handler
+               toggler.guid = guid;
+               while ( i < args.length ) {
+                       args[ i++ ].guid = guid;
+               }
+
+               return this.click( toggler );
+       },
+
+       hover: function( fnOver, fnOut ) {
+               return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+       }
+});
+
+var liveMap = {
+       focus: "focusin",
+       blur: "focusout",
+       mouseenter: "mouseover",
+       mouseleave: "mouseout"
+};
+
+jQuery.each(["live", "die"], function( i, name ) {
+       jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {
+               var type, i = 0, match, namespaces, preType,
+                       selector = origSelector || this.selector,
+                       context = origSelector ? this : jQuery( this.context );
+
+               if ( typeof types === "object" && !types.preventDefault ) {
+                       for ( var key in types ) {
+                               context[ name ]( key, data, types[key], selector );
+                       }
+
+                       return this;
+               }
+
+               if ( name === "die" && !types &&
+                                       origSelector && origSelector.charAt(0) === "." ) {
+
+                       context.unbind( origSelector );
+
+                       return this;
+               }
+
+               if ( data === false || jQuery.isFunction( data ) ) {
+                       fn = data || returnFalse;
+                       data = undefined;
+               }
+
+               types = (types || "").split(" ");
+
+               while ( (type = types[ i++ ]) != null ) {
+                       match = rnamespaces.exec( type );
+                       namespaces = "";
+
+                       if ( match )  {
+                               namespaces = match[0];
+                               type = type.replace( rnamespaces, "" );
+                       }
+
+                       if ( type === "hover" ) {
+                               types.push( "mouseenter" + namespaces, "mouseleave" + namespaces );
+                               continue;
+                       }
+
+                       preType = type;
+
+                       if ( liveMap[ type ] ) {
+                               types.push( liveMap[ type ] + namespaces );
+                               type = type + namespaces;
+
+                       } else {
+                               type = (liveMap[ type ] || type) + namespaces;
+                       }
+
+                       if ( name === "live" ) {
+                               // bind live handler
+                               for ( var j = 0, l = context.length; j < l; j++ ) {
+                                       jQuery.event.add( context[j], "live." + liveConvert( type, selector ),
+                                               { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );
+                               }
+
+                       } else {
+                               // unbind live handler
+                               context.unbind( "live." + liveConvert( type, selector ), fn );
+                       }
+               }
+
+               return this;
+       };
+});
+
+function liveHandler( event ) {
+       var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,
+               elems = [],
+               selectors = [],
+               events = jQuery._data( this, "events" );
+
+       // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)
+       if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === "click" ) {
+               return;
+       }
+
+       if ( event.namespace ) {
+               namespace = new RegExp("(^|\\.)" + event.namespace.split(".").join("\\.(?:.*\\.)?") + "(\\.|$)");
+       }
+
+       event.liveFired = this;
+
+       var live = events.live.slice(0);
+
+       for ( j = 0; j < live.length; j++ ) {
+               handleObj = live[j];
+
+               if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) {
+                       selectors.push( handleObj.selector );
+
+               } else {
+                       live.splice( j--, 1 );
+               }
+       }
+
+       match = jQuery( event.target ).closest( selectors, event.currentTarget );
+
+       for ( i = 0, l = match.length; i < l; i++ ) {
+               close = match[i];
+
+               for ( j = 0; j < live.length; j++ ) {
+                       handleObj = live[j];
+
+                       if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {
+                               elem = close.elem;
+                               related = null;
+
+                               // Those two events require additional checking
+                               if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) {
+                                       event.type = handleObj.preType;
+                                       related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];
+
+                                       // Make sure not to accidentally match a child element with the same selector
+                                       if ( related && jQuery.contains( elem, related ) ) {
+                                               related = elem;
+                                       }
+                               }
+
+                               if ( !related || related !== elem ) {
+                                       elems.push({ elem: elem, handleObj: handleObj, level: close.level });
+                               }
+                       }
+               }
+       }
+
+       for ( i = 0, l = elems.length; i < l; i++ ) {
+               match = elems[i];
+
+               if ( maxLevel && match.level > maxLevel ) {
+                       break;
+               }
+
+               event.currentTarget = match.elem;
+               event.data = match.handleObj.data;
+               event.handleObj = match.handleObj;
+
+               ret = match.handleObj.origHandler.apply( match.elem, arguments );
+
+               if ( ret === false || event.isPropagationStopped() ) {
+                       maxLevel = match.level;
+
+                       if ( ret === false ) {
+                               stop = false;
+                       }
+                       if ( event.isImmediatePropagationStopped() ) {
+                               break;
+                       }
+               }
+       }
+
+       return stop;
+}
+
+function liveConvert( type, selector ) {
+       return (type && type !== "*" ? type + "." : "") + selector.replace(rperiod, "`").replace(rspaces, "&");
+}
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+       "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+       "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
+
+       // Handle event binding
+       jQuery.fn[ name ] = function( data, fn ) {
+               if ( fn == null ) {
+                       fn = data;
+                       data = null;
+               }
+
+               return arguments.length > 0 ?
+                       this.bind( name, data, fn ) :
+                       this.trigger( name );
+       };
+
+       if ( jQuery.attrFn ) {
+               jQuery.attrFn[ name ] = true;
+       }
+});
+
+
+
+/*!
+ * Sizzle CSS Selector Engine
+ *  Copyright 2011, The Dojo Foundation
+ *  Released under the MIT, BSD, and GPL Licenses.
+ *  More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+       done = 0,
+       toString = Object.prototype.toString,
+       hasDuplicate = false,
+       baseHasDuplicate = true,
+       rBackslash = /\\/g,
+       rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+//   Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+       baseHasDuplicate = false;
+       return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+       results = results || [];
+       context = context || document;
+
+       var origContext = context;
+
+       if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+               return [];
+       }
+       
+       if ( !selector || typeof selector !== "string" ) {
+               return results;
+       }
+
+       var m, set, checkSet, extra, ret, cur, pop, i,
+               prune = true,
+               contextXML = Sizzle.isXML( context ),
+               parts = [],
+               soFar = selector;
+       
+       // Reset the position of the chunker regexp (start from head)
+       do {
+               chunker.exec( "" );
+               m = chunker.exec( soFar );
+
+               if ( m ) {
+                       soFar = m[3];
+               
+                       parts.push( m[1] );
+               
+                       if ( m[2] ) {
+                               extra = m[3];
+                               break;
+                       }
+               }
+       } while ( m );
+
+       if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+               if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+                       set = posProcess( parts[0] + parts[1], context );
+
+               } else {
+                       set = Expr.relative[ parts[0] ] ?
+                               [ context ] :
+                               Sizzle( parts.shift(), context );
+
+                       while ( parts.length ) {
+                               selector = parts.shift();
+
+                               if ( Expr.relative[ selector ] ) {
+                                       selector += parts.shift();
+                               }
+                               
+                               set = posProcess( selector, set );
+                       }
+               }
+
+       } else {
+               // Take a shortcut and set the context if the root selector is an ID
+               // (but not if it'll be faster if the inner selector is an ID)
+               if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+                               Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+                       ret = Sizzle.find( parts.shift(), context, contextXML );
+                       context = ret.expr ?
+                               Sizzle.filter( ret.expr, ret.set )[0] :
+                               ret.set[0];
+               }
+
+               if ( context ) {
+                       ret = seed ?
+                               { expr: parts.pop(), set: makeArray(seed) } :
+                               Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+                       set = ret.expr ?
+                               Sizzle.filter( ret.expr, ret.set ) :
+                               ret.set;
+
+                       if ( parts.length > 0 ) {
+                               checkSet = makeArray( set );
+
+                       } else {
+                               prune = false;
+                       }
+
+                       while ( parts.length ) {
+                               cur = parts.pop();
+                               pop = cur;
+
+                               if ( !Expr.relative[ cur ] ) {
+                                       cur = "";
+                               } else {
+                                       pop = parts.pop();
+                               }
+
+                               if ( pop == null ) {
+                                       pop = context;
+                               }
+
+                               Expr.relative[ cur ]( checkSet, pop, contextXML );
+                       }
+
+               } else {
+                       checkSet = parts = [];
+               }
+       }
+
+       if ( !checkSet ) {
+               checkSet = set;
+       }
+
+       if ( !checkSet ) {
+               Sizzle.error( cur || selector );
+       }
+
+       if ( toString.call(checkSet) === "[object Array]" ) {
+               if ( !prune ) {
+                       results.push.apply( results, checkSet );
+
+               } else if ( context && context.nodeType === 1 ) {
+                       for ( i = 0; checkSet[i] != null; i++ ) {
+                               if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+                                       results.push( set[i] );
+                               }
+                       }
+
+               } else {
+                       for ( i = 0; checkSet[i] != null; i++ ) {
+                               if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+                                       results.push( set[i] );
+                               }
+                       }
+               }
+
+       } else {
+               makeArray( checkSet, results );
+       }
+
+       if ( extra ) {
+               Sizzle( extra, origContext, results, seed );
+               Sizzle.uniqueSort( results );
+       }
+
+       return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+       if ( sortOrder ) {
+               hasDuplicate = baseHasDuplicate;
+               results.sort( sortOrder );
+
+               if ( hasDuplicate ) {
+                       for ( var i = 1; i < results.length; i++ ) {
+                               if ( results[i] === results[ i - 1 ] ) {
+                                       results.splice( i--, 1 );
+                               }
+                       }
+               }
+       }
+
+       return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+       return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+       return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+       var set;
+
+       if ( !expr ) {
+               return [];
+       }
+
+       for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
+               var match,
+                       type = Expr.order[i];
+               
+               if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+                       var left = match[1];
+                       match.splice( 1, 1 );
+
+                       if ( left.substr( left.length - 1 ) !== "\\" ) {
+                               match[1] = (match[1] || "").replace( rBackslash, "" );
+                               set = Expr.find[ type ]( match, context, isXML );
+
+                               if ( set != null ) {
+                                       expr = expr.replace( Expr.match[ type ], "" );
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if ( !set ) {
+               set = typeof context.getElementsByTagName !== "undefined" ?
+                       context.getElementsByTagName( "*" ) :
+                       [];
+       }
+
+       return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+       var match, anyFound,
+               old = expr,
+               result = [],
+               curLoop = set,
+               isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+       while ( expr && set.length ) {
+               for ( var type in Expr.filter ) {
+                       if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+                               var found, item,
+                                       filter = Expr.filter[ type ],
+                                       left = match[1];
+
+                               anyFound = false;
+
+                               match.splice(1,1);
+
+                               if ( left.substr( left.length - 1 ) === "\\" ) {
+                                       continue;
+                               }
+
+                               if ( curLoop === result ) {
+                                       result = [];
+                               }
+
+                               if ( Expr.preFilter[ type ] ) {
+                                       match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+                                       if ( !match ) {
+                                               anyFound = found = true;
+
+                                       } else if ( match === true ) {
+                                               continue;
+                                       }
+                               }
+
+                               if ( match ) {
+                                       for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
+                                               if ( item ) {
+                                                       found = filter( item, match, i, curLoop );
+                                                       var pass = not ^ !!found;
+
+                                                       if ( inplace && found != null ) {
+                                                               if ( pass ) {
+                                                                       anyFound = true;
+
+                                                               } else {
+                                                                       curLoop[i] = false;
+                                                               }
+
+                                                       } else if ( pass ) {
+                                                               result.push( item );
+                                                               anyFound = true;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               if ( found !== undefined ) {
+                                       if ( !inplace ) {
+                                               curLoop = result;
+                                       }
+
+                                       expr = expr.replace( Expr.match[ type ], "" );
+
+                                       if ( !anyFound ) {
+                                               return [];
+                                       }
+
+                                       break;
+                               }
+                       }
+               }
+
+               // Improper expression
+               if ( expr === old ) {
+                       if ( anyFound == null ) {
+                               Sizzle.error( expr );
+
+                       } else {
+                               break;
+                       }
+               }
+
+               old = expr;
+       }
+
+       return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+       throw "Syntax error, unrecognized expression: " + msg;
+};
+
+var Expr = Sizzle.selectors = {
+       order: [ "ID", "NAME", "TAG" ],
+
+       match: {
+               ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+               CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+               NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+               ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+               TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+               CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+               POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+               PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+       },
+
+       leftMatch: {},
+
+       attrMap: {
+               "class": "className",
+               "for": "htmlFor"
+       },
+
+       attrHandle: {
+               href: function( elem ) {
+                       return elem.getAttribute( "href" );
+               },
+               type: function( elem ) {
+                       return elem.getAttribute( "type" );
+               }
+       },
+
+       relative: {
+               "+": function(checkSet, part){
+                       var isPartStr = typeof part === "string",
+                               isTag = isPartStr && !rNonWord.test( part ),
+                               isPartStrNotTag = isPartStr && !isTag;
+
+                       if ( isTag ) {
+                               part = part.toLowerCase();
+                       }
+
+                       for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+                               if ( (elem = checkSet[i]) ) {
+                                       while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+                                       checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+                                               elem || false :
+                                               elem === part;
+                               }
+                       }
+
+                       if ( isPartStrNotTag ) {
+                               Sizzle.filter( part, checkSet, true );
+                       }
+               },
+
+               ">": function( checkSet, part ) {
+                       var elem,
+                               isPartStr = typeof part === "string",
+                               i = 0,
+                               l = checkSet.length;
+
+                       if ( isPartStr && !rNonWord.test( part ) ) {
+                               part = part.toLowerCase();
+
+                               for ( ; i < l; i++ ) {
+                                       elem = checkSet[i];
+
+                                       if ( elem ) {
+                                               var parent = elem.parentNode;
+                                               checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+                                       }
+                               }
+
+                       } else {
+                               for ( ; i < l; i++ ) {
+                                       elem = checkSet[i];
+
+                                       if ( elem ) {
+                                               checkSet[i] = isPartStr ?
+                                                       elem.parentNode :
+                                                       elem.parentNode === part;
+                                       }
+                               }
+
+                               if ( isPartStr ) {
+                                       Sizzle.filter( part, checkSet, true );
+                               }
+                       }
+               },
+
+               "": function(checkSet, part, isXML){
+                       var nodeCheck,
+                               doneName = done++,
+                               checkFn = dirCheck;
+
+                       if ( typeof part === "string" && !rNonWord.test( part ) ) {
+                               part = part.toLowerCase();
+                               nodeCheck = part;
+                               checkFn = dirNodeCheck;
+                       }
+
+                       checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+               },
+
+               "~": function( checkSet, part, isXML ) {
+                       var nodeCheck,
+                               doneName = done++,
+                               checkFn = dirCheck;
+
+                       if ( typeof part === "string" && !rNonWord.test( part ) ) {
+                               part = part.toLowerCase();
+                               nodeCheck = part;
+                               checkFn = dirNodeCheck;
+                       }
+
+                       checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+               }
+       },
+
+       find: {
+               ID: function( match, context, isXML ) {
+                       if ( typeof context.getElementById !== "undefined" && !isXML ) {
+                               var m = context.getElementById(match[1]);
+                               // Check parentNode to catch when Blackberry 4.6 returns
+                               // nodes that are no longer in the document #6963
+                               return m && m.parentNode ? [m] : [];
+                       }
+               },
+
+               NAME: function( match, context ) {
+                       if ( typeof context.getElementsByName !== "undefined" ) {
+                               var ret = [],
+                                       results = context.getElementsByName( match[1] );
+
+                               for ( var i = 0, l = results.length; i < l; i++ ) {
+                                       if ( results[i].getAttribute("name") === match[1] ) {
+                                               ret.push( results[i] );
+                                       }
+                               }
+
+                               return ret.length === 0 ? null : ret;
+                       }
+               },
+
+               TAG: function( match, context ) {
+                       if ( typeof context.getElementsByTagName !== "undefined" ) {
+                               return context.getElementsByTagName( match[1] );
+                       }
+               }
+       },
+       preFilter: {
+               CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+                       match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+                       if ( isXML ) {
+                               return match;
+                       }
+
+                       for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+                               if ( elem ) {
+                                       if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+                                               if ( !inplace ) {
+                                                       result.push( elem );
+                                               }
+
+                                       } else if ( inplace ) {
+                                               curLoop[i] = false;
+                                       }
+                               }
+                       }
+
+                       return false;
+               },
+
+               ID: function( match ) {
+                       return match[1].replace( rBackslash, "" );
+               },
+
+               TAG: function( match, curLoop ) {
+                       return match[1].replace( rBackslash, "" ).toLowerCase();
+               },
+
+               CHILD: function( match ) {
+                       if ( match[1] === "nth" ) {
+                               if ( !match[2] ) {
+                                       Sizzle.error( match[0] );
+                               }
+
+                               match[2] = match[2].replace(/^\+|\s*/g, '');
+
+                               // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+                               var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+                                       match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+                                       !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+                               // calculate the numbers (first)n+(last) including if they are negative
+                               match[2] = (test[1] + (test[2] || 1)) - 0;
+                               match[3] = test[3] - 0;
+                       }
+                       else if ( match[2] ) {
+                               Sizzle.error( match[0] );
+                       }
+
+                       // TODO: Move to normal caching system
+                       match[0] = done++;
+
+                       return match;
+               },
+
+               ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+                       var name = match[1] = match[1].replace( rBackslash, "" );
+                       
+                       if ( !isXML && Expr.attrMap[name] ) {
+                               match[1] = Expr.attrMap[name];
+                       }
+
+                       // Handle if an un-quoted value was used
+                       match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+                       if ( match[2] === "~=" ) {
+                               match[4] = " " + match[4] + " ";
+                       }
+
+                       return match;
+               },
+
+               PSEUDO: function( match, curLoop, inplace, result, not ) {
+                       if ( match[1] === "not" ) {
+                               // If we're dealing with a complex expression, or a simple one
+                               if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+                                       match[3] = Sizzle(match[3], null, null, curLoop);
+
+                               } else {
+                                       var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+                                       if ( !inplace ) {
+                                               result.push.apply( result, ret );
+                                       }
+
+                                       return false;
+                               }
+
+                       } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+                               return true;
+                       }
+                       
+                       return match;
+               },
+
+               POS: function( match ) {
+                       match.unshift( true );
+
+                       return match;
+               }
+       },
+       
+       filters: {
+               enabled: function( elem ) {
+                       return elem.disabled === false && elem.type !== "hidden";
+               },
+
+               disabled: function( elem ) {
+                       return elem.disabled === true;
+               },
+
+               checked: function( elem ) {
+                       return elem.checked === true;
+               },
+               
+               selected: function( elem ) {
+                       // Accessing this property makes selected-by-default
+                       // options in Safari work properly
+                       if ( elem.parentNode ) {
+                               elem.parentNode.selectedIndex;
+                       }
+                       
+                       return elem.selected === true;
+               },
+
+               parent: function( elem ) {
+                       return !!elem.firstChild;
+               },
+
+               empty: function( elem ) {
+                       return !elem.firstChild;
+               },
+
+               has: function( elem, i, match ) {
+                       return !!Sizzle( match[3], elem ).length;
+               },
+
+               header: function( elem ) {
+                       return (/h\d/i).test( elem.nodeName );
+               },
+
+               text: function( elem ) {
+                       var attr = elem.getAttribute( "type" ), type = elem.type;
+                       // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) 
+                       // use getAttribute instead to test this case
+                       return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+               },
+
+               radio: function( elem ) {
+                       return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+               },
+
+               checkbox: function( elem ) {
+                       return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+               },
+
+               file: function( elem ) {
+                       return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+               },
+
+               password: function( elem ) {
+                       return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+               },
+
+               submit: function( elem ) {
+                       var name = elem.nodeName.toLowerCase();
+                       return (name === "input" || name === "button") && "submit" === elem.type;
+               },
+
+               image: function( elem ) {
+                       return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+               },
+
+               reset: function( elem ) {
+                       return elem.nodeName.toLowerCase() === "input" && "reset" === elem.type;
+               },
+
+               button: function( elem ) {
+                       var name = elem.nodeName.toLowerCase();
+                       return name === "input" && "button" === elem.type || name === "button";
+               },
+
+               input: function( elem ) {
+                       return (/input|select|textarea|button/i).test( elem.nodeName );
+               },
+
+               focus: function( elem ) {
+                       return elem === elem.ownerDocument.activeElement;
+               }
+       },
+       setFilters: {
+               first: function( elem, i ) {
+                       return i === 0;
+               },
+
+               last: function( elem, i, match, array ) {
+                       return i === array.length - 1;
+               },
+
+               even: function( elem, i ) {
+                       return i % 2 === 0;
+               },
+
+               odd: function( elem, i ) {
+                       return i % 2 === 1;
+               },
+
+               lt: function( elem, i, match ) {
+                       return i < match[3] - 0;
+               },
+
+               gt: function( elem, i, match ) {
+                       return i > match[3] - 0;
+               },
+
+               nth: function( elem, i, match ) {
+                       return match[3] - 0 === i;
+               },
+
+               eq: function( elem, i, match ) {
+                       return match[3] - 0 === i;
+               }
+       },
+       filter: {
+               PSEUDO: function( elem, match, i, array ) {
+                       var name = match[1],
+                               filter = Expr.filters[ name ];
+
+                       if ( filter ) {
+                               return filter( elem, i, match, array );
+
+                       } else if ( name === "contains" ) {
+                               return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+                       } else if ( name === "not" ) {
+                               var not = match[3];
+
+                               for ( var j = 0, l = not.length; j < l; j++ ) {
+                                       if ( not[j] === elem ) {
+                                               return false;
+                                       }
+                               }
+
+                               return true;
+
+                       } else {
+                               Sizzle.error( name );
+                       }
+               },
+
+               CHILD: function( elem, match ) {
+                       var type = match[1],
+                               node = elem;
+
+                       switch ( type ) {
+                               case "only":
+                               case "first":
+                                       while ( (node = node.previousSibling) )  {
+                                               if ( node.nodeType === 1 ) { 
+                                                       return false; 
+                                               }
+                                       }
+
+                                       if ( type === "first" ) { 
+                                               return true; 
+                                       }
+
+                                       node = elem;
+
+                               case "last":
+                                       while ( (node = node.nextSibling) )      {
+                                               if ( node.nodeType === 1 ) { 
+                                                       return false; 
+                                               }
+                                       }
+
+                                       return true;
+
+                               case "nth":
+                                       var first = match[2],
+                                               last = match[3];
+
+                                       if ( first === 1 && last === 0 ) {
+                                               return true;
+                                       }
+                                       
+                                       var doneName = match[0],
+                                               parent = elem.parentNode;
+       
+                                       if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
+                                               var count = 0;
+                                               
+                                               for ( node = parent.firstChild; node; node = node.nextSibling ) {
+                                                       if ( node.nodeType === 1 ) {
+                                                               node.nodeIndex = ++count;
+                                                       }
+                                               } 
+
+                                               parent.sizcache = doneName;
+                                       }
+                                       
+                                       var diff = elem.nodeIndex - last;
+
+                                       if ( first === 0 ) {
+                                               return diff === 0;
+
+                                       } else {
+                                               return ( diff % first === 0 && diff / first >= 0 );
+                                       }
+                       }
+               },
+
+               ID: function( elem, match ) {
+                       return elem.nodeType === 1 && elem.getAttribute("id") === match;
+               },
+
+               TAG: function( elem, match ) {
+                       return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
+               },
+               
+               CLASS: function( elem, match ) {
+                       return (" " + (elem.className || elem.getAttribute("class")) + " ")
+                               .indexOf( match ) > -1;
+               },
+
+               ATTR: function( elem, match ) {
+                       var name = match[1],
+                               result = Expr.attrHandle[ name ] ?
+                                       Expr.attrHandle[ name ]( elem ) :
+                                       elem[ name ] != null ?
+                                               elem[ name ] :
+                                               elem.getAttribute( name ),
+                               value = result + "",
+                               type = match[2],
+                               check = match[4];
+
+                       return result == null ?
+                               type === "!=" :
+                               type === "=" ?
+                               value === check :
+                               type === "*=" ?
+                               value.indexOf(check) >= 0 :
+                               type === "~=" ?
+                               (" " + value + " ").indexOf(check) >= 0 :
+                               !check ?
+                               value && result !== false :
+                               type === "!=" ?
+                               value !== check :
+                               type === "^=" ?
+                               value.indexOf(check) === 0 :
+                               type === "$=" ?
+                               value.substr(value.length - check.length) === check :
+                               type === "|=" ?
+                               value === check || value.substr(0, check.length + 1) === check + "-" :
+                               false;
+               },
+
+               POS: function( elem, match, i, array ) {
+                       var name = match[2],
+                               filter = Expr.setFilters[ name ];
+
+                       if ( filter ) {
+                               return filter( elem, i, match, array );
+                       }
+               }
+       }
+};
+
+var origPOS = Expr.match.POS,
+       fescape = function(all, num){
+               return "\\" + (num - 0 + 1);
+       };
+
+for ( var type in Expr.match ) {
+       Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+       Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+
+var makeArray = function( array, results ) {
+       array = Array.prototype.slice.call( array, 0 );
+
+       if ( results ) {
+               results.push.apply( results, array );
+               return results;
+       }
+       
+       return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+       Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+       makeArray = function( array, results ) {
+               var i = 0,
+                       ret = results || [];
+
+               if ( toString.call(array) === "[object Array]" ) {
+                       Array.prototype.push.apply( ret, array );
+
+               } else {
+                       if ( typeof array.length === "number" ) {
+                               for ( var l = array.length; i < l; i++ ) {
+                                       ret.push( array[i] );
+                               }
+
+                       } else {
+                               for ( ; array[i]; i++ ) {
+                                       ret.push( array[i] );
+                               }
+                       }
+               }
+
+               return ret;
+       };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+       sortOrder = function( a, b ) {
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+               }
+
+               if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+                       return a.compareDocumentPosition ? -1 : 1;
+               }
+
+               return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+       };
+
+} else {
+       sortOrder = function( a, b ) {
+               var al, bl,
+                       ap = [],
+                       bp = [],
+                       aup = a.parentNode,
+                       bup = b.parentNode,
+                       cur = aup;
+
+               // The nodes are identical, we can exit early
+               if ( a === b ) {
+                       hasDuplicate = true;
+                       return 0;
+
+               // If the nodes are siblings (or identical) we can do a quick check
+               } else if ( aup === bup ) {
+                       return siblingCheck( a, b );
+
+               // If no parents were found then the nodes are disconnected
+               } else if ( !aup ) {
+                       return -1;
+
+               } else if ( !bup ) {
+                       return 1;
+               }
+
+               // Otherwise they're somewhere else in the tree so we need
+               // to build up a full list of the parentNodes for comparison
+               while ( cur ) {
+                       ap.unshift( cur );
+                       cur = cur.parentNode;
+               }
+
+               cur = bup;
+
+               while ( cur ) {
+                       bp.unshift( cur );
+                       cur = cur.parentNode;
+               }
+
+               al = ap.length;
+               bl = bp.length;
+
+               // Start walking down the tree looking for a discrepancy
+               for ( var i = 0; i < al && i < bl; i++ ) {
+                       if ( ap[i] !== bp[i] ) {
+                               return siblingCheck( ap[i], bp[i] );
+                       }
+               }
+
+               // We ended someplace up the tree so do a sibling check
+               return i === al ?
+                       siblingCheck( a, bp[i], -1 ) :
+                       siblingCheck( ap[i], b, 1 );
+       };
+
+       siblingCheck = function( a, b, ret ) {
+               if ( a === b ) {
+                       return ret;
+               }
+
+               var cur = a.nextSibling;
+
+               while ( cur ) {
+                       if ( cur === b ) {
+                               return -1;
+                       }
+
+                       cur = cur.nextSibling;
+               }
+
+               return 1;
+       };
+}
+
+// Utility function for retreiving the text value of an array of DOM nodes
+Sizzle.getText = function( elems ) {
+       var ret = "", elem;
+
+       for ( var i = 0; elems[i]; i++ ) {
+               elem = elems[i];
+
+               // Get the text from text nodes and CDATA nodes
+               if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
+                       ret += elem.nodeValue;
+
+               // Traverse everything else, except comment nodes
+               } else if ( elem.nodeType !== 8 ) {
+                       ret += Sizzle.getText( elem.childNodes );
+               }
+       }
+
+       return ret;
+};
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+       // We're going to inject a fake input element with a specified name
+       var form = document.createElement("div"),
+               id = "script" + (new Date()).getTime(),
+               root = document.documentElement;
+
+       form.innerHTML = "<a name='" + id + "'/>";
+
+       // Inject it into the root element, check its status, and remove it quickly
+       root.insertBefore( form, root.firstChild );
+
+       // The workaround has to do additional checks after a getElementById
+       // Which slows things down for other browsers (hence the branching)
+       if ( document.getElementById( id ) ) {
+               Expr.find.ID = function( match, context, isXML ) {
+                       if ( typeof context.getElementById !== "undefined" && !isXML ) {
+                               var m = context.getElementById(match[1]);
+
+                               return m ?
+                                       m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+                                               [m] :
+                                               undefined :
+                                       [];
+                       }
+               };
+
+               Expr.filter.ID = function( elem, match ) {
+                       var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+                       return elem.nodeType === 1 && node && node.nodeValue === match;
+               };
+       }
+
+       root.removeChild( form );
+
+       // release memory in IE
+       root = form = null;
+})();
+
+(function(){
+       // Check to see if the browser returns only elements
+       // when doing getElementsByTagName("*")
+
+       // Create a fake element
+       var div = document.createElement("div");
+       div.appendChild( document.createComment("") );
+
+       // Make sure no comments are found
+       if ( div.getElementsByTagName("*").length > 0 ) {
+               Expr.find.TAG = function( match, context ) {
+                       var results = context.getElementsByTagName( match[1] );
+
+                       // Filter out possible comments
+                       if ( match[1] === "*" ) {
+                               var tmp = [];
+
+                               for ( var i = 0; results[i]; i++ ) {
+                                       if ( results[i].nodeType === 1 ) {
+                                               tmp.push( results[i] );
+                                       }
+                               }
+
+                               results = tmp;
+                       }
+
+                       return results;
+               };
+       }
+
+       // Check to see if an attribute returns normalized href attributes
+       div.innerHTML = "<a href='#'></a>";
+
+       if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+                       div.firstChild.getAttribute("href") !== "#" ) {
+
+               Expr.attrHandle.href = function( elem ) {
+                       return elem.getAttribute( "href", 2 );
+               };
+       }
+
+       // release memory in IE
+       div = null;
+})();
+
+if ( document.querySelectorAll ) {
+       (function(){
+               var oldSizzle = Sizzle,
+                       div = document.createElement("div"),
+                       id = "__sizzle__";
+
+               div.innerHTML = "<p class='TEST'></p>";
+
+               // Safari can't handle uppercase or unicode characters when
+               // in quirks mode.
+               if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+                       return;
+               }
+       
+               Sizzle = function( query, context, extra, seed ) {
+                       context = context || document;
+
+                       // Only use querySelectorAll on non-XML documents
+                       // (ID selectors don't work in non-HTML documents)
+                       if ( !seed && !Sizzle.isXML(context) ) {
+                               // See if we find a selector to speed up
+                               var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+                               
+                               if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+                                       // Speed-up: Sizzle("TAG")
+                                       if ( match[1] ) {
+                                               return makeArray( context.getElementsByTagName( query ), extra );
+                                       
+                                       // Speed-up: Sizzle(".CLASS")
+                                       } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+                                               return makeArray( context.getElementsByClassName( match[2] ), extra );
+                                       }
+                               }
+                               
+                               if ( context.nodeType === 9 ) {
+                                       // Speed-up: Sizzle("body")
+                                       // The body element only exists once, optimize finding it
+                                       if ( query === "body" && context.body ) {
+                                               return makeArray( [ context.body ], extra );
+                                               
+                                       // Speed-up: Sizzle("#ID")
+                                       } else if ( match && match[3] ) {
+                                               var elem = context.getElementById( match[3] );
+
+                                               // Check parentNode to catch when Blackberry 4.6 returns
+                                               // nodes that are no longer in the document #6963
+                                               if ( elem && elem.parentNode ) {
+                                                       // Handle the case where IE and Opera return items
+                                                       // by name instead of ID
+                                                       if ( elem.id === match[3] ) {
+                                                               return makeArray( [ elem ], extra );
+                                                       }
+                                                       
+                                               } else {
+                                                       return makeArray( [], extra );
+                                               }
+                                       }
+                                       
+                                       try {
+                                               return makeArray( context.querySelectorAll(query), extra );
+                                       } catch(qsaError) {}
+
+                               // qSA works strangely on Element-rooted queries
+                               // We can work around this by specifying an extra ID on the root
+                               // and working up from there (Thanks to Andrew Dupont for the technique)
+                               // IE 8 doesn't work on object elements
+                               } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+                                       var oldContext = context,
+                                               old = context.getAttribute( "id" ),
+                                               nid = old || id,
+                                               hasParent = context.parentNode,
+                                               relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+                                       if ( !old ) {
+                                               context.setAttribute( "id", nid );
+                                       } else {
+                                               nid = nid.replace( /'/g, "\\$&" );
+                                       }
+                                       if ( relativeHierarchySelector && hasParent ) {
+                                               context = context.parentNode;
+                                       }
+
+                                       try {
+                                               if ( !relativeHierarchySelector || hasParent ) {
+                                                       return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+                                               }
+
+                                       } catch(pseudoError) {
+                                       } finally {
+                                               if ( !old ) {
+                                                       oldContext.removeAttribute( "id" );
+                                               }
+                                       }
+                               }
+                       }
+               
+                       return oldSizzle(query, context, extra, seed);
+               };
+
+               for ( var prop in oldSizzle ) {
+                       Sizzle[ prop ] = oldSizzle[ prop ];
+               }
+
+               // release memory in IE
+               div = null;
+       })();
+}
+
+(function(){
+       var html = document.documentElement,
+               matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+       if ( matches ) {
+               // Check to see if it's possible to do matchesSelector
+               // on a disconnected node (IE 9 fails this)
+               var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+                       pseudoWorks = false;
+
+               try {
+                       // This should fail with an exception
+                       // Gecko does not error, returns false instead
+                       matches.call( document.documentElement, "[test!='']:sizzle" );
+       
+               } catch( pseudoError ) {
+                       pseudoWorks = true;
+               }
+
+               Sizzle.matchesSelector = function( node, expr ) {
+                       // Make sure that attribute selectors are quoted
+                       expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+                       if ( !Sizzle.isXML( node ) ) {
+                               try { 
+                                       if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+                                               var ret = matches.call( node, expr );
+
+                                               // IE 9's matchesSelector returns false on disconnected nodes
+                                               if ( ret || !disconnectedMatch ||
+                                                               // As well, disconnected nodes are said to be in a document
+                                                               // fragment in IE 9, so check for that
+                                                               node.document && node.document.nodeType !== 11 ) {
+                                                       return ret;
+                                               }
+                                       }
+                               } catch(e) {}
+                       }
+
+                       return Sizzle(expr, null, null, [node]).length > 0;
+               };
+       }
+})();
+
+(function(){
+       var div = document.createElement("div");
+
+       div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+       // Opera can't find a second classname (in 9.6)
+       // Also, make sure that getElementsByClassName actually exists
+       if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+               return;
+       }
+
+       // Safari caches class attributes, doesn't catch changes (in 3.2)
+       div.lastChild.className = "e";
+
+       if ( div.getElementsByClassName("e").length === 1 ) {
+               return;
+       }
+       
+       Expr.order.splice(1, 0, "CLASS");
+       Expr.find.CLASS = function( match, context, isXML ) {
+               if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+                       return context.getElementsByClassName(match[1]);
+               }
+       };
+
+       // release memory in IE
+       div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+               var elem = checkSet[i];
+
+               if ( elem ) {
+                       var match = false;
+
+                       elem = elem[dir];
+
+                       while ( elem ) {
+                               if ( elem.sizcache === doneName ) {
+                                       match = checkSet[elem.sizset];
+                                       break;
+                               }
+
+                               if ( elem.nodeType === 1 && !isXML ){
+                                       elem.sizcache = doneName;
+                                       elem.sizset = i;
+                               }
+
+                               if ( elem.nodeName.toLowerCase() === cur ) {
+                                       match = elem;
+                                       break;
+                               }
+
+                               elem = elem[dir];
+                       }
+
+                       checkSet[i] = match;
+               }
+       }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+       for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+               var elem = checkSet[i];
+
+               if ( elem ) {
+                       var match = false;
+                       
+                       elem = elem[dir];
+
+                       while ( elem ) {
+                               if ( elem.sizcache === doneName ) {
+                                       match = checkSet[elem.sizset];
+                                       break;
+                               }
+
+                               if ( elem.nodeType === 1 ) {
+                                       if ( !isXML ) {
+                                               elem.sizcache = doneName;
+                                               elem.sizset = i;
+                                       }
+
+                                       if ( typeof cur !== "string" ) {
+                                               if ( elem === cur ) {
+                                                       match = true;
+                                                       break;
+                                               }
+
+                                       } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+                                               match = elem;
+                                               break;
+                                       }
+                               }
+
+                               elem = elem[dir];
+                       }
+
+                       checkSet[i] = match;
+               }
+       }
+}
+
+if ( document.documentElement.contains ) {
+       Sizzle.contains = function( a, b ) {
+               return a !== b && (a.contains ? a.contains(b) : true);
+       };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+       Sizzle.contains = function( a, b ) {
+               return !!(a.compareDocumentPosition(b) & 16);
+       };
+
+} else {
+       Sizzle.contains = function() {
+               return false;
+       };
+}
+
+Sizzle.isXML = function( elem ) {
+       // documentElement is verified for cases where it doesn't yet exist
+       // (such as loading iframes in IE - #4833) 
+       var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+       return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context ) {
+       var match,
+               tmpSet = [],
+               later = "",
+               root = context.nodeType ? [context] : context;
+
+       // Position selectors must be done after the filter
+       // And so must :not(positional) so we move all PSEUDOs to the end
+       while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+               later += match[0];
+               selector = selector.replace( Expr.match.PSEUDO, "" );
+       }
+
+       selector = Expr.relative[selector] ? selector + "*" : selector;
+
+       for ( var i = 0, l = root.length; i < l; i++ ) {
+               Sizzle( selector, root[i], tmpSet );
+       }
+
+       return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})();
+
+
+var runtil = /Until$/,
+       rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+       // Note: This RegExp should be improved, or likely pulled from Sizzle
+       rmultiselector = /,/,
+       isSimple = /^.[^:#\[\.,]*$/,
+       slice = Array.prototype.slice,
+       POS = jQuery.expr.match.POS,
+       // methods guaranteed to produce a unique set when starting from a unique set
+       guaranteedUnique = {
+               children: true,
+               contents: true,
+               next: true,
+               prev: true
+       };
+
+jQuery.fn.extend({
+       find: function( selector ) {
+               var self = this,
+                       i, l;
+
+               if ( typeof selector !== "string" ) {
+                       return jQuery( selector ).filter(function() {
+                               for ( i = 0, l = self.length; i < l; i++ ) {
+                                       if ( jQuery.contains( self[ i ], this ) ) {
+                                               return true;
+                                       }
+                               }
+                       });
+               }
+
+               var ret = this.pushStack( "", "find", selector ),
+                       length, n, r;
+
+               for ( i = 0, l = this.length; i < l; i++ ) {
+                       length = ret.length;
+                       jQuery.find( selector, this[i], ret );
+
+                       if ( i > 0 ) {
+                               // Make sure that the results are unique
+                               for ( n = length; n < ret.length; n++ ) {
+                                       for ( r = 0; r < length; r++ ) {
+                                               if ( ret[r] === ret[n] ) {
+                                                       ret.splice(n--, 1);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return ret;
+       },
+
+       has: function( target ) {
+               var targets = jQuery( target );
+               return this.filter(function() {
+                       for ( var i = 0, l = targets.length; i < l; i++ ) {
+                               if ( jQuery.contains( this, targets[i] ) ) {
+                                       return true;
+                               }
+                       }
+               });
+       },
+
+       not: function( selector ) {
+               return this.pushStack( winnow(this, selector, false), "not", selector);
+       },
+
+       filter: function( selector ) {
+               return this.pushStack( winnow(this, selector, true), "filter", selector );
+       },
+
+       is: function( selector ) {
+               return !!selector && ( typeof selector === "string" ?
+                       jQuery.filter( selector, this ).length > 0 :
+                       this.filter( selector ).length > 0 );
+       },
+
+       closest: function( selectors, context ) {
+               var ret = [], i, l, cur = this[0];
+               
+               // Array
+               if ( jQuery.isArray( selectors ) ) {
+                       var match, selector,
+                               matches = {},
+                               level = 1;
+
+                       if ( cur && selectors.length ) {
+                               for ( i = 0, l = selectors.length; i < l; i++ ) {
+                                       selector = selectors[i];
+
+                                       if ( !matches[ selector ] ) {
+                                               matches[ selector ] = POS.test( selector ) ?
+                                                       jQuery( selector, context || this.context ) :
+                                                       selector;
+                                       }
+                               }
+
+                               while ( cur && cur.ownerDocument && cur !== context ) {
+                                       for ( selector in matches ) {
+                                               match = matches[ selector ];
+
+                                               if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) {
+                                                       ret.push({ selector: selector, elem: cur, level: level });
+                                               }
+                                       }
+
+                                       cur = cur.parentNode;
+                                       level++;
+                               }
+                       }
+
+                       return ret;
+               }
+
+               // String
+               var pos = POS.test( selectors ) || typeof selectors !== "string" ?
+                               jQuery( selectors, context || this.context ) :
+                               0;
+
+               for ( i = 0, l = this.length; i < l; i++ ) {
+                       cur = this[i];
+
+                       while ( cur ) {
+                               if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+                                       ret.push( cur );
+                                       break;
+
+                               } else {
+                                       cur = cur.parentNode;
+                                       if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+               return this.pushStack( ret, "closest", selectors );
+       },
+
+       // Determine the position of an element within
+       // the matched set of elements
+       index: function( elem ) {
+               if ( !elem || typeof elem === "string" ) {
+                       return jQuery.inArray( this[0],
+                               // If it receives a string, the selector is used
+                               // If it receives nothing, the siblings are used
+                               elem ? jQuery( elem ) : this.parent().children() );
+               }
+               // Locate the position of the desired element
+               return jQuery.inArray(
+                       // If it receives a jQuery object, the first element is used
+                       elem.jquery ? elem[0] : elem, this );
+       },
+
+       add: function( selector, context ) {
+               var set = typeof selector === "string" ?
+                               jQuery( selector, context ) :
+                               jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+                       all = jQuery.merge( this.get(), set );
+
+               return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+                       all :
+                       jQuery.unique( all ) );
+       },
+
+       andSelf: function() {
+               return this.add( this.prevObject );
+       }
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+       return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+       parent: function( elem ) {
+               var parent = elem.parentNode;
+               return parent && parent.nodeType !== 11 ? parent : null;
+       },
+       parents: function( elem ) {
+               return jQuery.dir( elem, "parentNode" );
+       },
+       parentsUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "parentNode", until );
+       },
+       next: function( elem ) {
+               return jQuery.nth( elem, 2, "nextSibling" );
+       },
+       prev: function( elem ) {
+               return jQuery.nth( elem, 2, "previousSibling" );
+       },
+       nextAll: function( elem ) {
+               return jQuery.dir( elem, "nextSibling" );
+       },
+       prevAll: function( elem ) {
+               return jQuery.dir( elem, "previousSibling" );
+       },
+       nextUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "nextSibling", until );
+       },
+       prevUntil: function( elem, i, until ) {
+               return jQuery.dir( elem, "previousSibling", until );
+       },
+       siblings: function( elem ) {
+               return jQuery.sibling( elem.parentNode.firstChild, elem );
+       },
+       children: function( elem ) {
+               return jQuery.sibling( elem.firstChild );
+       },
+       contents: function( elem ) {
+               return jQuery.nodeName( elem, "iframe" ) ?
+                       elem.contentDocument || elem.contentWindow.document :
+                       jQuery.makeArray( elem.childNodes );
+       }
+}, function( name, fn ) {
+       jQuery.fn[ name ] = function( until, selector ) {
+               var ret = jQuery.map( this, fn, until ),
+                       // The variable 'args' was introduced in
+                       // https://github.com/jquery/jquery/commit/52a0238
+                       // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.
+                       // http://code.google.com/p/v8/issues/detail?id=1050
+                       args = slice.call(arguments);
+
+               if ( !runtil.test( name ) ) {
+                       selector = until;
+               }
+
+               if ( selector && typeof selector === "string" ) {
+                       ret = jQuery.filter( selector, ret );
+               }
+
+               ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+               if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+                       ret = ret.reverse();
+               }
+
+               return this.pushStack( ret, name, args.join(",") );
+       };
+});
+
+jQuery.extend({
+       filter: function( expr, elems, not ) {
+               if ( not ) {
+                       expr = ":not(" + expr + ")";
+               }
+
+               return elems.length === 1 ?
+                       jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+                       jQuery.find.matches(expr, elems);
+       },
+
+       dir: function( elem, dir, until ) {
+               var matched = [],
+                       cur = elem[ dir ];
+
+               while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+                       if ( cur.nodeType === 1 ) {
+                               matched.push( cur );
+                       }
+                       cur = cur[dir];
+               }
+               return matched;
+       },
+
+       nth: function( cur, result, dir, elem ) {
+               result = result || 1;
+               var num = 0;
+
+               for ( ; cur; cur = cur[dir] ) {
+                       if ( cur.nodeType === 1 && ++num === result ) {
+                               break;
+                       }
+               }
+
+               return cur;
+       },
+
+       sibling: function( n, elem ) {
+               var r = [];
+
+               for ( ; n; n = n.nextSibling ) {
+                       if ( n.nodeType === 1 && n !== elem ) {
+                               r.push( n );
+                       }
+               }
+
+               return r;
+       }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+       // Can't pass null or undefined to indexOf in Firefox 4
+       // Set to 0 to skip string check
+       qualifier = qualifier || 0;
+
+       if ( jQuery.isFunction( qualifier ) ) {
+               return jQuery.grep(elements, function( elem, i ) {
+                       var retVal = !!qualifier.call( elem, i, elem );
+                       return retVal === keep;
+               });
+
+       } else if ( qualifier.nodeType ) {
+               return jQuery.grep(elements, function( elem, i ) {
+                       return (elem === qualifier) === keep;
+               });
+
+       } else if ( typeof qualifier === "string" ) {
+               var filtered = jQuery.grep(elements, function( elem ) {
+                       return elem.nodeType === 1;
+               });
+
+               if ( isSimple.test( qualifier ) ) {
+                       return jQuery.filter(qualifier, filtered, !keep);
+               } else {
+                       qualifier = jQuery.filter( qualifier, filtered );
+               }
+       }
+
+       return jQuery.grep(elements, function( elem, i ) {
+               return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
+       });
+}
+
+
+
+
+var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+       rleadingWhitespace = /^\s+/,
+       rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+       rtagName = /<([\w:]+)/,
+       rtbody = /<tbody/i,
+       rhtml = /<|&#?\w+;/,
+       rnocache = /<(?:script|object|embed|option|style)/i,
+       // checked="checked" or checked
+       rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+       rscriptType = /\/(java|ecma)script/i,
+       wrapMap = {
+               option: [ 1, "<select multiple='multiple'>", "</select>" ],
+               legend: [ 1, "<fieldset>", "</fieldset>" ],
+               thead: [ 1, "<table>", "</table>" ],
+               tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+               td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+               col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+               area: [ 1, "<map>", "</map>" ],
+               _default: [ 0, "", "" ]
+       };
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+       wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+       text: function( text ) {
+               if ( jQuery.isFunction(text) ) {
+                       return this.each(function(i) {
+                               var self = jQuery( this );
+
+                               self.text( text.call(this, i, self.text()) );
+                       });
+               }
+
+               if ( typeof text !== "object" && text !== undefined ) {
+                       return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+               }
+
+               return jQuery.text( this );
+       },
+
+       wrapAll: function( html ) {
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function(i) {
+                               jQuery(this).wrapAll( html.call(this, i) );
+                       });
+               }
+
+               if ( this[0] ) {
+                       // The elements to wrap the target around
+                       var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+                       if ( this[0].parentNode ) {
+                               wrap.insertBefore( this[0] );
+                       }
+
+                       wrap.map(function() {
+                               var elem = this;
+
+                               while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+                                       elem = elem.firstChild;
+                               }
+
+                               return elem;
+                       }).append( this );
+               }
+
+               return this;
+       },
+
+       wrapInner: function( html ) {
+               if ( jQuery.isFunction( html ) ) {
+                       return this.each(function(i) {
+                               jQuery(this).wrapInner( html.call(this, i) );
+                       });
+               }
+
+               return this.each(function() {
+                       var self = jQuery( this ),
+                               contents = self.contents();
+
+                       if ( contents.length ) {
+                               contents.wrapAll( html );
+
+                       } else {
+                               self.append( html );
+                       }
+               });
+       },
+
+       wrap: function( html ) {
+               return this.each(function() {
+                       jQuery( this ).wrapAll( html );
+               });
+       },
+
+       unwrap: function() {
+               return this.parent().each(function() {
+                       if ( !jQuery.nodeName( this, "body" ) ) {
+                               jQuery( this ).replaceWith( this.childNodes );
+                       }
+               }).end();
+       },
+
+       append: function() {
+               return this.domManip(arguments, true, function( elem ) {
+                       if ( this.nodeType === 1 ) {
+                               this.appendChild( elem );
+                       }
+               });
+       },
+
+       prepend: function() {
+               return this.domManip(arguments, true, function( elem ) {
+                       if ( this.nodeType === 1 ) {
+                               this.insertBefore( elem, this.firstChild );
+                       }
+               });
+       },
+
+       before: function() {
+               if ( this[0] && this[0].parentNode ) {
+                       return this.domManip(arguments, false, function( elem ) {
+                               this.parentNode.insertBefore( elem, this );
+                       });
+               } else if ( arguments.length ) {
+                       var set = jQuery(arguments[0]);
+                       set.push.apply( set, this.toArray() );
+                       return this.pushStack( set, "before", arguments );
+               }
+       },
+
+       after: function() {
+               if ( this[0] && this[0].parentNode ) {
+                       return this.domManip(arguments, false, function( elem ) {
+                               this.parentNode.insertBefore( elem, this.nextSibling );
+                       });
+               } else if ( arguments.length ) {
+                       var set = this.pushStack( this, "after", arguments );
+                       set.push.apply( set, jQuery(arguments[0]).toArray() );
+                       return set;
+               }
+       },
+
+       // keepData is for internal use only--do not document
+       remove: function( selector, keepData ) {
+               for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+                       if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+                               if ( !keepData && elem.nodeType === 1 ) {
+                                       jQuery.cleanData( elem.getElementsByTagName("*") );
+                                       jQuery.cleanData( [ elem ] );
+                               }
+
+                               if ( elem.parentNode ) {
+                                       elem.parentNode.removeChild( elem );
+                               }
+                       }
+               }
+
+               return this;
+       },
+
+       empty: function() {
+               for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+                       // Remove element nodes and prevent memory leaks
+                       if ( elem.nodeType === 1 ) {
+                               jQuery.cleanData( elem.getElementsByTagName("*") );
+                       }
+
+                       // Remove any remaining nodes
+                       while ( elem.firstChild ) {
+                               elem.removeChild( elem.firstChild );
+                       }
+               }
+
+               return this;
+       },
+
+       clone: function( dataAndEvents, deepDataAndEvents ) {
+               dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+               deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+               return this.map( function () {
+                       return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+               });
+       },
+
+       html: function( value ) {
+               if ( value === undefined ) {
+                       return this[0] && this[0].nodeType === 1 ?
+                               this[0].innerHTML.replace(rinlinejQuery, "") :
+                               null;
+
+               // See if we can take a shortcut and just use innerHTML
+               } else if ( typeof value === "string" && !rnocache.test( value ) &&
+                       (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
+                       !wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
+
+                       value = value.replace(rxhtmlTag, "<$1></$2>");
+
+                       try {
+                               for ( var i = 0, l = this.length; i < l; i++ ) {
+                                       // Remove element nodes and prevent memory leaks
+                                       if ( this[i].nodeType === 1 ) {
+                                               jQuery.cleanData( this[i].getElementsByTagName("*") );
+                                               this[i].innerHTML = value;
+                                       }
+                               }
+
+                       // If using innerHTML throws an exception, use the fallback method
+                       } catch(e) {
+                               this.empty().append( value );
+                       }
+
+               } else if ( jQuery.isFunction( value ) ) {
+                       this.each(function(i){
+                               var self = jQuery( this );
+
+                               self.html( value.call(this, i, self.html()) );
+                       });
+
+               } else {
+                       this.empty().append( value );
+               }
+
+               return this;
+       },
+
+       replaceWith: function( value ) {
+               if ( this[0] && this[0].parentNode ) {
+                       // Make sure that the elements are removed from the DOM before they are inserted
+                       // this can help fix replacing a parent with child elements
+                       if ( jQuery.isFunction( value ) ) {
+                               return this.each(function(i) {
+                                       var self = jQuery(this), old = self.html();
+                                       self.replaceWith( value.call( this, i, old ) );
+                               });
+                       }
+
+                       if ( typeof value !== "string" ) {
+                               value = jQuery( value ).detach();
+                       }
+
+                       return this.each(function() {
+                               var next = this.nextSibling,
+                                       parent = this.parentNode;
+
+                               jQuery( this ).remove();
+
+                               if ( next ) {
+                                       jQuery(next).before( value );
+                               } else {
+                                       jQuery(parent).append( value );
+                               }
+                       });
+               } else {
+                       return this.length ?
+                               this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+                               this;
+               }
+       },
+
+       detach: function( selector ) {
+               return this.remove( selector, true );
+       },
+
+       domManip: function( args, table, callback ) {
+               var results, first, fragment, parent,
+                       value = args[0],
+                       scripts = [];
+
+               // We can't cloneNode fragments that contain checked, in WebKit
+               if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+                       return this.each(function() {
+                               jQuery(this).domManip( args, table, callback, true );
+                       });
+               }
+
+               if ( jQuery.isFunction(value) ) {
+                       return this.each(function(i) {
+                               var self = jQuery(this);
+                               args[0] = value.call(this, i, table ? self.html() : undefined);
+                               self.domManip( args, table, callback );
+                       });
+               }
+
+               if ( this[0] ) {
+                       parent = value && value.parentNode;
+
+                       // If we're in a fragment, just use that instead of building a new one
+                       if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+                               results = { fragment: parent };
+
+                       } else {
+                               results = jQuery.buildFragment( args, this, scripts );
+                       }
+
+                       fragment = results.fragment;
+
+                       if ( fragment.childNodes.length === 1 ) {
+                               first = fragment = fragment.firstChild;
+                       } else {
+                               first = fragment.firstChild;
+                       }
+
+                       if ( first ) {
+                               table = table && jQuery.nodeName( first, "tr" );
+
+                               for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
+                                       callback.call(
+                                               table ?
+                                                       root(this[i], first) :
+                                                       this[i],
+                                               // Make sure that we do not leak memory by inadvertently discarding
+                                               // the original fragment (which might have attached data) instead of
+                                               // using it; in addition, use the original fragment object for the last
+                                               // item instead of first because it can end up being emptied incorrectly
+                                               // in certain situations (Bug #8070).
+                                               // Fragments from the fragment cache must always be cloned and never used
+                                               // in place.
+                                               results.cacheable || (l > 1 && i < lastIndex) ?
+                                                       jQuery.clone( fragment, true, true ) :
+                                                       fragment
+                                       );
+                               }
+                       }
+
+                       if ( scripts.length ) {
+                               jQuery.each( scripts, evalScript );
+                       }
+               }
+
+               return this;
+       }
+});
+
+function root( elem, cur ) {
+       return jQuery.nodeName(elem, "table") ?
+               (elem.getElementsByTagName("tbody")[0] ||
+               elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+               elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+
+       if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+               return;
+       }
+
+       var internalKey = jQuery.expando,
+               oldData = jQuery.data( src ),
+               curData = jQuery.data( dest, oldData );
+
+       // Switch to use the internal data object, if it exists, for the next
+       // stage of data copying
+       if ( (oldData = oldData[ internalKey ]) ) {
+               var events = oldData.events;
+                               curData = curData[ internalKey ] = jQuery.extend({}, oldData);
+
+               if ( events ) {
+                       delete curData.handle;
+                       curData.events = {};
+
+                       for ( var type in events ) {
+                               for ( var i = 0, l = events[ type ].length; i < l; i++ ) {
+                                       jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? "." : "" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );
+                               }
+                       }
+               }
+       }
+}
+
+function cloneFixAttributes( src, dest ) {
+       var nodeName;
+
+       // We do not need to do anything for non-Elements
+       if ( dest.nodeType !== 1 ) {
+               return;
+       }
+
+       // clearAttributes removes the attributes, which we don't want,
+       // but also removes the attachEvent events, which we *do* want
+       if ( dest.clearAttributes ) {
+               dest.clearAttributes();
+       }
+
+       // mergeAttributes, in contrast, only merges back on the
+       // original attributes, not the events
+       if ( dest.mergeAttributes ) {
+               dest.mergeAttributes( src );
+       }
+
+       nodeName = dest.nodeName.toLowerCase();
+
+       // IE6-8 fail to clone children inside object elements that use
+       // the proprietary classid attribute value (rather than the type
+       // attribute) to identify the type of content to display
+       if ( nodeName === "object" ) {
+               dest.outerHTML = src.outerHTML;
+
+       } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+               // IE6-8 fails to persist the checked state of a cloned checkbox
+               // or radio button. Worse, IE6-7 fail to give the cloned element
+               // a checked appearance if the defaultChecked value isn't also set
+               if ( src.checked ) {
+                       dest.defaultChecked = dest.checked = src.checked;
+               }
+
+               // IE6-7 get confused and end up setting the value of a cloned
+               // checkbox/radio button to an empty string instead of "on"
+               if ( dest.value !== src.value ) {
+                       dest.value = src.value;
+               }
+
+       // IE6-8 fails to return the selected option to the default selected
+       // state when cloning options
+       } else if ( nodeName === "option" ) {
+               dest.selected = src.defaultSelected;
+
+       // IE6-8 fails to set the defaultValue to the correct value when
+       // cloning other types of input fields
+       } else if ( nodeName === "input" || nodeName === "textarea" ) {
+               dest.defaultValue = src.defaultValue;
+       }
+
+       // Event data gets referenced instead of copied if the expando
+       // gets copied too
+       dest.removeAttribute( jQuery.expando );
+}
+
+jQuery.buildFragment = function( args, nodes, scripts ) {
+       var fragment, cacheable, cacheresults,
+               doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);
+
+       // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+       // Cloning options loses the selected state, so don't cache them
+       // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+       // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+       if ( args.length === 1 && typeof args[0] === "string" && args[0].length < 512 && doc === document &&
+               args[0].charAt(0) === "<" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {
+
+               cacheable = true;
+
+               cacheresults = jQuery.fragments[ args[0] ];
+               if ( cacheresults && cacheresults !== 1 ) {
+                       fragment = cacheresults;
+               }
+       }
+
+       if ( !fragment ) {
+               fragment = doc.createDocumentFragment();
+               jQuery.clean( args, doc, fragment, scripts );
+       }
+
+       if ( cacheable ) {
+               jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;
+       }
+
+       return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+       appendTo: "append",
+       prependTo: "prepend",
+       insertBefore: "before",
+       insertAfter: "after",
+       replaceAll: "replaceWith"
+}, function( name, original ) {
+       jQuery.fn[ name ] = function( selector ) {
+               var ret = [],
+                       insert = jQuery( selector ),
+                       parent = this.length === 1 && this[0].parentNode;
+
+               if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+                       insert[ original ]( this[0] );
+                       return this;
+
+               } else {
+                       for ( var i = 0, l = insert.length; i < l; i++ ) {
+                               var elems = (i > 0 ? this.clone(true) : this).get();
+                               jQuery( insert[i] )[ original ]( elems );
+                               ret = ret.concat( elems );
+                       }
+
+                       return this.pushStack( ret, name, insert.selector );
+               }
+       };
+});
+
+function getAll( elem ) {
+       if ( "getElementsByTagName" in elem ) {
+               return elem.getElementsByTagName( "*" );
+       
+       } else if ( "querySelectorAll" in elem ) {
+               return elem.querySelectorAll( "*" );
+
+       } else {
+               return [];
+       }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+       if ( elem.type === "checkbox" || elem.type === "radio" ) {
+               elem.defaultChecked = elem.checked;
+       }
+}
+// Finds all inputs and passes them to fixDefaultChecked
+function findInputs( elem ) {
+       if ( jQuery.nodeName( elem, "input" ) ) {
+               fixDefaultChecked( elem );
+       } else if ( elem.getElementsByTagName ) {
+               jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+       }
+}
+
+jQuery.extend({
+       clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+               var clone = elem.cloneNode(true),
+                               srcElements,
+                               destElements,
+                               i;
+
+               if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+                               (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+                       // IE copies events bound via attachEvent when using cloneNode.
+                       // Calling detachEvent on the clone will also remove the events
+                       // from the original. In order to get around this, we use some
+                       // proprietary methods to clear the events. Thanks to MooTools
+                       // guys for this hotness.
+
+                       cloneFixAttributes( elem, clone );
+
+                       // Using Sizzle here is crazy slow, so we use getElementsByTagName
+                       // instead
+                       srcElements = getAll( elem );
+                       destElements = getAll( clone );
+
+                       // Weird iteration because IE will replace the length property
+                       // with an element if you are cloning the body and one of the
+                       // elements on the page has a name or id of "length"
+                       for ( i = 0; srcElements[i]; ++i ) {
+                               cloneFixAttributes( srcElements[i], destElements[i] );
+                       }
+               }
+
+               // Copy the events from the original to the clone
+               if ( dataAndEvents ) {
+                       cloneCopyEvent( elem, clone );
+
+                       if ( deepDataAndEvents ) {
+                               srcElements = getAll( elem );
+                               destElements = getAll( clone );
+
+                               for ( i = 0; srcElements[i]; ++i ) {
+                                       cloneCopyEvent( srcElements[i], destElements[i] );
+                               }
+                       }
+               }
+
+               // Return the cloned set
+               return clone;
+       },
+
+       clean: function( elems, context, fragment, scripts ) {
+               var checkScriptType;
+
+               context = context || document;
+
+               // !context.createElement fails in IE with an error but returns typeof 'object'
+               if ( typeof context.createElement === "undefined" ) {
+                       context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+               }
+
+               var ret = [];
+
+               for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+                       if ( typeof elem === "number" ) {
+                               elem += "";
+                       }
+
+                       if ( !elem ) {
+                               continue;
+                       }
+
+                       // Convert html string into DOM nodes
+                       if ( typeof elem === "string" ) {
+                               if ( !rhtml.test( elem ) ) {
+                                       elem = context.createTextNode( elem );
+                               } else {
+                                       // Fix "XHTML"-style tags in all browsers
+                                       elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+                                       // Trim whitespace, otherwise indexOf won't work as expected
+                                       var tag = (rtagName.exec( elem ) || ["", ""])[1].toLowerCase(),
+                                               wrap = wrapMap[ tag ] || wrapMap._default,
+                                               depth = wrap[0],
+                                               div = context.createElement("div");
+
+                                       // Go to html and back, then peel off extra wrappers
+                                       div.innerHTML = wrap[1] + elem + wrap[2];
+
+                                       // Move to the right depth
+                                       while ( depth-- ) {
+                                               div = div.lastChild;
+                                       }
+
+                                       // Remove IE's autoinserted <tbody> from table fragments
+                                       if ( !jQuery.support.tbody ) {
+
+                                               // String was a <table>, *may* have spurious <tbody>
+                                               var hasBody = rtbody.test(elem),
+                                                       tbody = tag === "table" && !hasBody ?
+                                                               div.firstChild && div.firstChild.childNodes :
+
+                                                               // String was a bare <thead> or <tfoot>
+                                                               wrap[1] === "<table>" && !hasBody ?
+                                                                       div.childNodes :
+                                                                       [];
+
+                                               for ( var j = tbody.length - 1; j >= 0 ; --j ) {
+                                                       if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+                                                               tbody[ j ].parentNode.removeChild( tbody[ j ] );
+                                                       }
+                                               }
+                                       }
+
+                                       // IE completely kills leading whitespace when innerHTML is used
+                                       if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+                                               div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+                                       }
+
+                                       elem = div.childNodes;
+                               }
+                       }
+
+                       // Resets defaultChecked for any radios and checkboxes
+                       // about to be appended to the DOM in IE 6/7 (#8060)
+                       var len;
+                       if ( !jQuery.support.appendChecked ) {
+                               if ( elem[0] && typeof (len = elem.length) === "number" ) {
+                                       for ( i = 0; i < len; i++ ) {
+                                               findInputs( elem[i] );
+                                       }
+                               } else {
+                                       findInputs( elem );
+                               }
+                       }
+
+                       if ( elem.nodeType ) {
+                               ret.push( elem );
+                       } else {
+                               ret = jQuery.merge( ret, elem );
+                       }
+               }
+
+               if ( fragment ) {
+                       checkScriptType = function( elem ) {
+                               return !elem.type || rscriptType.test( elem.type );
+                       };
+                       for ( i = 0; ret[i]; i++ ) {
+                               if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
+                                       scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
+
+                               } else {
+                                       if ( ret[i].nodeType === 1 ) {
+                                               var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType );
+
+                                               ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+                                       }
+                                       fragment.appendChild( ret[i] );
+                               }
+                       }
+               }
+
+               return ret;
+       },
+
+       cleanData: function( elems ) {
+               var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,
+                       deleteExpando = jQuery.support.deleteExpando;
+
+               for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+                       if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+                               continue;
+                       }
+
+                       id = elem[ jQuery.expando ];
+
+                       if ( id ) {
+                               data = cache[ id ] && cache[ id ][ internalKey ];
+
+                               if ( data && data.events ) {
+                                       for ( var type in data.events ) {
+                                               if ( special[ type ] ) {
+                                                       jQuery.event.remove( elem, type );
+
+                                               // This is a shortcut to avoid jQuery.event.remove's overhead
+                                               } else {
+                                                       jQuery.removeEvent( elem, type, data.handle );
+                                               }
+                                       }
+
+                                       // Null the DOM reference to avoid IE6/7/8 leak (#7054)
+                                       if ( data.handle ) {
+                                               data.handle.elem = null;
+                                       }
+                               }
+
+                               if ( deleteExpando ) {
+                                       delete elem[ jQuery.expando ];
+
+                               } else if ( elem.removeAttribute ) {
+                                       elem.removeAttribute( jQuery.expando );
+                               }
+
+                               delete cache[ id ];
+                       }
+               }
+       }
+});
+
+function evalScript( i, elem ) {
+       if ( elem.src ) {
+               jQuery.ajax({
+                       url: elem.src,
+                       async: false,
+                       dataType: "script"
+               });
+       } else {
+               jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+       }
+
+       if ( elem.parentNode ) {
+               elem.parentNode.removeChild( elem );
+       }
+}
+
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
+       ropacity = /opacity=([^)]*)/,
+       rdashAlpha = /-([a-z])/ig,
+       // fixed for IE9, see #8346
+       rupper = /([A-Z]|^ms)/g,
+       rnumpx = /^-?\d+(?:px)?$/i,
+       rnum = /^-?\d/,
+       rrelNum = /^[+\-]=/,
+       rrelNumFilter = /[^+\-\.\de]+/g,
+
+       cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+       cssWidth = [ "Left", "Right" ],
+       cssHeight = [ "Top", "Bottom" ],
+       curCSS,
+
+       getComputedStyle,
+       currentStyle,
+
+       fcamelCase = function( all, letter ) {
+               return letter.toUpperCase();
+       };
+
+jQuery.fn.css = function( name, value ) {
+       // Setting 'undefined' is a no-op
+       if ( arguments.length === 2 && value === undefined ) {
+               return this;
+       }
+
+       return jQuery.access( this, name, value, true, function( elem, name, value ) {
+               return value !== undefined ?
+                       jQuery.style( elem, name, value ) :
+                       jQuery.css( elem, name );
+       });
+};
+
+jQuery.extend({
+       // Add in style property hooks for overriding the default
+       // behavior of getting and setting a style property
+       cssHooks: {
+               opacity: {
+                       get: function( elem, computed ) {
+                               if ( computed ) {
+                                       // We should always get a number back from opacity
+                                       var ret = curCSS( elem, "opacity", "opacity" );
+                                       return ret === "" ? "1" : ret;
+
+                               } else {
+                                       return elem.style.opacity;
+                               }
+                       }
+               }
+       },
+
+       // Exclude the following css properties to add px
+       cssNumber: {
+               "zIndex": true,
+               "fontWeight": true,
+               "opacity": true,
+               "zoom": true,
+               "lineHeight": true,
+               "widows": true,
+               "orphans": true
+       },
+
+       // Add in properties whose names you wish to fix before
+       // setting or getting the value
+       cssProps: {
+               // normalize float css property
+               "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+       },
+
+       // Get and set the style property on a DOM Node
+       style: function( elem, name, value, extra ) {
+               // Don't set styles on text and comment nodes
+               if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+                       return;
+               }
+
+               // Make sure that we're working with the right name
+               var ret, type, origName = jQuery.camelCase( name ),
+                       style = elem.style, hooks = jQuery.cssHooks[ origName ];
+
+               name = jQuery.cssProps[ origName ] || origName;
+
+               // Check if we're setting a value
+               if ( value !== undefined ) {
+                       type = typeof value;
+
+                       // Make sure that NaN and null values aren't set. See: #7116
+                       if ( type === "number" && isNaN( value ) || value == null ) {
+                               return;
+                       }
+
+                       // convert relative number strings (+= or -=) to relative numbers. #7345
+                       if ( type === "string" && rrelNum.test( value ) ) {
+                               value = +value.replace( rrelNumFilter, "" ) + parseFloat( jQuery.css( elem, name ) );
+                       }
+
+                       // If a number was passed in, add 'px' to the (except for certain CSS properties)
+                       if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+                               value += "px";
+                       }
+
+                       // If a hook was provided, use that value, otherwise just set the specified value
+                       if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+                               // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+                               // Fixes bug #5509
+                               try {
+                                       style[ name ] = value;
+                               } catch(e) {}
+                       }
+
+               } else {
+                       // If a hook was provided get the non-computed value from there
+                       if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+                               return ret;
+                       }
+
+                       // Otherwise just get the value from the style object
+                       return style[ name ];
+               }
+       },
+
+       css: function( elem, name, extra ) {
+               var ret, hooks;
+
+               // Make sure that we're working with the right name
+               name = jQuery.camelCase( name );
+               hooks = jQuery.cssHooks[ name ];
+               name = jQuery.cssProps[ name ] || name;
+
+               // cssFloat needs a special treatment
+               if ( name === "cssFloat" ) {
+                       name = "float";
+               }
+
+               // If a hook was provided get the computed value from there
+               if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+                       return ret;
+
+               // Otherwise, if a way to get the computed value exists, use that
+               } else if ( curCSS ) {
+                       return curCSS( elem, name );
+               }
+       },
+
+       // A method for quickly swapping in/out CSS properties to get correct calculations
+       swap: function( elem, options, callback ) {
+               var old = {};
+
+               // Remember the old values, and insert the new ones
+               for ( var name in options ) {
+                       old[ name ] = elem.style[ name ];
+                       elem.style[ name ] = options[ name ];
+               }
+
+               callback.call( elem );
+
+               // Revert the old values
+               for ( name in options ) {
+                       elem.style[ name ] = old[ name ];
+               }
+       },
+
+       camelCase: function( string ) {
+               return string.replace( rdashAlpha, fcamelCase );
+       }
+});
+
+// DEPRECATED, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
+
+jQuery.each(["height", "width"], function( i, name ) {
+       jQuery.cssHooks[ name ] = {
+               get: function( elem, computed, extra ) {
+                       var val;
+
+                       if ( computed ) {
+                               if ( elem.offsetWidth !== 0 ) {
+                                       val = getWH( elem, name, extra );
+
+                               } else {
+                                       jQuery.swap( elem, cssShow, function() {
+                                               val = getWH( elem, name, extra );
+                                       });
+                               }
+
+                               if ( val <= 0 ) {
+                                       val = curCSS( elem, name, name );
+
+                                       if ( val === "0px" && currentStyle ) {
+                                               val = currentStyle( elem, name, name );
+                                       }
+
+                                       if ( val != null ) {
+                                               // Should return "auto" instead of 0, use 0 for
+                                               // temporary backwards-compat
+                                               return val === "" || val === "auto" ? "0px" : val;
+                                       }
+                               }
+
+                               if ( val < 0 || val == null ) {
+                                       val = elem.style[ name ];
+
+                                       // Should return "auto" instead of 0, use 0 for
+                                       // temporary backwards-compat
+                                       return val === "" || val === "auto" ? "0px" : val;
+                               }
+
+                               return typeof val === "string" ? val : val + "px";
+                       }
+               },
+
+               set: function( elem, value ) {
+                       if ( rnumpx.test( value ) ) {
+                               // ignore negative width and height values #1599
+                               value = parseFloat(value);
+
+                               if ( value >= 0 ) {
+                                       return value + "px";
+                               }
+
+                       } else {
+                               return value;
+                       }
+               }
+       };
+});
+
+if ( !jQuery.support.opacity ) {
+       jQuery.cssHooks.opacity = {
+               get: function( elem, computed ) {
+                       // IE uses filters for opacity
+                       return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+                               ( parseFloat( RegExp.$1 ) / 100 ) + "" :
+                               computed ? "1" : "";
+               },
+
+               set: function( elem, value ) {
+                       var style = elem.style,
+                               currentStyle = elem.currentStyle;
+
+                       // IE has trouble with opacity if it does not have layout
+                       // Force it by setting the zoom level
+                       style.zoom = 1;
+
+                       // Set the alpha filter to set the opacity
+                       var opacity = jQuery.isNaN( value ) ?
+                               "" :
+                               "alpha(opacity=" + value * 100 + ")",
+                               filter = currentStyle && currentStyle.filter || style.filter || "";
+
+                       style.filter = ralpha.test( filter ) ?
+                               filter.replace( ralpha, opacity ) :
+                               filter + " " + opacity;
+               }
+       };
+}
+
+jQuery(function() {
+       // This hook cannot be added until DOM ready because the support test
+       // for it is not run until after DOM ready
+       if ( !jQuery.support.reliableMarginRight ) {
+               jQuery.cssHooks.marginRight = {
+                       get: function( elem, computed ) {
+                               // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+                               // Work around by temporarily setting element display to inline-block
+                               var ret;
+                               jQuery.swap( elem, { "display": "inline-block" }, function() {
+                                       if ( computed ) {
+                                               ret = curCSS( elem, "margin-right", "marginRight" );
+                                       } else {
+                                               ret = elem.style.marginRight;
+                                       }
+                               });
+                               return ret;
+                       }
+               };
+       }
+});
+
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+       getComputedStyle = function( elem, name ) {
+               var ret, defaultView, computedStyle;
+
+               name = name.replace( rupper, "-$1" ).toLowerCase();
+
+               if ( !(defaultView = elem.ownerDocument.defaultView) ) {
+                       return undefined;
+               }
+
+               if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+                       ret = computedStyle.getPropertyValue( name );
+                       if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+                               ret = jQuery.style( elem, name );
+                       }
+               }
+
+               return ret;
+       };
+}
+
+if ( document.documentElement.currentStyle ) {
+       currentStyle = function( elem, name ) {
+               var left,
+                       ret = elem.currentStyle && elem.currentStyle[ name ],
+                       rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],
+                       style = elem.style;
+
+               // From the awesome hack by Dean Edwards
+               // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+               // If we're not dealing with a regular pixel number
+               // but a number that has a weird ending, we need to convert it to pixels
+               if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {
+                       // Remember the original values
+                       left = style.left;
+
+                       // Put in the new values to get a computed value out
+                       if ( rsLeft ) {
+                               elem.runtimeStyle.left = elem.currentStyle.left;
+                       }
+                       style.left = name === "fontSize" ? "1em" : (ret || 0);
+                       ret = style.pixelLeft + "px";
+
+                       // Revert the changed values
+                       style.left = left;
+                       if ( rsLeft ) {
+                               elem.runtimeStyle.left = rsLeft;
+                       }
+               }
+
+               return ret === "" ? "auto" : ret;
+       };
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWH( elem, name, extra ) {
+       var which = name === "width" ? cssWidth : cssHeight,
+               val = name === "width" ? elem.offsetWidth : elem.offsetHeight;
+
+       if ( extra === "border" ) {
+               return val;
+       }
+
+       jQuery.each( which, function() {
+               if ( !extra ) {
+                       val -= parseFloat(jQuery.css( elem, "padding" + this )) || 0;
+               }
+
+               if ( extra === "margin" ) {
+                       val += parseFloat(jQuery.css( elem, "margin" + this )) || 0;
+
+               } else {
+                       val -= parseFloat(jQuery.css( elem, "border" + this + "Width" )) || 0;
+               }
+       });
+
+       return val;
+}
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+       jQuery.expr.filters.hidden = function( elem ) {
+               var width = elem.offsetWidth,
+                       height = elem.offsetHeight;
+
+               return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, "display" )) === "none");
+       };
+
+       jQuery.expr.filters.visible = function( elem ) {
+               return !jQuery.expr.filters.hidden( elem );
+       };
+}
+
+
+
+
+var r20 = /%20/g,
+       rbracket = /\[\]$/,
+       rCRLF = /\r?\n/g,
+       rhash = /#.*$/,
+       rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+       rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+       // #7653, #8125, #8152: local protocol detection
+       rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
+       rnoContent = /^(?:GET|HEAD)$/,
+       rprotocol = /^\/\//,
+       rquery = /\?/,
+       rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+       rselectTextarea = /^(?:select|textarea)/i,
+       rspacesAjax = /\s+/,
+       rts = /([?&])_=[^&]*/,
+       rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+       // Keep a copy of the old load method
+       _load = jQuery.fn.load,
+
+       /* Prefilters
+        * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+        * 2) These are called:
+        *    - BEFORE asking for a transport
+        *    - AFTER param serialization (s.data is a string if s.processData is true)
+        * 3) key is the dataType
+        * 4) the catchall symbol "*" can be used
+        * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+        */
+       prefilters = {},
+
+       /* Transports bindings
+        * 1) key is the dataType
+        * 2) the catchall symbol "*" can be used
+        * 3) selection will start with transport dataType and THEN go to "*" if needed
+        */
+       transports = {},
+
+       // Document location
+       ajaxLocation,
+
+       // Document location segments
+       ajaxLocParts;
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+       ajaxLocation = location.href;
+} catch( e ) {
+       // Use the href attribute of an A element
+       // since IE will modify it given document.location
+       ajaxLocation = document.createElement( "a" );
+       ajaxLocation.href = "";
+       ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+       // dataTypeExpression is optional and defaults to "*"
+       return function( dataTypeExpression, func ) {
+
+               if ( typeof dataTypeExpression !== "string" ) {
+                       func = dataTypeExpression;
+                       dataTypeExpression = "*";
+               }
+
+               if ( jQuery.isFunction( func ) ) {
+                       var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+                               i = 0,
+                               length = dataTypes.length,
+                               dataType,
+                               list,
+                               placeBefore;
+
+                       // For each dataType in the dataTypeExpression
+                       for(; i < length; i++ ) {
+                               dataType = dataTypes[ i ];
+                               // We control if we're asked to add before
+                               // any existing element
+                               placeBefore = /^\+/.test( dataType );
+                               if ( placeBefore ) {
+                                       dataType = dataType.substr( 1 ) || "*";
+                               }
+                               list = structure[ dataType ] = structure[ dataType ] || [];
+                               // then we add to the structure accordingly
+                               list[ placeBefore ? "unshift" : "push" ]( func );
+                       }
+               }
+       };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+               dataType /* internal */, inspected /* internal */ ) {
+
+       dataType = dataType || options.dataTypes[ 0 ];
+       inspected = inspected || {};
+
+       inspected[ dataType ] = true;
+
+       var list = structure[ dataType ],
+               i = 0,
+               length = list ? list.length : 0,
+               executeOnly = ( structure === prefilters ),
+               selection;
+
+       for(; i < length && ( executeOnly || !selection ); i++ ) {
+               selection = list[ i ]( options, originalOptions, jqXHR );
+               // If we got redirected to another dataType
+               // we try there if executing only and not done already
+               if ( typeof selection === "string" ) {
+                       if ( !executeOnly || inspected[ selection ] ) {
+                               selection = undefined;
+                       } else {
+                               options.dataTypes.unshift( selection );
+                               selection = inspectPrefiltersOrTransports(
+                                               structure, options, originalOptions, jqXHR, selection, inspected );
+                       }
+               }
+       }
+       // If we're only executing or nothing was selected
+       // we try the catchall dataType if not done already
+       if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+               selection = inspectPrefiltersOrTransports(
+                               structure, options, originalOptions, jqXHR, "*", inspected );
+       }
+       // unnecessary when only executing (prefilters)
+       // but it'll be ignored by the caller in that case
+       return selection;
+}
+
+jQuery.fn.extend({
+       load: function( url, params, callback ) {
+               if ( typeof url !== "string" && _load ) {
+                       return _load.apply( this, arguments );
+
+               // Don't do a request if no elements are being requested
+               } else if ( !this.length ) {
+                       return this;
+               }
+
+               var off = url.indexOf( " " );
+               if ( off >= 0 ) {
+                       var selector = url.slice( off, url.length );
+                       url = url.slice( 0, off );
+               }
+
+               // Default to a GET request
+               var type = "GET";
+
+               // If the second parameter was provided
+               if ( params ) {
+                       // If it's a function
+                       if ( jQuery.isFunction( params ) ) {
+                               // We assume that it's the callback
+                               callback = params;
+                               params = undefined;
+
+                       // Otherwise, build a param string
+                       } else if ( typeof params === "object" ) {
+                               params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+                               type = "POST";
+                       }
+               }
+
+               var self = this;
+
+               // Request the remote document
+               jQuery.ajax({
+                       url: url,
+                       type: type,
+                       dataType: "html",
+                       data: params,
+                       // Complete callback (responseText is used internally)
+                       complete: function( jqXHR, status, responseText ) {
+                               // Store the response as specified by the jqXHR object
+                               responseText = jqXHR.responseText;
+                               // If successful, inject the HTML into all the matched elements
+                               if ( jqXHR.isResolved() ) {
+                                       // #4825: Get the actual response in case
+                                       // a dataFilter is present in ajaxSettings
+                                       jqXHR.done(function( r ) {
+                                               responseText = r;
+                                       });
+                                       // See if a selector was specified
+                                       self.html( selector ?
+                                               // Create a dummy div to hold the results
+                                               jQuery("<div>")
+                                                       // inject the contents of the document in, removing the scripts
+                                                       // to avoid any 'Permission Denied' errors in IE
+                                                       .append(responseText.replace(rscript, ""))
+
+                                                       // Locate the specified elements
+                                                       .find(selector) :
+
+                                               // If not, just inject the full result
+                                               responseText );
+                               }
+
+                               if ( callback ) {
+                                       self.each( callback, [ responseText, status, jqXHR ] );
+                               }
+                       }
+               });
+
+               return this;
+       },
+
+       serialize: function() {
+               return jQuery.param( this.serializeArray() );
+       },
+
+       serializeArray: function() {
+               return this.map(function(){
+                       return this.elements ? jQuery.makeArray( this.elements ) : this;
+               })
+               .filter(function(){
+                       return this.name && !this.disabled &&
+                               ( this.checked || rselectTextarea.test( this.nodeName ) ||
+                                       rinput.test( this.type ) );
+               })
+               .map(function( i, elem ){
+                       var val = jQuery( this ).val();
+
+                       return val == null ?
+                               null :
+                               jQuery.isArray( val ) ?
+                                       jQuery.map( val, function( val, i ){
+                                               return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+                                       }) :
+                                       { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+               }).get();
+       }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+       jQuery.fn[ o ] = function( f ){
+               return this.bind( o, f );
+       };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+       jQuery[ method ] = function( url, data, callback, type ) {
+               // shift arguments if data argument was omitted
+               if ( jQuery.isFunction( data ) ) {
+                       type = type || callback;
+                       callback = data;
+                       data = undefined;
+               }
+
+               return jQuery.ajax({
+                       type: method,
+                       url: url,
+                       data: data,
+                       success: callback,
+                       dataType: type
+               });
+       };
+});
+
+jQuery.extend({
+
+       getScript: function( url, callback ) {
+               return jQuery.get( url, undefined, callback, "script" );
+       },
+
+       getJSON: function( url, data, callback ) {
+               return jQuery.get( url, data, callback, "json" );
+       },
+
+       // Creates a full fledged settings object into target
+       // with both ajaxSettings and settings fields.
+       // If target is omitted, writes into ajaxSettings.
+       ajaxSetup: function ( target, settings ) {
+               if ( !settings ) {
+                       // Only one parameter, we extend ajaxSettings
+                       settings = target;
+                       target = jQuery.extend( true, jQuery.ajaxSettings, settings );
+               } else {
+                       // target was provided, we extend into it
+                       jQuery.extend( true, target, jQuery.ajaxSettings, settings );
+               }
+               // Flatten fields we don't want deep extended
+               for( var field in { context: 1, url: 1 } ) {
+                       if ( field in settings ) {
+                               target[ field ] = settings[ field ];
+                       } else if( field in jQuery.ajaxSettings ) {
+                               target[ field ] = jQuery.ajaxSettings[ field ];
+                       }
+               }
+               return target;
+       },
+
+       ajaxSettings: {
+               url: ajaxLocation,
+               isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+               global: true,
+               type: "GET",
+               contentType: "application/x-www-form-urlencoded",
+               processData: true,
+               async: true,
+               /*
+               timeout: 0,
+               data: null,
+               dataType: null,
+               username: null,
+               password: null,
+               cache: null,
+               traditional: false,
+               headers: {},
+               */
+
+               accepts: {
+                       xml: "application/xml, text/xml",
+                       html: "text/html",
+                       text: "text/plain",
+                       json: "application/json, text/javascript",
+                       "*": "*/*"
+               },
+
+               contents: {
+                       xml: /xml/,
+                       html: /html/,
+                       json: /json/
+               },
+
+               responseFields: {
+                       xml: "responseXML",
+                       text: "responseText"
+               },
+
+               // List of data converters
+               // 1) key format is "source_type destination_type" (a single space in-between)
+               // 2) the catchall symbol "*" can be used for source_type
+               converters: {
+
+                       // Convert anything to text
+                       "* text": window.String,
+
+                       // Text to html (true = no transformation)
+                       "text html": true,
+
+                       // Evaluate text as a json expression
+                       "text json": jQuery.parseJSON,
+
+                       // Parse text as xml
+                       "text xml": jQuery.parseXML
+               }
+       },
+
+       ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+       ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+       // Main method
+       ajax: function( url, options ) {
+
+               // If url is an object, simulate pre-1.5 signature
+               if ( typeof url === "object" ) {
+                       options = url;
+                       url = undefined;
+               }
+
+               // Force options to be an object
+               options = options || {};
+
+               var // Create the final options object
+                       s = jQuery.ajaxSetup( {}, options ),
+                       // Callbacks context
+                       callbackContext = s.context || s,
+                       // Context for global events
+                       // It's the callbackContext if one was provided in the options
+                       // and if it's a DOM node or a jQuery collection
+                       globalEventContext = callbackContext !== s &&
+                               ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+                                               jQuery( callbackContext ) : jQuery.event,
+                       // Deferreds
+                       deferred = jQuery.Deferred(),
+                       completeDeferred = jQuery._Deferred(),
+                       // Status-dependent callbacks
+                       statusCode = s.statusCode || {},
+                       // ifModified key
+                       ifModifiedKey,
+                       // Headers (they are sent all at once)
+                       requestHeaders = {},
+                       requestHeadersNames = {},
+                       // Response headers
+                       responseHeadersString,
+                       responseHeaders,
+                       // transport
+                       transport,
+                       // timeout handle
+                       timeoutTimer,
+                       // Cross-domain detection vars
+                       parts,
+                       // The jqXHR state
+                       state = 0,
+                       // To know if global events are to be dispatched
+                       fireGlobals,
+                       // Loop variable
+                       i,
+                       // Fake xhr
+                       jqXHR = {
+
+                               readyState: 0,
+
+                               // Caches the header
+                               setRequestHeader: function( name, value ) {
+                                       if ( !state ) {
+                                               var lname = name.toLowerCase();
+                                               name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+                                               requestHeaders[ name ] = value;
+                                       }
+                                       return this;
+                               },
+
+                               // Raw string
+                               getAllResponseHeaders: function() {
+                                       return state === 2 ? responseHeadersString : null;
+                               },
+
+                               // Builds headers hashtable if needed
+                               getResponseHeader: function( key ) {
+                                       var match;
+                                       if ( state === 2 ) {
+                                               if ( !responseHeaders ) {
+                                                       responseHeaders = {};
+                                                       while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+                                                               responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+                                                       }
+                                               }
+                                               match = responseHeaders[ key.toLowerCase() ];
+                                       }
+                                       return match === undefined ? null : match;
+                               },
+
+                               // Overrides response content-type header
+                               overrideMimeType: function( type ) {
+                                       if ( !state ) {
+                                               s.mimeType = type;
+                                       }
+                                       return this;
+                               },
+
+                               // Cancel the request
+                               abort: function( statusText ) {
+                                       statusText = statusText || "abort";
+                                       if ( transport ) {
+                                               transport.abort( statusText );
+                                       }
+                                       done( 0, statusText );
+                                       return this;
+                               }
+                       };
+
+               // Callback for when everything is done
+               // It is defined here because jslint complains if it is declared
+               // at the end of the function (which would be more logical and readable)
+               function done( status, statusText, responses, headers ) {
+
+                       // Called once
+                       if ( state === 2 ) {
+                               return;
+                       }
+
+                       // State is "done" now
+                       state = 2;
+
+                       // Clear timeout if it exists
+                       if ( timeoutTimer ) {
+                               clearTimeout( timeoutTimer );
+                       }
+
+                       // Dereference transport for early garbage collection
+                       // (no matter how long the jqXHR object will be used)
+                       transport = undefined;
+
+                       // Cache response headers
+                       responseHeadersString = headers || "";
+
+                       // Set readyState
+                       jqXHR.readyState = status ? 4 : 0;
+
+                       var isSuccess,
+                               success,
+                               error,
+                               response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+                               lastModified,
+                               etag;
+
+                       // If successful, handle type chaining
+                       if ( status >= 200 && status < 300 || status === 304 ) {
+
+                               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+                               if ( s.ifModified ) {
+
+                                       if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+                                               jQuery.lastModified[ ifModifiedKey ] = lastModified;
+                                       }
+                                       if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+                                               jQuery.etag[ ifModifiedKey ] = etag;
+                                       }
+                               }
+
+                               // If not modified
+                               if ( status === 304 ) {
+
+                                       statusText = "notmodified";
+                                       isSuccess = true;
+
+                               // If we have data
+                               } else {
+
+                                       try {
+                                               success = ajaxConvert( s, response );
+                                               statusText = "success";
+                                               isSuccess = true;
+                                       } catch(e) {
+                                               // We have a parsererror
+                                               statusText = "parsererror";
+                                               error = e;
+                                       }
+                               }
+                       } else {
+                               // We extract error from statusText
+                               // then normalize statusText and status for non-aborts
+                               error = statusText;
+                               if( !statusText || status ) {
+                                       statusText = "error";
+                                       if ( status < 0 ) {
+                                               status = 0;
+                                       }
+                               }
+                       }
+
+                       // Set data for the fake xhr object
+                       jqXHR.status = status;
+                       jqXHR.statusText = statusText;
+
+                       // Success/Error
+                       if ( isSuccess ) {
+                               deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+                       } else {
+                               deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+                       }
+
+                       // Status-dependent callbacks
+                       jqXHR.statusCode( statusCode );
+                       statusCode = undefined;
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+                                               [ jqXHR, s, isSuccess ? success : error ] );
+                       }
+
+                       // Complete
+                       completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );
+
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxComplete", [ jqXHR, s] );
+                               // Handle the global AJAX counter
+                               if ( !( --jQuery.active ) ) {
+                                       jQuery.event.trigger( "ajaxStop" );
+                               }
+                       }
+               }
+
+               // Attach deferreds
+               deferred.promise( jqXHR );
+               jqXHR.success = jqXHR.done;
+               jqXHR.error = jqXHR.fail;
+               jqXHR.complete = completeDeferred.done;
+
+               // Status-dependent callbacks
+               jqXHR.statusCode = function( map ) {
+                       if ( map ) {
+                               var tmp;
+                               if ( state < 2 ) {
+                                       for( tmp in map ) {
+                                               statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+                                       }
+                               } else {
+                                       tmp = map[ jqXHR.status ];
+                                       jqXHR.then( tmp, tmp );
+                               }
+                       }
+                       return this;
+               };
+
+               // Remove hash character (#7531: and string promotion)
+               // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+               // We also use the url parameter if available
+               s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+               // Extract dataTypes list
+               s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+               // Determine if a cross-domain request is in order
+               if ( s.crossDomain == null ) {
+                       parts = rurl.exec( s.url.toLowerCase() );
+                       s.crossDomain = !!( parts &&
+                               ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+                                       ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+                                               ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+                       );
+               }
+
+               // Convert data if not already a string
+               if ( s.data && s.processData && typeof s.data !== "string" ) {
+                       s.data = jQuery.param( s.data, s.traditional );
+               }
+
+               // Apply prefilters
+               inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+               // If request was aborted inside a prefiler, stop there
+               if ( state === 2 ) {
+                       return false;
+               }
+
+               // We can fire global events as of now if asked to
+               fireGlobals = s.global;
+
+               // Uppercase the type
+               s.type = s.type.toUpperCase();
+
+               // Determine if request has content
+               s.hasContent = !rnoContent.test( s.type );
+
+               // Watch for a new set of requests
+               if ( fireGlobals && jQuery.active++ === 0 ) {
+                       jQuery.event.trigger( "ajaxStart" );
+               }
+
+               // More options handling for requests with no content
+               if ( !s.hasContent ) {
+
+                       // If data is available, append data to url
+                       if ( s.data ) {
+                               s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+                       }
+
+                       // Get ifModifiedKey before adding the anti-cache parameter
+                       ifModifiedKey = s.url;
+
+                       // Add anti-cache in url if needed
+                       if ( s.cache === false ) {
+
+                               var ts = jQuery.now(),
+                                       // try replacing _= if it is there
+                                       ret = s.url.replace( rts, "$1_=" + ts );
+
+                               // if nothing was replaced, add timestamp to the end
+                               s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+                       }
+               }
+
+               // Set the correct header, if data is being sent
+               if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+                       jqXHR.setRequestHeader( "Content-Type", s.contentType );
+               }
+
+               // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+               if ( s.ifModified ) {
+                       ifModifiedKey = ifModifiedKey || s.url;
+                       if ( jQuery.lastModified[ ifModifiedKey ] ) {
+                               jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+                       }
+                       if ( jQuery.etag[ ifModifiedKey ] ) {
+                               jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+                       }
+               }
+
+               // Set the Accepts header for the server, depending on the dataType
+               jqXHR.setRequestHeader(
+                       "Accept",
+                       s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+                               s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", */*; q=0.01" : "" ) :
+                               s.accepts[ "*" ]
+               );
+
+               // Check for headers option
+               for ( i in s.headers ) {
+                       jqXHR.setRequestHeader( i, s.headers[ i ] );
+               }
+
+               // Allow custom headers/mimetypes and early abort
+               if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+                               // Abort if not done already
+                               jqXHR.abort();
+                               return false;
+
+               }
+
+               // Install callbacks on deferreds
+               for ( i in { success: 1, error: 1, complete: 1 } ) {
+                       jqXHR[ i ]( s[ i ] );
+               }
+
+               // Get transport
+               transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+               // If no transport, we auto-abort
+               if ( !transport ) {
+                       done( -1, "No Transport" );
+               } else {
+                       jqXHR.readyState = 1;
+                       // Send global event
+                       if ( fireGlobals ) {
+                               globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+                       }
+                       // Timeout
+                       if ( s.async && s.timeout > 0 ) {
+                               timeoutTimer = setTimeout( function(){
+                                       jqXHR.abort( "timeout" );
+                               }, s.timeout );
+                       }
+
+                       try {
+                               state = 1;
+                               transport.send( requestHeaders, done );
+                       } catch (e) {
+                               // Propagate exception as error if not done
+                               if ( status < 2 ) {
+                                       done( -1, e );
+                               // Simply rethrow otherwise
+                               } else {
+                                       jQuery.error( e );
+                               }
+                       }
+               }
+
+               return jqXHR;
+       },
+
+       // Serialize an array of form elements or a set of
+       // key/values into a query string
+       param: function( a, traditional ) {
+               var s = [],
+                       add = function( key, value ) {
+                               // If value is a function, invoke it and return its value
+                               value = jQuery.isFunction( value ) ? value() : value;
+                               s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+                       };
+
+               // Set traditional to true for jQuery <= 1.3.2 behavior.
+               if ( traditional === undefined ) {
+                       traditional = jQuery.ajaxSettings.traditional;
+               }
+
+               // If an array was passed in, assume that it is an array of form elements.
+               if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+                       // Serialize the form elements
+                       jQuery.each( a, function() {
+                               add( this.name, this.value );
+                       });
+
+               } else {
+                       // If traditional, encode the "old" way (the way 1.3.2 or older
+                       // did it), otherwise encode params recursively.
+                       for ( var prefix in a ) {
+                               buildParams( prefix, a[ prefix ], traditional, add );
+                       }
+               }
+
+               // Return the resulting serialization
+               return s.join( "&" ).replace( r20, "+" );
+       }
+});
+
+function buildParams( prefix, obj, traditional, add ) {
+       if ( jQuery.isArray( obj ) ) {
+               // Serialize array item.
+               jQuery.each( obj, function( i, v ) {
+                       if ( traditional || rbracket.test( prefix ) ) {
+                               // Treat each array item as a scalar.
+                               add( prefix, v );
+
+                       } else {
+                               // If array item is non-scalar (array or object), encode its
+                               // numeric index to resolve deserialization ambiguity issues.
+                               // Note that rack (as of 1.0.0) can't currently deserialize
+                               // nested arrays properly, and attempting to do so may cause
+                               // a server error. Possible fixes are to modify rack's
+                               // deserialization algorithm or to provide an option or flag
+                               // to force array serialization to be shallow.
+                               buildParams( prefix + "[" + ( typeof v === "object" || jQuery.isArray(v) ? i : "" ) + "]", v, traditional, add );
+                       }
+               });
+
+       } else if ( !traditional && obj != null && typeof obj === "object" ) {
+               // Serialize object item.
+               for ( var name in obj ) {
+                       buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+               }
+
+       } else {
+               // Serialize scalar item.
+               add( prefix, obj );
+       }
+}
+
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+       // Counter for holding the number of active queries
+       active: 0,
+
+       // Last-Modified header cache for next request
+       lastModified: {},
+       etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+       var contents = s.contents,
+               dataTypes = s.dataTypes,
+               responseFields = s.responseFields,
+               ct,
+               type,
+               finalDataType,
+               firstDataType;
+
+       // Fill responseXXX fields
+       for( type in responseFields ) {
+               if ( type in responses ) {
+                       jqXHR[ responseFields[type] ] = responses[ type ];
+               }
+       }
+
+       // Remove auto dataType and get content-type in the process
+       while( dataTypes[ 0 ] === "*" ) {
+               dataTypes.shift();
+               if ( ct === undefined ) {
+                       ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+               }
+       }
+
+       // Check if we're dealing with a known content-type
+       if ( ct ) {
+               for ( type in contents ) {
+                       if ( contents[ type ] && contents[ type ].test( ct ) ) {
+                               dataTypes.unshift( type );
+                               break;
+                       }
+               }
+       }
+
+       // Check to see if we have a response for the expected dataType
+       if ( dataTypes[ 0 ] in responses ) {
+               finalDataType = dataTypes[ 0 ];
+       } else {
+               // Try convertible dataTypes
+               for ( type in responses ) {
+                       if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+                               finalDataType = type;
+                               break;
+                       }
+                       if ( !firstDataType ) {
+                               firstDataType = type;
+                       }
+               }
+               // Or just use first one
+               finalDataType = finalDataType || firstDataType;
+       }
+
+       // If we found a dataType
+       // We add the dataType to the list if needed
+       // and return the corresponding response
+       if ( finalDataType ) {
+               if ( finalDataType !== dataTypes[ 0 ] ) {
+                       dataTypes.unshift( finalDataType );
+               }
+               return responses[ finalDataType ];
+       }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+       // Apply the dataFilter if provided
+       if ( s.dataFilter ) {
+               response = s.dataFilter( response, s.dataType );
+       }
+
+       var dataTypes = s.dataTypes,
+               converters = {},
+               i,
+               key,
+               length = dataTypes.length,
+               tmp,
+               // Current and previous dataTypes
+               current = dataTypes[ 0 ],
+               prev,
+               // Conversion expression
+               conversion,
+               // Conversion function
+               conv,
+               // Conversion functions (transitive conversion)
+               conv1,
+               conv2;
+
+       // For each dataType in the chain
+       for( i = 1; i < length; i++ ) {
+
+               // Create converters map
+               // with lowercased keys
+               if ( i === 1 ) {
+                       for( key in s.converters ) {
+                               if( typeof key === "string" ) {
+                                       converters[ key.toLowerCase() ] = s.converters[ key ];
+                               }
+                       }
+               }
+
+               // Get the dataTypes
+               prev = current;
+               current = dataTypes[ i ];
+
+               // If current is auto dataType, update it to prev
+               if( current === "*" ) {
+                       current = prev;
+               // If no auto and dataTypes are actually different
+               } else if ( prev !== "*" && prev !== current ) {
+
+                       // Get the converter
+                       conversion = prev + " " + current;
+                       conv = converters[ conversion ] || converters[ "* " + current ];
+
+                       // If there is no direct converter, search transitively
+                       if ( !conv ) {
+                               conv2 = undefined;
+                               for( conv1 in converters ) {
+                                       tmp = conv1.split( " " );
+                                       if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+                                               conv2 = converters[ tmp[1] + " " + current ];
+                                               if ( conv2 ) {
+                                                       conv1 = converters[ conv1 ];
+                                                       if ( conv1 === true ) {
+                                                               conv = conv2;
+                                                       } else if ( conv2 === true ) {
+                                                               conv = conv1;
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+                       // If we found no converter, dispatch an error
+                       if ( !( conv || conv2 ) ) {
+                               jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+                       }
+                       // If found converter is not an equivalence
+                       if ( conv !== true ) {
+                               // Convert with 1 or 2 converters accordingly
+                               response = conv ? conv( response ) : conv2( conv1(response) );
+                       }
+               }
+       }
+       return response;
+}
+
+
+
+
+var jsc = jQuery.now(),
+       jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+       jsonp: "callback",
+       jsonpCallback: function() {
+               return jQuery.expando + "_" + ( jsc++ );
+       }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+       var inspectData = s.contentType === "application/x-www-form-urlencoded" &&
+               ( typeof s.data === "string" );
+
+       if ( s.dataTypes[ 0 ] === "jsonp" ||
+               s.jsonp !== false && ( jsre.test( s.url ) ||
+                               inspectData && jsre.test( s.data ) ) ) {
+
+               var responseContainer,
+                       jsonpCallback = s.jsonpCallback =
+                               jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+                       previous = window[ jsonpCallback ],
+                       url = s.url,
+                       data = s.data,
+                       replace = "$1" + jsonpCallback + "$2";
+
+               if ( s.jsonp !== false ) {
+                       url = url.replace( jsre, replace );
+                       if ( s.url === url ) {
+                               if ( inspectData ) {
+                                       data = data.replace( jsre, replace );
+                               }
+                               if ( s.data === data ) {
+                                       // Add callback manually
+                                       url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+                               }
+                       }
+               }
+
+               s.url = url;
+               s.data = data;
+
+               // Install callback
+               window[ jsonpCallback ] = function( response ) {
+                       responseContainer = [ response ];
+               };
+
+               // Clean-up function
+               jqXHR.always(function() {
+                       // Set callback back to previous value
+                       window[ jsonpCallback ] = previous;
+                       // Call if it was a function and we have a response
+                       if ( responseContainer && jQuery.isFunction( previous ) ) {
+                               window[ jsonpCallback ]( responseContainer[ 0 ] );
+                       }
+               });
+
+               // Use data converter to retrieve json after script execution
+               s.converters["script json"] = function() {
+                       if ( !responseContainer ) {
+                               jQuery.error( jsonpCallback + " was not called" );
+                       }
+                       return responseContainer[ 0 ];
+               };
+
+               // force json dataType
+               s.dataTypes[ 0 ] = "json";
+
+               // Delegate to script
+               return "script";
+       }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+       accepts: {
+               script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+       },
+       contents: {
+               script: /javascript|ecmascript/
+       },
+       converters: {
+               "text script": function( text ) {
+                       jQuery.globalEval( text );
+                       return text;
+               }
+       }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+       if ( s.cache === undefined ) {
+               s.cache = false;
+       }
+       if ( s.crossDomain ) {
+               s.type = "GET";
+               s.global = false;
+       }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+       // This transport only deals with cross domain requests
+       if ( s.crossDomain ) {
+
+               var script,
+                       head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+               return {
+
+                       send: function( _, callback ) {
+
+                               script = document.createElement( "script" );
+
+                               script.async = "async";
+
+                               if ( s.scriptCharset ) {
+                                       script.charset = s.scriptCharset;
+                               }
+
+                               script.src = s.url;
+
+                               // Attach handlers for all browsers
+                               script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+                                       if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+                                               // Handle memory leak in IE
+                                               script.onload = script.onreadystatechange = null;
+
+                                               // Remove the script
+                                               if ( head && script.parentNode ) {
+                                                       head.removeChild( script );
+                                               }
+
+                                               // Dereference the script
+                                               script = undefined;
+
+                                               // Callback if not abort
+                                               if ( !isAbort ) {
+                                                       callback( 200, "success" );
+                                               }
+                                       }
+                               };
+                               // Use insertBefore instead of appendChild  to circumvent an IE6 bug.
+                               // This arises when a base node is used (#2709 and #4378).
+                               head.insertBefore( script, head.firstChild );
+                       },
+
+                       abort: function() {
+                               if ( script ) {
+                                       script.onload( 0, 1 );
+                               }
+                       }
+               };
+       }
+});
+
+
+
+
+var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+       xhrOnUnloadAbort = window.ActiveXObject ? function() {
+               // Abort all pending requests
+               for ( var key in xhrCallbacks ) {
+                       xhrCallbacks[ key ]( 0, 1 );
+               }
+       } : false,
+       xhrId = 0,
+       xhrCallbacks;
+
+// Functions to create xhrs
+function createStandardXHR() {
+       try {
+               return new window.XMLHttpRequest();
+       } catch( e ) {}
+}
+
+function createActiveXHR() {
+       try {
+               return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+       } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+       /* Microsoft failed to properly
+        * implement the XMLHttpRequest in IE7 (can't request local files),
+        * so we use the ActiveXObject when it is available
+        * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+        * we need a fallback.
+        */
+       function() {
+               return !this.isLocal && createStandardXHR() || createActiveXHR();
+       } :
+       // For all other browsers, use the standard XMLHttpRequest object
+       createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+       jQuery.extend( jQuery.support, {
+               ajax: !!xhr,
+               cors: !!xhr && ( "withCredentials" in xhr )
+       });
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+       jQuery.ajaxTransport(function( s ) {
+               // Cross domain only allowed if supported through XMLHttpRequest
+               if ( !s.crossDomain || jQuery.support.cors ) {
+
+                       var callback;
+
+                       return {
+                               send: function( headers, complete ) {
+
+                                       // Get a new xhr
+                                       var xhr = s.xhr(),
+                                               handle,
+                                               i;
+
+                                       // Open the socket
+                                       // Passing null username, generates a login popup on Opera (#2865)
+                                       if ( s.username ) {
+                                               xhr.open( s.type, s.url, s.async, s.username, s.password );
+                                       } else {
+                                               xhr.open( s.type, s.url, s.async );
+                                       }
+
+                                       // Apply custom fields if provided
+                                       if ( s.xhrFields ) {
+                                               for ( i in s.xhrFields ) {
+                                                       xhr[ i ] = s.xhrFields[ i ];
+                                               }
+                                       }
+
+                                       // Override mime type if needed
+                                       if ( s.mimeType && xhr.overrideMimeType ) {
+                                               xhr.overrideMimeType( s.mimeType );
+                                       }
+
+                                       // X-Requested-With header
+                                       // For cross-domain requests, seeing as conditions for a preflight are
+                                       // akin to a jigsaw puzzle, we simply never set it to be sure.
+                                       // (it can always be set on a per-request basis or even using ajaxSetup)
+                                       // For same-domain requests, won't change header if already provided.
+                                       if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+                                               headers[ "X-Requested-With" ] = "XMLHttpRequest";
+                                       }
+
+                                       // Need an extra try/catch for cross domain requests in Firefox 3
+                                       try {
+                                               for ( i in headers ) {
+                                                       xhr.setRequestHeader( i, headers[ i ] );
+                                               }
+                                       } catch( _ ) {}
+
+                                       // Do send the request
+                                       // This may raise an exception which is actually
+                                       // handled in jQuery.ajax (so no try/catch here)
+                                       xhr.send( ( s.hasContent && s.data ) || null );
+
+                                       // Listener
+                                       callback = function( _, isAbort ) {
+
+                                               var status,
+                                                       statusText,
+                                                       responseHeaders,
+                                                       responses,
+                                                       xml;
+
+                                               // Firefox throws exceptions when accessing properties
+                                               // of an xhr when a network error occured
+                                               // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+                                               try {
+
+                                                       // Was never called and is aborted or complete
+                                                       if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+                                                               // Only called once
+                                                               callback = undefined;
+
+                                                               // Do not keep as active anymore
+                                                               if ( handle ) {
+                                                                       xhr.onreadystatechange = jQuery.noop;
+                                                                       if ( xhrOnUnloadAbort ) {
+                                                                               delete xhrCallbacks[ handle ];
+                                                                       }
+                                                               }
+
+                                                               // If it's an abort
+                                                               if ( isAbort ) {
+                                                                       // Abort it manually if needed
+                                                                       if ( xhr.readyState !== 4 ) {
+                                                                               xhr.abort();
+                                                                       }
+                                                               } else {
+                                                                       status = xhr.status;
+                                                                       responseHeaders = xhr.getAllResponseHeaders();
+                                                                       responses = {};
+                                                                       xml = xhr.responseXML;
+
+                                                                       // Construct response list
+                                                                       if ( xml && xml.documentElement /* #4958 */ ) {
+                                                                               responses.xml = xml;
+                                                                       }
+                                                                       responses.text = xhr.responseText;
+
+                                                                       // Firefox throws an exception when accessing
+                                                                       // statusText for faulty cross-domain requests
+                                                                       try {
+                                                                               statusText = xhr.statusText;
+                                                                       } catch( e ) {
+                                                                               // We normalize with Webkit giving an empty statusText
+                                                                               statusText = "";
+                                                                       }
+
+                                                                       // Filter status for non standard behaviors
+
+                                                                       // If the request is local and we have data: assume a success
+                                                                       // (success with no data won't get notified, that's the best we
+                                                                       // can do given current implementations)
+                                                                       if ( !status && s.isLocal && !s.crossDomain ) {
+                                                                               status = responses.text ? 200 : 404;
+                                                                       // IE - #1450: sometimes returns 1223 when it should be 204
+                                                                       } else if ( status === 1223 ) {
+                                                                               status = 204;
+                                                                       }
+                                                               }
+                                                       }
+                                               } catch( firefoxAccessException ) {
+                                                       if ( !isAbort ) {
+                                                               complete( -1, firefoxAccessException );
+                                                       }
+                                               }
+
+                                               // Call complete if needed
+                                               if ( responses ) {
+                                                       complete( status, statusText, responses, responseHeaders );
+                                               }
+                                       };
+
+                                       // if we're in sync mode or it's in cache
+                                       // and has been retrieved directly (IE6 & IE7)
+                                       // we need to manually fire the callback
+                                       if ( !s.async || xhr.readyState === 4 ) {
+                                               callback();
+                                       } else {
+                                               handle = ++xhrId;
+                                               if ( xhrOnUnloadAbort ) {
+                                                       // Create the active xhrs callbacks list if needed
+                                                       // and attach the unload handler
+                                                       if ( !xhrCallbacks ) {
+                                                               xhrCallbacks = {};
+                                                               jQuery( window ).unload( xhrOnUnloadAbort );
+                                                       }
+                                                       // Add to list of active xhrs callbacks
+                                                       xhrCallbacks[ handle ] = callback;
+                                               }
+                                               xhr.onreadystatechange = callback;
+                                       }
+                               },
+
+                               abort: function() {
+                                       if ( callback ) {
+                                               callback(0,1);
+                                       }
+                               }
+                       };
+               }
+       });
+}
+
+
+
+
+var elemdisplay = {},
+       iframe, iframeDoc,
+       rfxtypes = /^(?:toggle|show|hide)$/,
+       rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+       timerId,
+       fxAttrs = [
+               // height animations
+               [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+               // width animations
+               [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+               // opacity animations
+               [ "opacity" ]
+       ],
+       fxNow,
+       requestAnimationFrame = window.webkitRequestAnimationFrame ||
+           window.mozRequestAnimationFrame ||
+           window.oRequestAnimationFrame;
+
+jQuery.fn.extend({
+       show: function( speed, easing, callback ) {
+               var elem, display;
+
+               if ( speed || speed === 0 ) {
+                       return this.animate( genFx("show", 3), speed, easing, callback);
+
+               } else {
+                       for ( var i = 0, j = this.length; i < j; i++ ) {
+                               elem = this[i];
+
+                               if ( elem.style ) {
+                                       display = elem.style.display;
+
+                                       // Reset the inline display of this element to learn if it is
+                                       // being hidden by cascaded rules or not
+                                       if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+                                               display = elem.style.display = "";
+                                       }
+
+                                       // Set elements which have been overridden with display: none
+                                       // in a stylesheet to whatever the default browser style is
+                                       // for such an element
+                                       if ( display === "" && jQuery.css( elem, "display" ) === "none" ) {
+                                               jQuery._data(elem, "olddisplay", defaultDisplay(elem.nodeName));
+                                       }
+                               }
+                       }
+
+                       // Set the display of most of the elements in a second loop
+                       // to avoid the constant reflow
+                       for ( i = 0; i < j; i++ ) {
+                               elem = this[i];
+
+                               if ( elem.style ) {
+                                       display = elem.style.display;
+
+                                       if ( display === "" || display === "none" ) {
+                                               elem.style.display = jQuery._data(elem, "olddisplay") || "";
+                                       }
+                               }
+                       }
+
+                       return this;
+               }
+       },
+
+       hide: function( speed, easing, callback ) {
+               if ( speed || speed === 0 ) {
+                       return this.animate( genFx("hide", 3), speed, easing, callback);
+
+               } else {
+                       for ( var i = 0, j = this.length; i < j; i++ ) {
+                               if ( this[i].style ) {
+                                       var display = jQuery.css( this[i], "display" );
+
+                                       if ( display !== "none" && !jQuery._data( this[i], "olddisplay" ) ) {
+                                               jQuery._data( this[i], "olddisplay", display );
+                                       }
+                               }
+                       }
+
+                       // Set the display of the elements in a second loop
+                       // to avoid the constant reflow
+                       for ( i = 0; i < j; i++ ) {
+                               if ( this[i].style ) {
+                                       this[i].style.display = "none";
+                               }
+                       }
+
+                       return this;
+               }
+       },
+
+       // Save the old toggle function
+       _toggle: jQuery.fn.toggle,
+
+       toggle: function( fn, fn2, callback ) {
+               var bool = typeof fn === "boolean";
+
+               if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+                       this._toggle.apply( this, arguments );
+
+               } else if ( fn == null || bool ) {
+                       this.each(function() {
+                               var state = bool ? fn : jQuery(this).is(":hidden");
+                               jQuery(this)[ state ? "show" : "hide" ]();
+                       });
+
+               } else {
+                       this.animate(genFx("toggle", 3), fn, fn2, callback);
+               }
+
+               return this;
+       },
+
+       fadeTo: function( speed, to, easing, callback ) {
+               return this.filter(":hidden").css("opacity", 0).show().end()
+                                       .animate({opacity: to}, speed, easing, callback);
+       },
+
+       animate: function( prop, speed, easing, callback ) {
+               var optall = jQuery.speed(speed, easing, callback);
+
+               if ( jQuery.isEmptyObject( prop ) ) {
+                       return this.each( optall.complete, [ false ] );
+               }
+
+               return this[ optall.queue === false ? "each" : "queue" ](function() {
+                       // XXX 'this' does not always have a nodeName when running the
+                       // test suite
+
+                       if ( optall.queue === false ) {
+                               jQuery._mark( this );
+                       }
+
+                       var opt = jQuery.extend({}, optall),
+                               isElement = this.nodeType === 1,
+                               hidden = isElement && jQuery(this).is(":hidden"),
+                               name, val, p,
+                               display, e,
+                               parts, start, end, unit;
+
+                       // will store per property easing and be used to determine when an animation is complete
+                       opt.animatedProperties = {};
+
+                       for ( p in prop ) {
+
+                               // property name normalization
+                               name = jQuery.camelCase( p );
+                               if ( p !== name ) {
+                                       prop[ name ] = prop[ p ];
+                                       delete prop[ p ];
+                               }
+
+                               val = prop[name];
+
+                               if ( val === "hide" && hidden || val === "show" && !hidden ) {
+                                       return opt.complete.call(this);
+                               }
+
+                               if ( isElement && ( name === "height" || name === "width" ) ) {
+                                       // Make sure that nothing sneaks out
+                                       // Record all 3 overflow attributes because IE does not
+                                       // change the overflow attribute when overflowX and
+                                       // overflowY are set to the same value
+                                       opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+                                       // Set display property to inline-block for height/width
+                                       // animations on inline elements that are having width/height
+                                       // animated
+                                       if ( jQuery.css( this, "display" ) === "inline" &&
+                                                       jQuery.css( this, "float" ) === "none" ) {
+                                               if ( !jQuery.support.inlineBlockNeedsLayout ) {
+                                                       this.style.display = "inline-block";
+
+                                               } else {
+                                                       display = defaultDisplay(this.nodeName);
+
+                                                       // inline-level elements accept inline-block;
+                                                       // block-level elements need to be inline with layout
+                                                       if ( display === "inline" ) {
+                                                               this.style.display = "inline-block";
+
+                                                       } else {
+                                                               this.style.display = "inline";
+                                                               this.style.zoom = 1;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+                               opt.animatedProperties[name] = jQuery.isArray( val ) ?
+                                       val[1]:
+                                       opt.specialEasing && opt.specialEasing[name] || opt.easing || 'swing';
+                       }
+
+                       if ( opt.overflow != null ) {
+                               this.style.overflow = "hidden";
+                       }
+
+                       for ( p in prop ) {
+                               e = new jQuery.fx( this, opt, p );
+
+                               val = prop[p];
+
+                               if ( rfxtypes.test(val) ) {
+                                       e[ val === "toggle" ? hidden ? "show" : "hide" : val ]();
+
+                               } else {
+                                       parts = rfxnum.exec(val);
+                                       start = e.cur();
+
+                                       if ( parts ) {
+                                               end = parseFloat( parts[2] );
+                                               unit = parts[3] || ( jQuery.cssNumber[ name ] ? "" : "px" );
+
+                                               // We need to compute starting value
+                                               if ( unit !== "px" ) {
+                                                       jQuery.style( this, p, (end || 1) + unit);
+                                                       start = ((end || 1) / e.cur()) * start;
+                                                       jQuery.style( this, p, start + unit);
+                                               }
+
+                                               // If a +=/-= token was provided, we're doing a relative animation
+                                               if ( parts[1] ) {
+                                                       end = ((parts[1] === "-=" ? -1 : 1) * end) + start;
+                                               }
+
+                                               e.custom( start, end, unit );
+
+                                       } else {
+                                               e.custom( start, val, "" );
+                                       }
+                               }
+                       }
+
+                       // For JS strict compliance
+                       return true;
+               });
+       },
+
+       stop: function( clearQueue, gotoEnd ) {
+               if ( clearQueue ) {
+                       this.queue([]);
+               }
+
+               this.each(function() {
+                       var timers = jQuery.timers,
+                               i = timers.length;
+                       // clear marker counters if we know they won't be
+                       if ( !gotoEnd ) {
+                               jQuery._unmark( true, this );
+                       }
+                       // go in reverse order so anything added to the queue during the loop is ignored
+                       while ( i-- ) {
+                               if ( timers[i].elem === this ) {
+                                       if (gotoEnd) {
+                                               // force the next step to be the last
+                                               timers[i](true);
+                                       }
+
+                                       timers.splice(i, 1);
+                               }
+                       }
+               });
+
+               // start the next in the queue if the last step wasn't forced
+               if ( !gotoEnd ) {
+                       this.dequeue();
+               }
+
+               return this;
+       }
+
+});
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+       setTimeout( clearFxNow, 0 );
+       return ( fxNow = jQuery.now() );
+}
+
+function clearFxNow() {
+       fxNow = undefined;
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, num ) {
+       var obj = {};
+
+       jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {
+               obj[ this ] = type;
+       });
+
+       return obj;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+       slideDown: genFx("show", 1),
+       slideUp: genFx("hide", 1),
+       slideToggle: genFx("toggle", 1),
+       fadeIn: { opacity: "show" },
+       fadeOut: { opacity: "hide" },
+       fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+       jQuery.fn[ name ] = function( speed, easing, callback ) {
+               return this.animate( props, speed, easing, callback );
+       };
+});
+
+jQuery.extend({
+       speed: function( speed, easing, fn ) {
+               var opt = speed && typeof speed === "object" ? jQuery.extend({}, speed) : {
+                       complete: fn || !fn && easing ||
+                               jQuery.isFunction( speed ) && speed,
+                       duration: speed,
+                       easing: fn && easing || easing && !jQuery.isFunction(easing) && easing
+               };
+
+               opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+                       opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;
+
+               // Queueing
+               opt.old = opt.complete;
+               opt.complete = function( noUnmark ) {
+                       if ( opt.queue !== false ) {
+                               jQuery.dequeue( this );
+                       } else if ( noUnmark !== false ) {
+                               jQuery._unmark( this );
+                       }
+
+                       if ( jQuery.isFunction( opt.old ) ) {
+                               opt.old.call( this );
+                       }
+               };
+
+               return opt;
+       },
+
+       easing: {
+               linear: function( p, n, firstNum, diff ) {
+                       return firstNum + diff * p;
+               },
+               swing: function( p, n, firstNum, diff ) {
+                       return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+               }
+       },
+
+       timers: [],
+
+       fx: function( elem, options, prop ) {
+               this.options = options;
+               this.elem = elem;
+               this.prop = prop;
+
+               options.orig = options.orig || {};
+       }
+
+});
+
+jQuery.fx.prototype = {
+       // Simple function for setting a style value
+       update: function() {
+               if ( this.options.step ) {
+                       this.options.step.call( this.elem, this.now, this );
+               }
+
+               (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+       },
+
+       // Get the current size
+       cur: function() {
+               if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {
+                       return this.elem[ this.prop ];
+               }
+
+               var parsed,
+                       r = jQuery.css( this.elem, this.prop );
+               // Empty strings, null, undefined and "auto" are converted to 0,
+               // complex values such as "rotate(1rad)" are returned as is,
+               // simple values such as "10px" are parsed to Float.
+               return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+       },
+
+       // Start an animation from one number to another
+       custom: function( from, to, unit ) {
+               var self = this,
+                       fx = jQuery.fx,
+                       raf;
+
+               this.startTime = fxNow || createFxNow();
+               this.start = from;
+               this.end = to;
+               this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
+               this.now = this.start;
+               this.pos = this.state = 0;
+
+               function t( gotoEnd ) {
+                       return self.step(gotoEnd);
+               }
+
+               t.elem = this.elem;
+
+               if ( t() && jQuery.timers.push(t) && !timerId ) {
+                       // Use requestAnimationFrame instead of setInterval if available
+                       if ( requestAnimationFrame ) {
+                               timerId = 1;
+                               raf = function() {
+                                       // When timerId gets set to null at any point, this stops
+                                       if ( timerId ) {
+                                               requestAnimationFrame( raf );
+                                               fx.tick();
+                                       }
+                               };
+                               requestAnimationFrame( raf );
+                       } else {
+                               timerId = setInterval( fx.tick, fx.interval );
+                       }
+               }
+       },
+
+       // Simple 'show' function
+       show: function() {
+               // Remember where we started, so that we can go back to it later
+               this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+               this.options.show = true;
+
+               // Begin the animation
+               // Make sure that we start at a small width/height to avoid any
+               // flash of content
+               this.custom(this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur());
+
+               // Start by showing the element
+               jQuery( this.elem ).show();
+       },
+
+       // Simple 'hide' function
+       hide: function() {
+               // Remember where we started, so that we can go back to it later
+               this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );
+               this.options.hide = true;
+
+               // Begin the animation
+               this.custom(this.cur(), 0);
+       },
+
+       // Each step of an animation
+       step: function( gotoEnd ) {
+               var t = fxNow || createFxNow(),
+                       done = true,
+                       elem = this.elem,
+                       options = this.options,
+                       i, n;
+
+               if ( gotoEnd || t >= options.duration + this.startTime ) {
+                       this.now = this.end;
+                       this.pos = this.state = 1;
+                       this.update();
+
+                       options.animatedProperties[ this.prop ] = true;
+
+                       for ( i in options.animatedProperties ) {
+                               if ( options.animatedProperties[i] !== true ) {
+                                       done = false;
+                               }
+                       }
+
+                       if ( done ) {
+                               // Reset the overflow
+                               if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+
+                                       jQuery.each( [ "", "X", "Y" ], function (index, value) {
+                                               elem.style[ "overflow" + value ] = options.overflow[index];
+                                       });
+                               }
+
+                               // Hide the element if the "hide" operation was done
+                               if ( options.hide ) {
+                                       jQuery(elem).hide();
+                               }
+
+                               // Reset the properties, if the item has been hidden or shown
+                               if ( options.hide || options.show ) {
+                                       for ( var p in options.animatedProperties ) {
+                                               jQuery.style( elem, p, options.orig[p] );
+                                       }
+                               }
+
+                               // Execute the complete function
+                               options.complete.call( elem );
+                       }
+
+                       return false;
+
+               } else {
+                       // classical easing cannot be used with an Infinity duration
+                       if ( options.duration == Infinity ) {
+                               this.now = t;
+                       } else {
+                               n = t - this.startTime;
+
+                               this.state = n / options.duration;
+                               // Perform the easing function, defaults to swing
+                               this.pos = jQuery.easing[options.animatedProperties[this.prop]](this.state, n, 0, 1, options.duration);
+                               this.now = this.start + ((this.end - this.start) * this.pos);
+                       }
+                       // Perform the next step of the animation
+                       this.update();
+               }
+
+               return true;
+       }
+};
+
+jQuery.extend( jQuery.fx, {
+       tick: function() {
+               var timers = jQuery.timers,
+                       i = timers.length;
+               while ( i-- ) {
+                       if ( !timers[i]() ) {
+                               timers.splice(i, 1);
+                       }
+               }
+
+               if ( !timers.length ) {
+                       jQuery.fx.stop();
+               }
+       },
+
+       interval: 13,
+
+       stop: function() {
+               clearInterval( timerId );
+               timerId = null;
+       },
+
+       speeds: {
+               slow: 600,
+               fast: 200,
+               // Default speed
+               _default: 400
+       },
+
+       step: {
+               opacity: function( fx ) {
+                       jQuery.style( fx.elem, "opacity", fx.now );
+               },
+
+               _default: function( fx ) {
+                       if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+                               fx.elem.style[ fx.prop ] = (fx.prop === "width" || fx.prop === "height" ? Math.max(0, fx.now) : fx.now) + fx.unit;
+                       } else {
+                               fx.elem[ fx.prop ] = fx.now;
+                       }
+               }
+       }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+       jQuery.expr.filters.animated = function( elem ) {
+               return jQuery.grep(jQuery.timers, function( fn ) {
+                       return elem === fn.elem;
+               }).length;
+       };
+}
+
+// Try to restore the default display value of an element
+function defaultDisplay( nodeName ) {
+
+       if ( !elemdisplay[ nodeName ] ) {
+
+               var elem = jQuery( "<" + nodeName + ">" ).appendTo( "body" ),
+                       display = elem.css( "display" );
+
+               elem.remove();
+
+               // If the simple way fails,
+               // get element's real default display by attaching it to a temp iframe
+               if ( display === "none" || display === "" ) {
+                       // No iframe to use yet, so create it
+                       if ( !iframe ) {
+                               iframe = document.createElement( "iframe" );
+                               iframe.frameBorder = iframe.width = iframe.height = 0;
+                       }
+
+                       document.body.appendChild( iframe );
+
+                       // Create a cacheable copy of the iframe document on first call.
+                       // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake html
+                       // document to it, Webkit & Firefox won't allow reusing the iframe document
+                       if ( !iframeDoc || !iframe.createElement ) {
+                               iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+                               iframeDoc.write( "<!doctype><html><body></body></html>" );
+                       }
+
+                       elem = iframeDoc.createElement( nodeName );
+
+                       iframeDoc.body.appendChild( elem );
+
+                       display = jQuery.css( elem, "display" );
+
+                       document.body.removeChild( iframe );
+               }
+
+               // Store the correct default display
+               elemdisplay[ nodeName ] = display;
+       }
+
+       return elemdisplay[ nodeName ];
+}
+
+
+
+
+var rtable = /^t(?:able|d|h)$/i,
+       rroot = /^(?:body|html)$/i;
+
+if ( "getBoundingClientRect" in document.documentElement ) {
+       jQuery.fn.offset = function( options ) {
+               var elem = this[0], box;
+
+               if ( options ) {
+                       return this.each(function( i ) {
+                               jQuery.offset.setOffset( this, options, i );
+                       });
+               }
+
+               if ( !elem || !elem.ownerDocument ) {
+                       return null;
+               }
+
+               if ( elem === elem.ownerDocument.body ) {
+                       return jQuery.offset.bodyOffset( elem );
+               }
+
+               try {
+                       box = elem.getBoundingClientRect();
+               } catch(e) {}
+
+               var doc = elem.ownerDocument,
+                       docElem = doc.documentElement;
+
+               // Make sure we're not dealing with a disconnected DOM node
+               if ( !box || !jQuery.contains( docElem, elem ) ) {
+                       return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+               }
+
+               var body = doc.body,
+                       win = getWindow(doc),
+                       clientTop  = docElem.clientTop  || body.clientTop  || 0,
+                       clientLeft = docElem.clientLeft || body.clientLeft || 0,
+                       scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,
+                       scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+                       top  = box.top  + scrollTop  - clientTop,
+                       left = box.left + scrollLeft - clientLeft;
+
+               return { top: top, left: left };
+       };
+
+} else {
+       jQuery.fn.offset = function( options ) {
+               var elem = this[0];
+
+               if ( options ) {
+                       return this.each(function( i ) {
+                               jQuery.offset.setOffset( this, options, i );
+                       });
+               }
+
+               if ( !elem || !elem.ownerDocument ) {
+                       return null;
+               }
+
+               if ( elem === elem.ownerDocument.body ) {
+                       return jQuery.offset.bodyOffset( elem );
+               }
+
+               jQuery.offset.initialize();
+
+               var computedStyle,
+                       offsetParent = elem.offsetParent,
+                       prevOffsetParent = elem,
+                       doc = elem.ownerDocument,
+                       docElem = doc.documentElement,
+                       body = doc.body,
+                       defaultView = doc.defaultView,
+                       prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+                       top = elem.offsetTop,
+                       left = elem.offsetLeft;
+
+               while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+                       if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+                               break;
+                       }
+
+                       computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+                       top  -= elem.scrollTop;
+                       left -= elem.scrollLeft;
+
+                       if ( elem === offsetParent ) {
+                               top  += elem.offsetTop;
+                               left += elem.offsetLeft;
+
+                               if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+                                       top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+                                       left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+                               }
+
+                               prevOffsetParent = offsetParent;
+                               offsetParent = elem.offsetParent;
+                       }
+
+                       if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+                               top  += parseFloat( computedStyle.borderTopWidth  ) || 0;
+                               left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+                       }
+
+                       prevComputedStyle = computedStyle;
+               }
+
+               if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+                       top  += body.offsetTop;
+                       left += body.offsetLeft;
+               }
+
+               if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === "fixed" ) {
+                       top  += Math.max( docElem.scrollTop, body.scrollTop );
+                       left += Math.max( docElem.scrollLeft, body.scrollLeft );
+               }
+
+               return { top: top, left: left };
+       };
+}
+
+jQuery.offset = {
+       initialize: function() {
+               var body = document.body, container = document.createElement("div"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, "marginTop") ) || 0,
+                       html = "<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
+
+               jQuery.extend( container.style, { position: "absolute", top: 0, left: 0, margin: 0, border: 0, width: "1px", height: "1px", visibility: "hidden" } );
+
+               container.innerHTML = html;
+               body.insertBefore( container, body.firstChild );
+               innerDiv = container.firstChild;
+               checkDiv = innerDiv.firstChild;
+               td = innerDiv.nextSibling.firstChild.firstChild;
+
+               this.doesNotAddBorder = (checkDiv.offsetTop !== 5);
+               this.doesAddBorderForTableAndCells = (td.offsetTop === 5);
+
+               checkDiv.style.position = "fixed";
+               checkDiv.style.top = "20px";
+
+               // safari subtracts parent border width here which is 5px
+               this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);
+               checkDiv.style.position = checkDiv.style.top = "";
+
+               innerDiv.style.overflow = "hidden";
+               innerDiv.style.position = "relative";
+
+               this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);
+
+               this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);
+
+               body.removeChild( container );
+               jQuery.offset.initialize = jQuery.noop;
+       },
+
+       bodyOffset: function( body ) {
+               var top = body.offsetTop,
+                       left = body.offsetLeft;
+
+               jQuery.offset.initialize();
+
+               if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {
+                       top  += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+                       left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+               }
+
+               return { top: top, left: left };
+       },
+
+       setOffset: function( elem, options, i ) {
+               var position = jQuery.css( elem, "position" );
+
+               // set position first, in-case top/left are set even on static elem
+               if ( position === "static" ) {
+                       elem.style.position = "relative";
+               }
+
+               var curElem = jQuery( elem ),
+                       curOffset = curElem.offset(),
+                       curCSSTop = jQuery.css( elem, "top" ),
+                       curCSSLeft = jQuery.css( elem, "left" ),
+                       calculatePosition = (position === "absolute" || position === "fixed") && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+                       props = {}, curPosition = {}, curTop, curLeft;
+
+               // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+               if ( calculatePosition ) {
+                       curPosition = curElem.position();
+                       curTop = curPosition.top;
+                       curLeft = curPosition.left;
+               } else {
+                       curTop = parseFloat( curCSSTop ) || 0;
+                       curLeft = parseFloat( curCSSLeft ) || 0;
+               }
+
+               if ( jQuery.isFunction( options ) ) {
+                       options = options.call( elem, i, curOffset );
+               }
+
+               if (options.top != null) {
+                       props.top = (options.top - curOffset.top) + curTop;
+               }
+               if (options.left != null) {
+                       props.left = (options.left - curOffset.left) + curLeft;
+               }
+
+               if ( "using" in options ) {
+                       options.using.call( elem, props );
+               } else {
+                       curElem.css( props );
+               }
+       }
+};
+
+
+jQuery.fn.extend({
+       position: function() {
+               if ( !this[0] ) {
+                       return null;
+               }
+
+               var elem = this[0],
+
+               // Get *real* offsetParent
+               offsetParent = this.offsetParent(),
+
+               // Get correct offsets
+               offset       = this.offset(),
+               parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+               // Subtract element margins
+               // note: when an element has margin: auto the offsetLeft and marginLeft
+               // are the same in Safari causing offset.left to incorrectly be 0
+               offset.top  -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+               offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+               // Add offsetParent borders
+               parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+               parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+               // Subtract the two offsets
+               return {
+                       top:  offset.top  - parentOffset.top,
+                       left: offset.left - parentOffset.left
+               };
+       },
+
+       offsetParent: function() {
+               return this.map(function() {
+                       var offsetParent = this.offsetParent || document.body;
+                       while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+                               offsetParent = offsetParent.offsetParent;
+                       }
+                       return offsetParent;
+               });
+       }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ["Left", "Top"], function( i, name ) {
+       var method = "scroll" + name;
+
+       jQuery.fn[ method ] = function( val ) {
+               var elem, win;
+
+               if ( val === undefined ) {
+                       elem = this[ 0 ];
+
+                       if ( !elem ) {
+                               return null;
+                       }
+
+                       win = getWindow( elem );
+
+                       // Return the scroll offset
+                       return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] :
+                               jQuery.support.boxModel && win.document.documentElement[ method ] ||
+                                       win.document.body[ method ] :
+                               elem[ method ];
+               }
+
+               // Set the scroll offset
+               return this.each(function() {
+                       win = getWindow( this );
+
+                       if ( win ) {
+                               win.scrollTo(
+                                       !i ? val : jQuery( win ).scrollLeft(),
+                                        i ? val : jQuery( win ).scrollTop()
+                               );
+
+                       } else {
+                               this[ method ] = val;
+                       }
+               });
+       };
+});
+
+function getWindow( elem ) {
+       return jQuery.isWindow( elem ) ?
+               elem :
+               elem.nodeType === 9 ?
+                       elem.defaultView || elem.parentWindow :
+                       false;
+}
+
+
+
+
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function( i, name ) {
+
+       var type = name.toLowerCase();
+
+       // innerHeight and innerWidth
+       jQuery.fn["inner" + name] = function() {
+               return this[0] ?
+                       parseFloat( jQuery.css( this[0], type, "padding" ) ) :
+                       null;
+       };
+
+       // outerHeight and outerWidth
+       jQuery.fn["outer" + name] = function( margin ) {
+               return this[0] ?
+                       parseFloat( jQuery.css( this[0], type, margin ? "margin" : "border" ) ) :
+                       null;
+       };
+
+       jQuery.fn[ type ] = function( size ) {
+               // Get window width or height
+               var elem = this[0];
+               if ( !elem ) {
+                       return size == null ? null : this;
+               }
+
+               if ( jQuery.isFunction( size ) ) {
+                       return this.each(function( i ) {
+                               var self = jQuery( this );
+                               self[ type ]( size.call( this, i, self[ type ]() ) );
+                       });
+               }
+
+               if ( jQuery.isWindow( elem ) ) {
+                       // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+                       // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+                       var docElemProp = elem.document.documentElement[ "client" + name ];
+                       return elem.document.compatMode === "CSS1Compat" && docElemProp ||
+                               elem.document.body[ "client" + name ] || docElemProp;
+
+               // Get document width or height
+               } else if ( elem.nodeType === 9 ) {
+                       // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+                       return Math.max(
+                               elem.documentElement["client" + name],
+                               elem.body["scroll" + name], elem.documentElement["scroll" + name],
+                               elem.body["offset" + name], elem.documentElement["offset" + name]
+                       );
+
+               // Get or set width or height on the element
+               } else if ( size === undefined ) {
+                       var orig = jQuery.css( elem, type ),
+                               ret = parseFloat( orig );
+
+                       return jQuery.isNaN( ret ) ? orig : ret;
+
+               // Set the width or height on the element (default to pixels if value is unitless)
+               } else {
+                       return this.css( type, typeof size === "string" ? size : size + "px" );
+               }
+       };
+
+});
+
+
+window.jQuery = window.$ = jQuery;
+})(window);
diff --git a/www/plugins/crayons/js/jquery.px.js b/www/plugins/crayons/js/jquery.px.js
new file mode 100644 (file)
index 0000000..e6c195d
--- /dev/null
@@ -0,0 +1,18 @@
+// Ce plugin permet de recuperer css(fontSize) en px meme sous MSIE
+(function($){
+       $.fn.px = function(prop) {
+               var val;
+               if($.browser.msie) {
+                       $('<span><\/span>')
+                       .css({display: 'block', width: '1em'})
+                       .appendTo(this[0])
+                       .each(function(){
+                               val = parseInt($(this).width()) + 'px';
+                       })
+                       .remove();
+               } else {
+                       val = this.css(prop);
+               }
+               return val;
+       };
+})(jQuery);
diff --git a/www/plugins/crayons/js/resizehandle.js b/www/plugins/crayons/js/resizehandle.js
new file mode 100644 (file)
index 0000000..686647f
--- /dev/null
@@ -0,0 +1,32 @@
+(function($){
+/*
+ * resizehandle.js (c) Fil 2007-2011, plugin pour jQuery
+ * @ http://www.jquery.info/spip.php?article44
+ * Distribue sous licence GNU/LGPL et MIT
+ */
+$.fn.resizehandle = function() {
+  return this.each(function() {
+    var me = $(this);
+    me.after(
+      $('<div class="resizehandle"></div>')
+      .css({height:'16px',width:Math.max(me.width()-4,10)}) // bug MSIE si 100%
+      .bind('mousedown', function(e) {
+        var h = me.height();
+        var y = e.clientY;
+        var moveHandler = function(e) {
+          me
+          .height(Math.max(20, e.clientY + h - y));
+        };
+        var upHandler = function(e) {
+          $('html')
+          .unbind('mousemove',moveHandler)
+          .unbind('mouseup',upHandler);
+        };
+        $('html')
+        .bind('mousemove', moveHandler)
+        .bind('mouseup', upHandler);
+      })
+    );
+  });
+};
+})(jQuery);
diff --git a/www/plugins/crayons/js/uploader.js.html b/www/plugins/crayons/js/uploader.js.html
new file mode 100644 (file)
index 0000000..5bcca93
--- /dev/null
@@ -0,0 +1,70 @@
+<script>\r
+// activer l'uploader\r
+(function($) {\r
+       var url = '[(#VAL{crayons_upload}|generer_url_action{id=#ENV{id_article}&type=article, true, true})]';\r
+\r
+       $('textarea.crayon-active,#uploader#ENV{id_article}')\r
+       .html5Uploader({\r
+               name: 'upss',\r
+               postUrl: url,\r
+               onClientLoadStart: function(e, file) {\r
+                       file.mark = 'up'+Math.ceil(10000000*Math.random());\r
+                       $('<li>lecture de '+file.name+'...</li>')\r
+                       .addClass('loading')\r
+                       .attr('id', file.mark)\r
+                       .prependTo('#uploader_liste')\r
+                       ;\r
+               },\r
+               onClientLoad: function(e, file) {\r
+                       $('#uploader#ENV{id_article}')\r
+                       .removeClass('hover');\r
+               },\r
+               onServerProgress: function(e,file) {\r
+                       var percent = '';\r
+                       if(e.lengthComputable)\r
+                               percent = ''+Math.ceil(100*e.loaded/e.total)+'%';\r
+                       $('#'+file.mark)\r
+                       .html('envoi de '+file.name+' vers le serveur... '+percent);\r
+               },\r
+               onServerReadyStateChange: function(e,file) {\r
+                       if (e.target.responseText) {\r
+                               // traiter la reponse du serveur\r
+                               // todo: la passer en JSON si on veut\r
+                               $('#'+file.mark)\r
+                               .html(e.target.responseText);\r
+                       }\r
+               },\r
+               onServerLoad: function(e,file) {\r
+                       $('#'+file.mark)\r
+                       .removeClass('loading')\r
+                       .addClass('ok');\r
+               },\r
+       })\r
+       .bind("dragenter dragover", function() {\r
+               $(this).addClass('hover');\r
+               $('#uploader#ENV{id_article}')\r
+               .removeClass('ferme');\r
+       })\r
+       .bind("dragleave", function() {\r
+               $(this).removeClass('hover');\r
+               $('#uploader#ENV{id_article}')\r
+               .addClass('ferme');\r
+       })\r
+       .bind("drop", function(e) {\r
+               $(this)\r
+               .removeClass('hover');\r
+               $('#uploader#ENV{id_article}')\r
+               .removeClass('ferme');\r
+       })\r
+       .addClass('uploader')\r
+       ;\r
+       $('#uploader#ENV{id_article}')\r
+       .hover(function() {\r
+               $(this).removeClass('ferme');\r
+       }, function() {\r
+               $(this).addClass('ferme');\r
+       });\r
+\r
+})(cQuery);\r
+\r
+</script>
\ No newline at end of file
diff --git a/www/plugins/crayons/lang/crayons.xml b/www/plugins/crayons/lang/crayons.xml
new file mode 100644 (file)
index 0000000..c3e0647
--- /dev/null
@@ -0,0 +1,38 @@
+<traduction module="crayons" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/crayons/lang/" reference="fr">
+       <langue code="ast" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=ast">
+               <traducteur nom="Xuacu" lien="http://trad.spip.net/auteur/xuacu" />
+       </langue>
+       <langue code="ca" />
+       <langue code="de" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=de">
+               <traducteur nom="klaus++" lien="http://trad.spip.net/auteur/klaus" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+               <traducteur nom="Paolo" lien="http://trad.spip.net/auteur/paolo" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=es">
+               <traducteur nom="dani" lien="http://trad.spip.net/auteur/dani" />
+               <traducteur nom="severo" lien="http://trad.spip.net/auteur/severo" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="fr_tu" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=fr_tu">
+               <traducteur nom="beatnick" lien="http://trad.spip.net/auteur/beatnick" />
+       </langue>
+       <langue code="it" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=it">
+               <traducteur nom="Fil" lien="http://trad.spip.net/auteur/fil" />
+       </langue>
+       <langue code="nl" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=nl">
+               <traducteur nom="mpossoz" lien="http://trad.spip.net/auteur/mpossoz" />
+               <traducteur nom="Suske" lien="http://trad.spip.net/auteur/suske" />
+       </langue>
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/crayons?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+       <langue code="zh" />
+</traduction>
diff --git a/www/plugins/crayons/lang/crayons_ar.php b/www/plugins/crayons/lang/crayons_ar.php
new file mode 100644 (file)
index 0000000..59b37dc
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'إلغاء',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'عدّل سابقاً',
+       'donnees_mal_formatees' => 'تنسيق بيانات غير سليم',
+
+       // E
+       'editer' => 'تحرير',
+       'editer_@type@_@id@' => 'تحرير @type@ @id@ بالكامل',
+       'editer_tout' => 'تحرير الكل',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'عدّل في مكان آخر',
+
+       // N
+       'non_autorise' => 'غير مسموح',
+       'non_implemente' => 'غير مدعوم',
+
+       // P
+       'pas_de_modification' => 'لم تدخل اي تعديلات',
+       'pas_de_valeur' => 'لا توجد قيمة',
+
+       // S
+       'sauvegarder' => 'حفظ التعديلات؟',
+       'svp_copier_coller' => 'عذراً، قم بنسخ التعديلات ولصقها وإعادة المحاولة',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'الرجاء الانتظار...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_ast.php b/www/plugins/crayons/lang/crayons_ast.php
new file mode 100644 (file)
index 0000000..ce512a9
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=ast
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Hai otru complementu que torga l\'usu del portaplumes nel espaciu públicu.',
+       'annuler' => 'Anular',
+
+       // B
+       'bouton_supprimer' => 'Desaniciar',
+
+       // D
+       'deja_modifie' => 'Ya ta modificao',
+       'donnees_mal_formatees' => 'Datos mal formateaos',
+
+       // E
+       'editer' => 'Editar',
+       'editer_@type@_@id@' => 'Editar @type@ @id@ dafechu',
+       'editer_tout' => 'Editalo ensembre',
+       'effets' => 'Efeutos',
+       'explication_exec_autorise' => 'Páxines que se permite camudar
+  (?exec=...) : (, pa xebrar los exec).', # MODIF
+       'explication_introduction_article' => 'La introducción d\'un artículu amuesa la descripción del artículu, sinón amuesa los sos primeros 600 caráuteres (la entrada siguía pol testu).',
+       'explication_reduire_logo' => 'Amenorgar el logo si pasa del
+  tamañu máximu indicáu en pixels. Exemplu: 100. (0 = enxamás)', # MODIF
+
+       // I
+       'info_experimental' => 'Expérimental', # NEW
+
+       // L
+       'label_activer_barre_typo' => '¿Activar la barra tipográfica nos llápices?',
+       'label_activer_crayons_prive' => 'Activar los llápices pa la parte privada.',
+       'label_barre_typo' => 'Barra tipográfica',
+       'label_clickhide' => 'Calcar una vegada per fuera anubre los llápices',
+       'label_effets' => 'Esbilla de los efeutos',
+       'label_espaceprive' => '¿Llápices nel espaciu priváu?',
+       'label_exec_autorise' => 'Páxines autorizaes',
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Escoyer un mensaxe',
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si nun hai cambeos',
+       'label_reduire_logo' => 'Amenorgar los logos',
+       'label_upload_document' => 'Autoriser l\'ajout de documents par glisser/déposer sur le crayon article.texte', # NEW
+       'label_yellow_fade' => 'Dilir',
+       'legend_controleur_hyperlien' => 'Hiperenllaz',
+       'legend_controleur_logo' => 'Escoyer un logo:',
+       'legend_controleur_logo_remplacer' => 'Trocar esti logo',
+       'legend_controleur_qui' => '¿Quién?',
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_documents' => 'Upload de documents', # NEW
+       'legend_editer_prive' => 'Editar l\'espaciu priváu (esperimental)',
+       'legend_introduction_article' => 'Testu introductoriu del artículu',
+
+       // M
+       'message_image_obligatoire' => 'Hai qu\'escoyer una imaxe',
+       'messages' => 'Mensaxes',
+       'modifie_par_ailleurs' => 'Modificao n\'otru llau',
+
+       // N
+       'non_autorise' => 'Non autorizao',
+       'non_implemente' => 'Ensin implementar',
+
+       // P
+       'pas_de_modification' => 'Ensin modificación',
+       'pas_de_valeur' => 'Ensin valor',
+
+       // S
+       'sauvegarder' => '¿Guardar les modificaciones?',
+       'svp_copier_coller' => 'Sentimoslo, copia/pega los cambéos y torna a entamar',
+
+       // T
+       'titre_config_crayons' => 'Configurar los llápices',
+       'titre_crayons' => 'Llápices',
+
+       // U
+       'update_impossible' => 'Falló l\'anovación.',
+
+       // V
+       'veuillez_patienter' => 'Un momentu...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_br.php b/www/plugins/crayons/lang/crayons_br.php
new file mode 100644 (file)
index 0000000..1d5b6b7
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Nullañ',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Bet kemmet c\'hoazh',
+       'donnees_mal_formatees' => 'Stumm fall gant an titouroù',
+
+       // E
+       'editer' => 'Embann',
+       'editer_@type@_@id@' => 'Embann @type@ @id@ a-bezh',
+       'editer_tout' => 'Embann pep tra',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Kemmet e mod all',
+
+       // N
+       'non_autorise' => 'Ket aotreet',
+       'non_implemente' => 'Ket lakaet e-barzh',
+
+       // P
+       'pas_de_modification' => 'Kemm ebet',
+       'pas_de_valeur' => 'Talvoud ebet',
+
+       // S
+       'sauvegarder' => 'Saveteiñ ar c\'hemmoù ?',
+       'svp_copier_coller' => 'Digarez, eilit/pegit ho kemmoù, ha klaskit en-dro',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Gortozit...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_ca.php b/www/plugins/crayons/lang/crayons_ca.php
new file mode 100644 (file)
index 0000000..85abbe3
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=ca
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un altre connector impedeix l\'ús del portaplomes a l\'espai públic. ',
+       'annuler' => 'Anul·lar',
+
+       // B
+       'bouton_supprimer' => 'Suprimir',
+
+       // D
+       'deja_modifie' => 'Ja modificat',
+       'donnees_mal_formatees' => 'Dades mal formatades',
+
+       // E
+       'editer' => 'Editar',
+       'editer_@type@_@id@' => 'Editar @type@ @id@ de cap a peus',
+       'editer_tout' => 'Editar tot',
+       'effets' => 'Efectes',
+       'explication_exec_autorise' => 'Pàgines autoritzades a ser modificades
+  (?exec=...) : (, per separar les exec).', # MODIF
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Reduir el logotip si sobrepassa la mida màxima indicada en píxels. Exemple: 100. (0 = mai)', # MODIF
+
+       // I
+       'info_experimental' => 'Expérimental', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activar la barra tipogràfica a els llapis?',
+       'label_activer_crayons_prive' => 'Activar llapis a la part privada.',
+       'label_barre_typo' => 'Barra tipogràfica',
+       'label_clickhide' => 'Fent un clic a l\'exterior s\'amaga els llapis',
+       'label_effets' => 'Tria dels efectes',
+       'label_espaceprive' => 'Els llapis a la part privada?',
+       'label_exec_autorise' => 'Pàgines autoritzades',
+       'label_filet' => 'Filet',
+       'label_message' => 'Obtenir un missatge',
+       'label_msg_abandon' => 'Sobre l\'abandonament',
+       'label_msg_no_change' => 'Si no hi ha canvi',
+       'label_reduire_logo' => 'Reduir els logotips',
+       'label_upload_document' => 'Autoriser l\'ajout de documents par glisser/déposer sur le crayon article.texte', # NEW
+       'label_yellow_fade' => 'Sense interès',
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Escollir un logotip:',
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Escollir una vinyeta:',
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_documents' => 'Upload de documents', # NEW
+       'legend_editer_prive' => 'Editar l\'espai privat (experimental)',
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Cal escollir una imatge',
+       'messages' => 'Missatges',
+       'modifie_par_ailleurs' => 'Modificat per altres raons',
+
+       // N
+       'non_autorise' => 'No autoritzat',
+       'non_implemente' => 'No implementat',
+
+       // P
+       'pas_de_modification' => 'Cap modificació',
+       'pas_de_valeur' => 'Cap valor',
+
+       // S
+       'sauvegarder' => 'Salvaguardar les modificacions?',
+       'svp_copier_coller' => 'Em sap greu, copieu/enganxeu els vostres canvis i torneu a començar',
+
+       // T
+       'titre_config_crayons' => 'Configurar els llapis',
+       'titre_crayons' => 'Llapis',
+
+       // U
+       'update_impossible' => 'L\'actualització ha fracassat',
+
+       // V
+       'veuillez_patienter' => 'Si us plau, espereu un moment...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_de.php b/www/plugins/crayons/lang/crayons_de.php
new file mode 100644 (file)
index 0000000..af1c1d9
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Ein anderes Plugin verhindert den Einsatz des Federhalters im öffentlichen Bereich.',
+       'annuler' => 'Abbrechen',
+
+       // B
+       'bouton_supprimer' => 'Löschen',
+
+       // D
+       'deja_modifie' => 'Bereits geändert',
+       'donnees_mal_formatees' => 'Datenformat unrichtig',
+
+       // E
+       'editer' => 'Bearbeiten',
+       'editer_@type@_@id@' => '@type@ @id@ als Ganzes bearbeiten',
+       'editer_tout' => 'Alles bearbeiten',
+       'effets' => 'Effekte',
+       'explication_exec_autorise' => 'Zur Bearbeitung zugelassene Seiten
+  (?exec=...) : (exec-Skripte mit Komma trennen).',
+       'explication_introduction_article' => 'Die Einleitung eines Artikels zeigt das Feld "Beschreibung" an. Sollte es leer sein, werden die ersten  600 Zeichen des Artikels aus den Feldern "Kopf" und "Text" angezeigt.',
+       'explication_reduire_logo' => 'Logo verkleinern wenn es größer als x Pixel ist.
+Beispiel: 100. (0 = niemals)',
+
+       // I
+       'info_experimental' => 'Expérimentell',
+
+       // L
+       'label_activer_barre_typo' => 'Funktionsleisten f&uuml;r die Stifte aktivieren?',
+       'label_activer_crayons_prive' => 'Stifte im Redaktionssystem aktivieren',
+       'label_barre_typo' => 'Funktonsleiste',
+       'label_clickhide' => 'Ein Klick au&szlig;erhalb versteckt den Stift',
+       'label_effets' => 'Effekte w&auml;hlen',
+       'label_espaceprive' => 'Stifte im Redaktionssystem verwenden?',
+       'label_exec_autorise' => 'Erlaubte Seiten',
+       'label_filet' => 'Netz',
+       'label_message' => 'Nachricht erhalten',
+       'label_msg_abandon' => 'bei Abbruch',
+       'label_msg_no_change' => 'wenn keine &Auml;nderung',
+       'label_reduire_logo' => 'Logos verkleinern',
+       'label_upload_document' => 'Hinzufügen von Dokumenten durch Ziehen/Ablegen auf den Stift article.texte erlauben.',
+       'label_yellow_fade' => 'Ausblenden',
+       'legend_controleur_hyperlien' => 'Hyperlink',
+       'legend_controleur_logo' => 'Logoe wählen:',
+       'legend_controleur_logo_remplacer' => 'Dieses Logo ersetzen',
+       'legend_controleur_qui' => 'Wer?',
+       'legend_controleur_vignette' => 'Thumbnail wählen:',
+       'legend_controleur_vignette_remplacer' => 'Dieses Miniaturbild ersetzen',
+       'legend_documents' => 'Dokumente hochladen',
+       'legend_editer_prive' => 'Stifte im Redaktionssystem (experimentell)',
+       'legend_introduction_article' => 'Einleitender Text des Artikels',
+
+       // M
+       'message_image_obligatoire' => 'Es muß ein Bild gewählt werden.',
+       'messages' => 'Nachrichten',
+       'modifie_par_ailleurs' => 'Auf anderem Weg geändert',
+
+       // N
+       'non_autorise' => 'Nicht erlaubt',
+       'non_implemente' => 'Funktion nicht vorhanden',
+
+       // P
+       'pas_de_modification' => 'Keine Änderung',
+       'pas_de_valeur' => 'Kein Wert',
+
+       // S
+       'sauvegarder' => 'Änderungen speichern?',
+       'svp_copier_coller' => 'Pardon, bitte sichern Sie ihre Änderungen mit kopieren/einfügen und beginnen Sie von vorne.',
+
+       // T
+       'titre_config_crayons' => 'Stifte: Konfiguration ',
+       'titre_crayons' => 'Stifte',
+
+       // U
+       'update_impossible' => 'Das Update ist fehlgeschlagen.',
+
+       // V
+       'veuillez_patienter' => 'Bitte etwas Geduld...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_en.php b/www/plugins/crayons/lang/crayons_en.php
new file mode 100644 (file)
index 0000000..e5de44f
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Another plugin is preventing the use of  porte-plume on the public site.',
+       'annuler' => 'Cancel',
+
+       // B
+       'bouton_supprimer' => 'Delete',
+
+       // D
+       'deja_modifie' => 'Already modified',
+       'donnees_mal_formatees' => 'Invalid request format',
+
+       // E
+       'editer' => 'Edit',
+       'editer_@type@_@id@' => 'Edit the whole @type@ @id@',
+       'editer_tout' => 'Edit as a whole',
+       'effets' => 'Effects',
+       'explication_exec_autorise' => 'Pages which are authorised fro changes
+  (?exec=...) : (, to separate several pages- * for all).',
+       'explication_introduction_article' => 'The introduction for an article displays the description of the article if there is one, otherwise it displays the first 600 characters (of the standfirst and text).',
+       'explication_reduire_logo' => 'Reduce the logo size if it exceeds
+  the maximum size (in pixels). Example: 100 (0 = never).',
+
+       // I
+       'info_experimental' => 'Experimental',
+
+       // L
+       'label_activer_barre_typo' => 'Activate the typographical bar for "Pencils"?',
+       'label_activer_crayons_prive' => 'Activate "Pencils" for the editing area.',
+       'label_barre_typo' => 'Typographical bar',
+       'label_clickhide' => 'A click outside the area closes the pencils',
+       'label_effets' => 'Choice of effects',
+       'label_espaceprive' => 'Use "Pencils" in the editing area?',
+       'label_exec_autorise' => 'Pages authorised',
+       'label_filet' => 'Line',
+       'label_message' => 'Show a message',
+       'label_msg_abandon' => 'On cancelling',
+       'label_msg_no_change' => 'If no change made',
+       'label_reduire_logo' => 'Reduce logos',
+       'label_upload_document' => 'Allow adding documents by drag and drop on the pencil article.texte',
+       'label_yellow_fade' => 'Fade',
+       'legend_controleur_hyperlien' => 'Hyperlink',
+       'legend_controleur_logo' => 'Choose a logo:',
+       'legend_controleur_logo_remplacer' => 'Replace this logo',
+       'legend_controleur_qui' => 'Who?',
+       'legend_controleur_vignette' => 'Choose a thumbnail:',
+       'legend_controleur_vignette_remplacer' => 'Replace this thumbnail',
+       'legend_documents' => 'Upload documents',
+       'legend_editer_prive' => 'Use in editing area (experimental)',
+       'legend_introduction_article' => 'Introductory text for the article',
+
+       // M
+       'message_image_obligatoire' => 'You need to choose an image',
+       'messages' => 'Messages',
+       'modifie_par_ailleurs' => 'Was modified elsewhere in the meantime',
+
+       // N
+       'non_autorise' => 'Not allowed',
+       'non_implemente' => 'Not implemented',
+
+       // P
+       'pas_de_modification' => 'No change',
+       'pas_de_valeur' => 'No value for this id',
+
+       // S
+       'sauvegarder' => 'Save changes?',
+       'svp_copier_coller' => 'Sorry, copy/paste your changes and retry',
+
+       // T
+       'titre_config_crayons' => 'Configure "Pencils"',
+       'titre_crayons' => 'Pencils',
+
+       // U
+       'update_impossible' => 'The update did not succeed.',
+
+       // V
+       'veuillez_patienter' => 'Searching ...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_eo.php b/www/plugins/crayons/lang/crayons_eo.php
new file mode 100644 (file)
index 0000000..9c16428
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Nuligi',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Jam modifita',
+       'donnees_mal_formatees' => 'Datenoj malbone formatitaj',
+
+       // E
+       'editer' => 'Redakti',
+       'editer_@type@_@id@' => 'Tute redakti @type@ @id@ ',
+       'editer_tout' => 'Ĉion redakti',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Modifita dumtempe',
+
+       // N
+       'non_autorise' => 'Ne permesate',
+       'non_implemente' => 'Ne prirealigita',
+
+       // P
+       'pas_de_modification' => 'Neniu modifo',
+       'pas_de_valeur' => 'Neniu valoro',
+
+       // S
+       'sauvegarder' => 'Ĉu konservi modifojn?',
+       'svp_copier_coller' => 'Ni pardonpetas, kopigluu viajn ŝanĝojn kaj rekomencu',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Bonvolu atendi...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_es.php b/www/plugins/crayons/lang/crayons_es.php
new file mode 100644 (file)
index 0000000..43a7da2
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Otro plugin impide el uso del porta-plumas en el espacio público.',
+       'annuler' => 'Cancelar',
+
+       // B
+       'bouton_supprimer' => 'Suprimir',
+
+       // D
+       'deja_modifie' => 'Ya modificado',
+       'donnees_mal_formatees' => 'Datos mal formateados',
+
+       // E
+       'editer' => 'Editar',
+       'editer_@type@_@id@' => 'Editar @type@ @id@ entero',
+       'editer_tout' => 'Editar todo',
+       'effets' => 'Efectos',
+       'explication_exec_autorise' => 'Páginas cuya modificación es permitida
+  (?exec=...): (, para separar los exec - * para todas).',
+       'explication_introduction_article' => 'La introducción de un artículo enseña la descripción del artículo, o los primeros 600 carácteres (epígrafe y luego texto).',
+       'explication_reduire_logo' => 'Reducir el logotipo si va mas allá
+  del tamaño indicado en píxeles. Ejemplo: 100. (0 = nunca)',
+
+       // I
+       'info_experimental' => 'Experimental',
+
+       // L
+       'label_activer_barre_typo' => '¿Activar la barra tipográfica en los lápices?',
+       'label_activer_crayons_prive' => 'Activar los lápices en el espacio privado.',
+       'label_barre_typo' => 'Barra tipográfica',
+       'label_clickhide' => 'Un clic afuera esconde los lápices',
+       'label_effets' => 'Elegir los efectos',
+       'label_espaceprive' => '¿Lápices en el espacio privado?',
+       'label_exec_autorise' => 'Páginas permitidas',
+       'label_filet' => 'Filete',
+       'label_message' => 'Obtener un mensaje',
+       'label_msg_abandon' => 'Cuando se abandona',
+       'label_msg_no_change' => 'Si no hay cambios',
+       'label_reduire_logo' => 'Reducir el tamaño de los logotipos',
+       'label_upload_document' => 'Autorizar que se agreguen documentos por arrastrar/depositar ("drag & drop") sobre el lápiz artículo.texto (article.texte)',
+       'label_yellow_fade' => 'Fundido',
+       'legend_controleur_hyperlien' => 'Enlace hipertexto',
+       'legend_controleur_logo' => 'Elegir un logotipo:',
+       'legend_controleur_logo_remplacer' => 'Reemplazar este logotipo',
+       'legend_controleur_qui' => '¿Quién?',
+       'legend_controleur_vignette' => 'Escoger una viñeta:',
+       'legend_controleur_vignette_remplacer' => 'Reemplazar esta viñeta',
+       'legend_documents' => 'Subir documentos',
+       'legend_editer_prive' => 'Edición en el espacio privado (experimental)',
+       'legend_introduction_article' => 'Texto introductivo del artículo',
+
+       // M
+       'message_image_obligatoire' => 'Hay que escoger una imagen',
+       'messages' => 'Mensajes',
+       'modifie_par_ailleurs' => 'Modificado por otro lado',
+
+       // N
+       'non_autorise' => 'No autorizado',
+       'non_implemente' => 'No implementado',
+
+       // P
+       'pas_de_modification' => 'No hay modificaciones',
+       'pas_de_valeur' => 'No hay valor',
+
+       // S
+       'sauvegarder' => '¿Guardar las modificaciones?',
+       'svp_copier_coller' => 'Perdon, copia/pega tus cambios y vuelve a empezar',
+
+       // T
+       'titre_config_crayons' => 'Configuración de los lápices',
+       'titre_crayons' => 'Lápices',
+
+       // U
+       'update_impossible' => 'La actualización fracasó.',
+
+       // V
+       'veuillez_patienter' => 'Favor esperar...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_eu.php b/www/plugins/crayons/lang/crayons_eu.php
new file mode 100644 (file)
index 0000000..00a131a
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Ezeztatu',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Jadanik aldatua',
+       'donnees_mal_formatees' => 'Gaizki formatutako datuak',
+
+       // E
+       'editer' => 'Editatu',
+       'editer_@type@_@id@' => '@type@ @id@ osoki editatu',
+       'editer_tout' => 'Dena editatu',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Bestalde aldatua',
+
+       // N
+       'non_autorise' => 'Ez baimendua',
+       'non_implemente' => 'Ez inpliment atua',
+
+       // P
+       'pas_de_modification' => 'Aldaketarik ez',
+       'pas_de_valeur' => 'Balorerik ez',
+
+       // S
+       'sauvegarder' => 'Aldaketak grabatu ?',
+       'svp_copier_coller' => 'Désolé, copiez/collez vos changements et recommencez', # NEW
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Veuillez patienter...' # NEW
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_fa.php b/www/plugins/crayons/lang/crayons_fa.php
new file mode 100644 (file)
index 0000000..78c5e17
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'يك پلاگين ديگر مانع استفاده از چوب قلم در سايت همگاني است.',
+       'annuler' => 'ابطال',
+
+       // B
+       'bouton_supprimer' => 'حذف',
+
+       // D
+       'deja_modifie' => 'پيش‌‌ تر اصلاح شده',
+       'donnees_mal_formatees' => 'فرمت درخواست نامعتبر',
+
+       // E
+       'editer' => 'ويرايش ',
+       'editer_@type@_@id@' => 'تمام @type@ @id@ را ويرايش کنید',
+       'editer_tout' => 'ويرايش همه',
+       'effets' => 'افكت‌ها',
+       'explication_exec_autorise' => 'صفحه‌هاي مجاز براي اصلاح
+(?exec=...) : (, جداسازي چند صفحه- *براي همه).',
+       'explication_introduction_article' => 'پيشگفتار يك مقاله توصيف يك مقاله را اگر باشد، نشان مي‌دهد، و اگر نباشد 600 كاراكتر اول (ليد و متن)را نشان خواهد داد.',
+       'explication_reduire_logo' => 'اندازه‌ي لوگ را اگر از بيشترين حد بالا زده باشد كم مي‌كند (به پيكسل). نمونه : 100. ( 0 = هرگز)',
+
+       // I
+       'info_experimental' => 'Expérimental', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'فعال‌سازي ميل حروف‌نگاري در پلاگين «مدادها»؟',
+       'label_activer_crayons_prive' => 'فعال سازي «مدادها» راي قسمت خصوصي.',
+       'label_barre_typo' => 'ميل حروف نگاري ',
+       'label_clickhide' => 'يك كليك بيرون محوطه مدادها را مبي بندد',
+       'label_effets' => 'گزينش افكت‌ها',
+       'label_espaceprive' => 'مدادها در محوطه‌ي خصوصي؟',
+       'label_exec_autorise' => 'صفحه‌هاي مجاز',
+       'label_filet' => 'خط',
+       'label_message' => 'كسب پيام',
+       'label_msg_abandon' => 'در جريان ابطال',
+       'label_msg_no_change' => 'در صورت عدم تغيير ',
+       'label_reduire_logo' => 'كاهش لوگوها',
+       'label_upload_document' => 'Autoriser l\'ajout de documents par glisser/déposer sur le crayon article.texte', # NEW
+       'label_yellow_fade' => 'محو',
+       'legend_controleur_hyperlien' => 'ابرپيوند',
+       'legend_controleur_logo' => 'گزينش يك لوگو :',
+       'legend_controleur_logo_remplacer' => 'جايگزيني اين لوگو',
+       'legend_controleur_qui' => 'كي؟',
+       'legend_controleur_vignette' => 'گزيش يك صورتك  :',
+       'legend_controleur_vignette_remplacer' => 'جايگزيني اين صورت',
+       'legend_documents' => 'Upload de documents', # NEW
+       'legend_editer_prive' => 'استفاده در محوطه‌ي خصوصي (تجربي)',
+       'legend_introduction_article' => 'متن مقدماتي مقاله',
+
+       // M
+       'message_image_obligatoire' => 'بايد يك تصوير انتخاب كنيد',
+       'messages' => 'پيام‌ها',
+       'modifie_par_ailleurs' => 'جاي ديگر اصلاح شده',
+
+       // N
+       'non_autorise' => 'بي ‌مجوز',
+       'non_implemente' => 'انجام نیافته',
+
+       // P
+       'pas_de_modification' => 'بدون تغییر',
+       'pas_de_valeur' => 'بی ارزش',
+
+       // S
+       'sauvegarder' => ' ضبط تغییرات؟',
+       'svp_copier_coller' => 'متاسفیم. تغییرات را دوباره کپی سپس بچسبانید',
+
+       // T
+       'titre_config_crayons' => 'پيكربندي «مدادها» ',
+       'titre_crayons' => 'مدادها',
+
+       // U
+       'update_impossible' => 'روزآمد نشد.',
+
+       // V
+       'veuillez_patienter' => 'لطفأ صبر کنید ...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_fr.php b/www/plugins/crayons/lang/crayons_fr.php
new file mode 100644 (file)
index 0000000..df390e1
--- /dev/null
@@ -0,0 +1,86 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/crayons/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.',
+       'annuler' => 'Annuler',
+
+       // B
+       'bouton_supprimer' => 'Supprimer',
+
+       // D
+       'deja_modifie' => 'Déjà modifié',
+       'donnees_mal_formatees' => 'Données mal formatées',
+
+       // E
+       'editer' => 'Éditer',
+       'editer_@type@_@id@' => 'Éditer @type@ @id@ en entier',
+       'editer_tout' => 'Éditer tout',
+       'effets' => 'Effets',
+       'explication_exec_autorise' => 'Pages autorisées à la modification
+               (?exec=...) : (, pour séparer les exec - * pour toutes).',
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).',
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)',
+
+       // I
+       'info_experimental' => 'Expérimental',
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?',
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.',
+       'label_barre_typo' => 'Barre typographique',
+       'label_clickhide' => 'Un clic en-dehors masque les crayons',
+       'label_effets' => 'Choix des effets',
+       'label_espaceprive' => 'Crayons dans le privé ?',
+       'label_exec_autorise' => 'Pages autorisées',
+       'label_filet' => 'Filet',
+       'label_message' => 'Obtenir un message',
+       'label_msg_abandon' => 'Sur abandon',
+       'label_msg_no_change' => 'Si pas de changement',
+       'label_reduire_logo' => 'Réduire les logos',
+       'label_upload_document' => 'Autoriser l\'ajout de documents par glisser/déposer sur le crayon article.texte',
+       'label_yellow_fade' => 'Fade',
+       'legend_controleur_hyperlien' => 'Hyperlien',
+       'legend_controleur_logo' => 'Choisir un logo :',
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo',
+       'legend_controleur_qui' => 'Qui ?',
+       'legend_controleur_vignette' => 'Choisir une vignette :',
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette',
+       'legend_documents' => 'Upload de documents',
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)',
+       'legend_introduction_article' => 'Texte introductif de l\'article',
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image',
+       'messages' => 'Messages',
+       'modifie_par_ailleurs' => 'Modifié par ailleurs',
+
+       // N
+       'non_autorise' => 'Non autorisé',
+       'non_implemente' => 'Non implémenté',
+
+       // P
+       'pas_de_modification' => 'Pas de modification',
+       'pas_de_valeur' => 'Pas de valeur',
+
+       // S
+       'sauvegarder' => 'Sauvegarder les modifications ?',
+       'svp_copier_coller' => 'Désolé, copiez/collez vos changements et recommencez',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons',
+       'titre_crayons' => 'Crayons',
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.',
+
+       // V
+       'veuillez_patienter' => 'Veuillez patienter...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_fr_tu.php b/www/plugins/crayons/lang/crayons_fr_tu.php
new file mode 100644 (file)
index 0000000..e8eca5b
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=fr_tu
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.',
+       'annuler' => 'Annuler',
+
+       // B
+       'bouton_supprimer' => 'Supprimer',
+
+       // D
+       'deja_modifie' => 'Déjà modifié',
+       'donnees_mal_formatees' => 'Données mal formatées',
+
+       // E
+       'editer' => 'Éditer',
+       'editer_@type@_@id@' => 'Éditer @type@ @id@ en entier',
+       'editer_tout' => 'Éditer tout',
+       'effets' => 'Effets',
+       'explication_exec_autorise' => 'Pages autorisées à la modification
+  (?exec=...) : (, pour séparer les exec - * pour toutes).',
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).',
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse
+  la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # MODIF
+
+       // I
+       'info_experimental' => 'Expérimental', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?',
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.',
+       'label_barre_typo' => 'Barre typographique',
+       'label_clickhide' => 'Un clic en-dehors masque les crayons',
+       'label_effets' => 'Choix des effets',
+       'label_espaceprive' => 'Crayons dans le privé ?',
+       'label_exec_autorise' => 'Pages autorisées',
+       'label_filet' => 'Filet',
+       'label_message' => 'Obtenir un message',
+       'label_msg_abandon' => 'Sur abandon',
+       'label_msg_no_change' => 'Si pas de changement',
+       'label_reduire_logo' => 'Réduire les logos',
+       'label_upload_document' => 'Autoriser l\'ajout de documents par glisser/déposer sur le crayon article.texte', # NEW
+       'label_yellow_fade' => 'Fade',
+       'legend_controleur_hyperlien' => 'Hyperlien',
+       'legend_controleur_logo' => 'Choisir un logo :',
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo',
+       'legend_controleur_qui' => 'Qui ?',
+       'legend_controleur_vignette' => 'Choisir une vignette :',
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette',
+       'legend_documents' => 'Upload de documents', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)',
+       'legend_introduction_article' => 'Texte introductif de l\'article',
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image',
+       'messages' => 'Messages',
+       'modifie_par_ailleurs' => 'Modifié par ailleurs',
+
+       // N
+       'non_autorise' => 'Non autorisé',
+       'non_implemente' => 'Non implémenté',
+
+       // P
+       'pas_de_modification' => 'Pas de modification',
+       'pas_de_valeur' => 'Pas de valeur',
+
+       // S
+       'sauvegarder' => 'Sauvegarder les modifications ?',
+       'svp_copier_coller' => 'Désolé, copie/colle tes changements et recommence',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons',
+       'titre_crayons' => 'Crayons',
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.',
+
+       // V
+       'veuillez_patienter' => 'Patiente stp...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_gl.php b/www/plugins/crayons/lang/crayons_gl.php
new file mode 100644 (file)
index 0000000..2cdfca3
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Anular',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Xa modificado',
+       'donnees_mal_formatees' => 'Datos mal formatados',
+
+       // E
+       'editer' => 'Editar',
+       'editer_@type@_@id@' => 'Editar @type@ @id@ por completo',
+       'editer_tout' => 'Editar todo',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Modificado por outros',
+
+       // N
+       'non_autorise' => 'Non autorizado',
+       'non_implemente' => 'Non implementado',
+
+       // P
+       'pas_de_modification' => 'Non hai modificacións',
+       'pas_de_valeur' => 'Ningún valor',
+
+       // S
+       'sauvegarder' => 'Gardar as modificacións ?',
+       'svp_copier_coller' => 'Desculpe, copie/pegue os seus cambios e volva comezar',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'Fallou a actualización',
+
+       // V
+       'veuillez_patienter' => 'Teña paciencia ...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_it.php b/www/plugins/crayons/lang/crayons_it.php
new file mode 100644 (file)
index 0000000..8b998e6
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un altro plugin impedisce l\'utilizzo di porte-plume nella spazio pubblico.',
+       'annuler' => 'Annulla',
+
+       // B
+       'bouton_supprimer' => 'Elimina',
+
+       // D
+       'deja_modifie' => 'Già modificato',
+       'donnees_mal_formatees' => 'Dati mal formattati',
+
+       // E
+       'editer' => 'Modifica',
+       'editer_@type@_@id@' => 'Modifica @type@ @id@ in intero',
+       'editer_tout' => 'Modifica tutto',
+       'effets' => 'Effetti',
+       'explication_exec_autorise' => 'Pagine autorizzate per la modifica
+  (?exec=...) : (, per separare gli exec - * per tutti).',
+       'explication_introduction_article' => 'L\'introduzione di un articolo mostra la descrizione di un articolo, altrimenti mostra i suoi primi 600 caratteri (cappello più testo)',
+       'explication_reduire_logo' => 'Riduci il logo se supera
+  la dimensione massima indicata in pixel. Esempio: 100. (0 = mai)', # MODIF
+
+       // I
+       'info_experimental' => 'Expérimental', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Attivare la barra tipografica per i pennarelli?',
+       'label_activer_crayons_prive' => 'Attivare i pennarelli per la parte redazionale.',
+       'label_barre_typo' => 'Barra tipografica',
+       'label_clickhide' => 'Un click fuori nasconde i pennarelli',
+       'label_effets' => 'Scelta degli effetti',
+       'label_espaceprive' => 'Pennarelli in redazione?',
+       'label_exec_autorise' => 'Pagine autorizzate',
+       'label_filet' => 'Bordo',
+       'label_message' => 'Ottieni un messaggio',
+       'label_msg_abandon' => 'Sull\'abbandono',
+       'label_msg_no_change' => 'Se non c\'è nessuna modifica',
+       'label_reduire_logo' => 'Riduci i logo',
+       'label_upload_document' => 'Autoriser l\'ajout de documents par glisser/déposer sur le crayon article.texte', # NEW
+       'label_yellow_fade' => 'Fade',
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Scegli un logo:',
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Scegli una miniatura:',
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_documents' => 'Upload de documents', # NEW
+       'legend_editer_prive' => 'Modifica lo spazio redazionale (sperimentale)',
+       'legend_introduction_article' => 'Testo introduttivo dell\'articolo',
+
+       // M
+       'message_image_obligatoire' => 'Devi scegliere un\'immagine',
+       'messages' => 'Messaggi',
+       'modifie_par_ailleurs' => 'Modificato altrove',
+
+       // N
+       'non_autorise' => 'Non autorizzato',
+       'non_implemente' => 'Non implementato',
+
+       // P
+       'pas_de_modification' => 'Nessuna modifica',
+       'pas_de_valeur' => 'Nessun valore',
+
+       // S
+       'sauvegarder' => 'Registrare le modifiche?',
+       'svp_copier_coller' => 'Spiacente, copia/incolla le modifiche e comincia di nuovo',
+
+       // T
+       'titre_config_crayons' => 'Configura i pennarelli',
+       'titre_crayons' => 'Pennarelli',
+
+       // U
+       'update_impossible' => 'L\'aggiornamento è fallito.',
+
+       // V
+       'veuillez_patienter' => 'Attendere...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_it_fem.php b/www/plugins/crayons/lang/crayons_it_fem.php
new file mode 100644 (file)
index 0000000..937699b
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Annulla',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Già modificato',
+       'donnees_mal_formatees' => 'Dati mal formattati',
+
+       // E
+       'editer' => 'Modifica',
+       'editer_@type@_@id@' => 'Modifica @type@ @id@ in intero',
+       'editer_tout' => 'Modifica tutto',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Modificato altrove',
+
+       // N
+       'non_autorise' => 'Non autorizzato',
+       'non_implemente' => 'Non implementato',
+
+       // P
+       'pas_de_modification' => 'Nessuna modifica',
+       'pas_de_valeur' => 'Nessun valore',
+
+       // S
+       'sauvegarder' => 'Registrare le modifiche?',
+       'svp_copier_coller' => 'Spiacente, copia/incolla le modifiche e comincia di nuovo',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Attendere...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_km.php b/www/plugins/crayons/lang/crayons_km.php
new file mode 100644 (file)
index 0000000..3f9edc4
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'បោះបង់',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Already modified', # NEW
+       'donnees_mal_formatees' => 'Invalid request format', # NEW
+
+       // E
+       'editer' => 'កែប្រែ',
+       'editer_@type@_@id@' => 'Edit the whole @type@ @id@', # NEW
+       'editer_tout' => 'កែប្រែ ទាំងអស់',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Was modified elsewhere in the meantime', # NEW
+
+       // N
+       'non_autorise' => '<NEW>គ្មានអនុញ្ញាត',
+       'non_implemente' => 'Not implemented', # NEW
+
+       // P
+       'pas_de_modification' => '<NEW>គ្មានបំលាស់ប្តូរ',
+       'pas_de_valeur' => '<NEW>គ្មានតំលៃ សំរាប់អត្តសញ្ញា (ID) នេះ',
+
+       // S
+       'sauvegarder' => '<NEW>រក្សាទុក បំលាស់ប្តូរ?',
+       'svp_copier_coller' => 'Sorry, copy/paste your changes and retry', # NEW
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'ការបន្ទាន់សម័យ បានបរាជ័យ។',
+
+       // V
+       'veuillez_patienter' => 'កំពុងស្វែងរក ...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_lb.php b/www/plugins/crayons/lang/crayons_lb.php
new file mode 100644 (file)
index 0000000..0e0835b
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Annuléieren',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Schons geännert',
+       'donnees_mal_formatees' => 'Daten schlecht formatéiert',
+
+       // E
+       'editer' => 'Änneren',
+       'editer_@type@_@id@' => '@type@ @id@ ganz änneren',
+       'editer_tout' => 'Alles änneren',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Anerwärts geännert',
+
+       // N
+       'non_autorise' => 'Nët erlabt',
+       'non_implemente' => 'Nët agericht',
+
+       // P
+       'pas_de_modification' => 'Kéng Ännerung',
+       'pas_de_valeur' => 'Kéng Valeur',
+
+       // S
+       'sauvegarder' => 'Ännerunge späicheren?',
+       'svp_copier_coller' => 'Deet ons leet, kopéiert/pächt är Ännerungen a fänkt nei un',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Waart weg...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_nl.php b/www/plugins/crayons/lang/crayons_nl.php
new file mode 100644 (file)
index 0000000..f7315cb
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=nl
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Een andere plugin verbiedt het gebruik van pen in de openbare ruimte.',
+       'annuler' => 'Annuleren',
+
+       // B
+       'bouton_supprimer' => 'Verwijderen',
+
+       // D
+       'deja_modifie' => 'Reeds gewijzigd',
+       'donnees_mal_formatees' => 'Slecht geformatteerde gegevens',
+
+       // E
+       'editer' => 'Uitgeven',
+       'editer_@type@_@id@' => '@type@ @id@ in geheel uitgeven',
+       'editer_tout' => 'Alles uitgeven',
+       'effets' => 'Gevolgen',
+       'explication_exec_autorise' => 'Toegestaan ​​om pagina\'s te wijzigen
+  (?exec=...) : (, te scheiden exec - * voor allen).',
+       'explication_introduction_article' => 'De introductie van een functie geeft de beschrijving van het item, anders geeft de eerste 600 karakters (hoed en tekst).',
+       'explication_reduire_logo' => 'Verminder het logo als het hoger is dan 
+   de maximale grootte in pixels. Voorbeeld: 100. (0 = nooit)',
+
+       // I
+       'info_experimental' => 'Experimenteel',
+
+       // L
+       'label_activer_barre_typo' => 'Draai het typografie roer in de potloden ?',
+       'label_activer_crayons_prive' => 'Schakel potloden voor de private partij.',
+       'label_barre_typo' => 'Typografische bar',
+       'label_clickhide' => 'Te klikken buiten het masker potloden',
+       'label_effets' => 'Selectie-effecten',
+       'label_espaceprive' => 'Potloden in de prive-sector ?',
+       'label_exec_autorise' => 'pagina\'s geautoriseerde',
+       'label_filet' => 'Net',
+       'label_message' => 'Het krijgen van een bericht',
+       'label_msg_abandon' => 'Abandon zuid',
+       'label_msg_no_change' => 'Als er geen verandering',
+       'label_reduire_logo' => 'Verminderen logos',
+       'label_upload_document' => 'Bijvoegen van documenten door drag en drop op het article.texte potlood toelaten',
+       'label_yellow_fade' => 'Fade',
+       'legend_controleur_hyperlien' => 'Hyperlien',
+       'legend_controleur_logo' => 'Kies een logo :',
+       'legend_controleur_logo_remplacer' => 'Vervang deze logo',
+       'legend_controleur_qui' => 'Dat ?',
+       'legend_controleur_vignette' => 'Selecteer een miniatuur :',
+       'legend_controleur_vignette_remplacer' => 'Vervang deze tag',
+       'legend_documents' => 'Upload van documenten',
+       'legend_editer_prive' => 'Bewerk de private deel (experimentele)',
+       'legend_introduction_article' => 'Aanhef van artikel',
+
+       // M
+       'message_image_obligatoire' => 'U moet kiezen voor een foto',
+       'messages' => 'Berichten',
+       'modifie_par_ailleurs' => 'Voorts gewijzigd',
+
+       // N
+       'non_autorise' => 'Niet - toegelaten',
+       'non_implemente' => 'Niet geïmplementeerds',
+
+       // P
+       'pas_de_modification' => 'Geen wijziging',
+       'pas_de_valeur' => 'Geen waarde',
+
+       // S
+       'sauvegarder' => 'De wijzigingen beschermen?',
+       'svp_copier_coller' => 'Désolé, copiez/collez vos changements et recommencez',
+
+       // T
+       'titre_config_crayons' => 'Configureren potloden',
+       'titre_crayons' => 'Podloden',
+
+       // U
+       'update_impossible' => 'De update is niet geslaagd.',
+
+       // V
+       'veuillez_patienter' => 'Gelieve geduld te oefenen…'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_oc_lnc.php b/www/plugins/crayons/lang/crayons_oc_lnc.php
new file mode 100644 (file)
index 0000000..b9f466b
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Anullar',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Ja modificat',
+       'donnees_mal_formatees' => 'Donadas mal formatadas',
+
+       // E
+       'editer' => 'Editar',
+       'editer_@type@_@id@' => 'Editar @type@ @id@ en entièr',
+       'editer_tout' => 'Tot editar',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Modificat endacòm mai',
+
+       // N
+       'non_autorise' => 'Non autorizat',
+       'non_implemente' => 'Non implementat',
+
+       // P
+       'pas_de_modification' => 'Pas de modificacion',
+       'pas_de_valeur' => 'Pas de valor',
+
+       // S
+       'sauvegarder' => 'Registrar las modificacions ?',
+       'svp_copier_coller' => 'Desolats, copiatz/empegatz vòstres cambiaments e tornatz començar',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Mercés d\'esperar...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_pt_br.php b/www/plugins/crayons/lang/crayons_pt_br.php
new file mode 100644 (file)
index 0000000..2518073
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Cancelar',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'J&aacute; alterado',
+       'donnees_mal_formatees' => 'Dados mal formatados',
+
+       // E
+       'editer' => 'Editar',
+       'editer_@type@_@id@' => 'Editar @type@ @id@ completamente',
+       'editer_tout' => 'Editar tudo',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autoris&eacute;es &agrave; la modification
+               (?exec=...) : (, pour s&eacute;parer les exec).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caract&egrave;res (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'R&#233;duire le logo s\'il d&#233;passe
+               la taille maximale indiquee en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie priv&eacute;e.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le priv&eacute; ?', # NEW
+       'label_exec_autorise' => 'Pages autoris&eacute;es', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'R&eacute;duire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo&nbsp;:', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette&nbsp;:', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => '&Eacute;diter l\'espace priv&eacute; (exp&eacute;rimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Alterado em outro lugar',
+
+       // N
+       'non_autorise' => 'N&atilde;o autorizado',
+       'non_implemente' => 'N&atilde;o implementado',
+
+       // P
+       'pas_de_modification' => 'Sem modifica&ccedil;&atilde;o',
+       'pas_de_valeur' => 'Sem valor',
+
+       // S
+       'sauvegarder' => 'Fazer c&oacute;pia de seguran&ccedil;a das altera&ccedil;&otilde;es?',
+       'svp_copier_coller' => 'Desculpe, copie/cole as suas altera&ccedil;&otilde;es e recomece',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise &agrave; jour a &eacute;chou&eacute;.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Aguarde, por favor...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_ro.php b/www/plugins/crayons/lang/crayons_ro.php
new file mode 100644 (file)
index 0000000..857c8e6
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Anulati',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Deja modificat',
+       'donnees_mal_formatees' => 'Date rau formatate',
+
+       // E
+       'editer' => 'Editati',
+       'editer_@type@_@id@' => 'Editati @type@ @id@ in intregime',
+       'editer_tout' => 'Editati totul',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Modificat de altfel',
+
+       // N
+       'non_autorise' => 'Neautorizat',
+       'non_implemente' => 'Neimplementat',
+
+       // P
+       'pas_de_modification' => 'Fara modificari',
+       'pas_de_valeur' => 'Fara valoare',
+
+       // S
+       'sauvegarder' => 'Salvati modificarile ?',
+       'svp_copier_coller' => 'Ne pare rau, copiati/lipiti schimbarile dvs. si reincepeti',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Va rugam sa asteptati'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_ru.php b/www/plugins/crayons/lang/crayons_ru.php
new file mode 100644 (file)
index 0000000..e710dcf
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Другой плагин не дайет использовать porte-plume на сайте.',
+       'annuler' => 'Отмена',
+
+       // B
+       'bouton_supprimer' => 'Удалить',
+
+       // D
+       'deja_modifie' => 'Уже изменен',
+       'donnees_mal_formatees' => 'Неправильный формат запроса',
+
+       // E
+       'editer' => 'Редактировать',
+       'editer_@type@_@id@' => 'Редактировать @type@ @id@ полностью',
+       'editer_tout' => 'Редактировать полностью',
+       'effets' => 'Эффекты',
+       'explication_exec_autorise' => 'Страницы, на которых можно редактировать информацию   (?exec=...) : (, разделитель между страницами. * для всех страниц).',
+       'explication_introduction_article' => 'Вводная статьи выводит информацию из поля "введение". Если оно пустое, товыводится первые 600 символов текста статьи.',
+       'explication_reduire_logo' => 'Уменьшать логотипы если их размер превышает 
+  максимальный размер (в пикселях) Например: 100. (0 = никогда)',
+
+       // I
+       'info_experimental' => 'Экспериментальная опция',
+
+       // L
+       'label_activer_barre_typo' => 'Включить панель инструментов для плагина?',
+       'label_activer_crayons_prive' => 'Включить "Карандаш" в админке сайта',
+       'label_barre_typo' => 'Панель инструментов',
+       'label_clickhide' => 'Нажмите вне области редактирования чтобы закрыть экран',
+       'label_effets' => 'Выбрать эффект',
+       'label_espaceprive' => 'Использовать "Карандаш" в админке сайта?',
+       'label_exec_autorise' => 'Использовать на страницах',
+       'label_filet' => 'Линия',
+       'label_message' => 'Показать сообщение',
+       'label_msg_abandon' => 'При отмене',
+       'label_msg_no_change' => 'Если не были сделаны изменения',
+       'label_reduire_logo' => 'Уменьшать логотипы',
+       'label_upload_document' => 'Разрешить добавлять документы перетаскиванием их поле "текст" статьи (article.texte)',
+       'label_yellow_fade' => 'Тень',
+       'legend_controleur_hyperlien' => 'Ссылка',
+       'legend_controleur_logo' => 'Выбрать логотип:',
+       'legend_controleur_logo_remplacer' => 'Заменить логотип',
+       'legend_controleur_qui' => 'Кто?',
+       'legend_controleur_vignette' => 'Выбрать миниатюру:',
+       'legend_controleur_vignette_remplacer' => 'Заменить миниатюру',
+       'legend_documents' => 'Загрузить документ',
+       'legend_editer_prive' => 'Использовать в админке сайта',
+       'legend_introduction_article' => 'Вводный текст для статьи',
+
+       // M
+       'message_image_obligatoire' => 'Вам необходимо выбрать сообщение',
+       'messages' => 'Сообщения',
+       'modifie_par_ailleurs' => 'Был изменен в другом месте в то же время',
+
+       // N
+       'non_autorise' => 'Нет доступа',
+       'non_implemente' => 'Не выполнено',
+
+       // P
+       'pas_de_modification' => 'Без изменений',
+       'pas_de_valeur' => 'Не указано значение для этого id',
+
+       // S
+       'sauvegarder' => 'Сохранить изменения?',
+       'svp_copier_coller' => 'Сохраните сделанные изменения в другом месте и попробуйте заново',
+
+       // T
+       'titre_config_crayons' => 'Настроить "Карандаш"',
+       'titre_crayons' => 'Карандаш',
+
+       // U
+       'update_impossible' => 'Не удалось обновить.',
+
+       // V
+       'veuillez_patienter' => 'Идет поиск ...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_sk.php b/www/plugins/crayons/lang/crayons_sk.php
new file mode 100644 (file)
index 0000000..62d801d
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Iný zásuvný modul bráni použitiu porte-plume na verejne prístupnej stránke.',
+       'annuler' => 'Zrušiť',
+
+       // B
+       'bouton_supprimer' => 'Odstrániť',
+
+       // D
+       'deja_modifie' => 'Už upravený',
+       'donnees_mal_formatees' => 'Neplatný formát požiadavky',
+
+       // E
+       'editer' => 'Upraviť',
+       'editer_@type@_@id@' => 'Upraviť celý @type@ @id@',
+       'editer_tout' => 'Upravovať ako celok',
+       'effets' => 'Efekty',
+       'explication_exec_autorise' => 'Stránky, na ktorých je povolené vykonávať zmeny
+  (?exec=...): (, na oddelenie viacerých stránok, * pre všetky).',
+       'explication_introduction_article' => 'Ako úvod článku sa zobrazí popis článku, ak nejaký existuje, v opačnom prípade sa zobrazí prvých 600 znakov (úvodného odseku a textu).',
+       'explication_reduire_logo' => 'Zmenšiť veľkosť loga, ak presahuje
+  maximálnu veľkosť (v pixeloch). Príklad: 100 (0 = nikdy).',
+
+       // I
+       'info_experimental' => 'Experimentálny',
+
+       // L
+       'label_activer_barre_typo' => 'Aktivovať klávesový panel pre "Farbičky"?',
+       'label_activer_crayons_prive' => 'Aktivovať "Farbičky" pre súkromnú zónu.',
+       'label_barre_typo' => 'Klávesový panel',
+       'label_clickhide' => 'Klikom mimo oblasti farbičky zatvoríte',
+       'label_effets' => 'Výber efektov',
+       'label_espaceprive' => 'Používať "farbičky" v súkromnej zóne?',
+       'label_exec_autorise' => 'Stránky povolené',
+       'label_filet' => 'Čiara',
+       'label_message' => 'Zobraziť správu',
+       'label_msg_abandon' => 'Pri zrušení',
+       'label_msg_no_change' => 'Ak sa neurobí žiadna zmena',
+       'label_reduire_logo' => 'Zmenšiť logá',
+       'label_upload_document' => 'Povoliť pridávanie súborov pomocou farbičky article.texte',
+       'label_yellow_fade' => 'Tieň',
+       'legend_controleur_hyperlien' => 'Hypertextový odkaz',
+       'legend_controleur_logo' => 'Vyberte logo:',
+       'legend_controleur_logo_remplacer' => 'Nahradiť toto logo',
+       'legend_controleur_qui' => 'Kto?',
+       'legend_controleur_vignette' => 'Vyberte miniatúru:',
+       'legend_controleur_vignette_remplacer' => 'Nahradiť túto miniatúru',
+       'legend_documents' => 'Nahrávanie súborov',
+       'legend_editer_prive' => 'Použiť v súkromnej zóne (experimentálne)',
+       'legend_introduction_article' => 'Úvodný text článku',
+
+       // M
+       'message_image_obligatoire' => 'Musíte si vybrať obrázok',
+       'messages' => 'Správy',
+       'modifie_par_ailleurs' => 'Medzitým bol zmenený inde',
+
+       // N
+       'non_autorise' => 'Nepovolené',
+       'non_implemente' => 'Nezavedené',
+
+       // P
+       'pas_de_modification' => 'Žiadna zmena',
+       'pas_de_valeur' => 'Toto ID nemá žiadnu hodnotu',
+
+       // S
+       'sauvegarder' => 'Uložiť zmeny?',
+       'svp_copier_coller' => 'Prepáčte, skopírujte/prilepte svoje zmeny a skúste znova',
+
+       // T
+       'titre_config_crayons' => 'Nastaviť "Farbičky"',
+       'titre_crayons' => 'Farbičky',
+
+       // U
+       'update_impossible' => 'Aktualizácia neprebehla úspešne.',
+
+       // V
+       'veuillez_patienter' => 'Vyhľadáva sa...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_sv.php b/www/plugins/crayons/lang/crayons_sv.php
new file mode 100644 (file)
index 0000000..b2cb909
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'Ångra',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Redan ändrat',
+       'donnees_mal_formatees' => 'Felaktigt format på data',
+
+       // E
+       'editer' => 'Editera',
+       'editer_@type@_@id@' => 'Editera hela @type@ @id@',
+       'editer_tout' => 'Editera allt',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Någon annan har förändrat artikeln sedan du öppnade den',
+
+       // N
+       'non_autorise' => 'Ej tillåtet',
+       'non_implemente' => 'Funktionen saknas',
+
+       // P
+       'pas_de_modification' => 'Ingen förändring',
+       'pas_de_valeur' => 'Inget värde',
+
+       // S
+       'sauvegarder' => 'Spara förändringarna?',
+       'svp_copier_coller' => 'Ledsen, kopiera/klistra in dina förändringar och försök igen',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Söker ...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_tr.php b/www/plugins/crayons/lang/crayons_tr.php
new file mode 100644 (file)
index 0000000..ec8270f
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => 'İptal et',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => 'Zaten değiştirilmiş',
+       'donnees_mal_formatees' => 'Kötü formatlanmış veriler',
+
+       // E
+       'editer' => 'Düzenle',
+       'editer_@type@_@id@' => '@type@ @id@ tümünü düzenle',
+       'editer_tout' => 'Hepsini düzenle',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => 'Başkaları tarafından değiştirilmiş',
+
+       // N
+       'non_autorise' => 'Yetkisiz',
+       'non_implemente' => 'Geliştirilmemiş',
+
+       // P
+       'pas_de_modification' => 'Değişiklik yok',
+       'pas_de_valeur' => 'Değersiz',
+
+       // S
+       'sauvegarder' => 'Değişiklikler kaydedilsin mi ?',
+       'svp_copier_coller' => 'Üzgünüm, değişikliklerinizi kesin/yapıştırın ve tekrar başlayın',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => 'Lütfen sabrediniz...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_tw.php b/www/plugins/crayons/lang/crayons_tw.php
new file mode 100644 (file)
index 0000000..d9e3100
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => '取消',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => '已經修改過',
+       'donnees_mal_formatees' => '資料格式不正確',
+
+       // E
+       'editer' => '編輯',
+       'editer_@type@_@id@' => '完整編輯 @type@ @id@',
+       'editer_tout' => '編輯全部',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => '已經被修改過',
+
+       // N
+       'non_autorise' => '不被允許',
+       'non_implemente' => '尚未支援',
+
+       // P
+       'pas_de_modification' => '沒有修改過',
+       'pas_de_valeur' => '無指定值',
+
+       // S
+       'sauvegarder' => '儲存修改過的資料 ?',
+       'svp_copier_coller' => '對不起,我們建議您複製/貼上您的修改',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => '請稍後...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_zh.php b/www/plugins/crayons/lang/crayons_zh.php
new file mode 100644 (file)
index 0000000..8659fa7
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/crayons?lang_cible=zh
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => '取消', # MODIF
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => '已经修改', # MODIF
+       'donnees_mal_formatees' => '数据格式化错误', # MODIF
+
+       // E
+       'editer' => '编辑', # MODIF
+       'editer_@type@_@id@' => '编辑@type@@id@所有内容', # MODIF
+       'editer_tout' => '编辑所有内容', # MODIF
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification
+               (?exec=...) : (, pour séparer les exec).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse
+               la taille maximale indiquee en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // I
+       'info_experimental' => 'Expérimental', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_upload_document' => 'Autoriser l\'ajout de documents par glisser/déposer sur le crayon article.texte', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_documents' => 'Upload de documents', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)',
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => '被别人修改', # MODIF
+
+       // N
+       'non_autorise' => '没有授权', # MODIF
+       'non_implemente' => '为调试交机', # MODIF
+
+       // P
+       'pas_de_modification' => '无修改内容', # MODIF
+       'pas_de_valeur' => '没有值', # MODIF
+
+       // S
+       'sauvegarder' => '保存已修改的内容吗?', # MODIF
+       'svp_copier_coller' => '对不起,复制/粘贴已经改变的内容,并重新开始', # MODIF
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => '请稍后...' # MODIF
+);
+
+?>
diff --git a/www/plugins/crayons/lang/crayons_zh_tw.php b/www/plugins/crayons/lang/crayons_zh_tw.php
new file mode 100644 (file)
index 0000000..d9e3100
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'activation_barre_impossible' => 'Un autre plugin interdit l\'usage du porte-plume dans l\'espace public.', # NEW
+       'annuler' => '取消',
+
+       // B
+       'bouton_supprimer' => 'Supprimer', # NEW
+
+       // D
+       'deja_modifie' => '已經修改過',
+       'donnees_mal_formatees' => '資料格式不正確',
+
+       // E
+       'editer' => '編輯',
+       'editer_@type@_@id@' => '完整編輯 @type@ @id@',
+       'editer_tout' => '編輯全部',
+       'effets' => 'Effets', # NEW
+       'explication_exec_autorise' => 'Pages autorisées à la modification\r
+               (?exec=...) : (, pour séparer les exec - * pour toutes).', # NEW
+       'explication_introduction_article' => 'L\'introduction d\'un article affiche le descriptif de l\'article, sinon affiche ses 600 premiers caractères (chapeau puis texte).', # NEW
+       'explication_reduire_logo' => 'Réduire le logo s\'il dépasse\r
+               la taille maximale indiquée en pixels. Exemple : 100. (0 = jamais)', # NEW
+
+       // L
+       'label_activer_barre_typo' => 'Activer la barre typographique dans les crayons ?', # NEW
+       'label_activer_crayons_prive' => 'Activer crayons pour la partie privée.', # NEW
+       'label_barre_typo' => 'Barre typographique', # NEW
+       'label_clickhide' => 'Un clic en-dehors masque les crayons', # NEW
+       'label_effets' => 'Choix des effets', # NEW
+       'label_espaceprive' => 'Crayons dans le privé ?', # NEW
+       'label_exec_autorise' => 'Pages autorisées', # NEW
+       'label_filet' => 'Filet', # NEW
+       'label_message' => 'Obtenir un message', # NEW
+       'label_msg_abandon' => 'Sur abandon', # NEW
+       'label_msg_no_change' => 'Si pas de changement', # NEW
+       'label_reduire_logo' => 'Réduire les logos', # NEW
+       'label_yellow_fade' => 'Fade', # NEW
+       'legend_controleur_hyperlien' => 'Hyperlien', # NEW
+       'legend_controleur_logo' => 'Choisir un logo :', # NEW
+       'legend_controleur_logo_remplacer' => 'Remplacer ce logo', # NEW
+       'legend_controleur_qui' => 'Qui ?', # NEW
+       'legend_controleur_vignette' => 'Choisir une vignette :', # NEW
+       'legend_controleur_vignette_remplacer' => 'Remplacer cette vignette', # NEW
+       'legend_editer_prive' => 'Éditer l\'espace privé (expérimental)', # NEW
+       'legend_introduction_article' => 'Texte introductif de l\'article', # NEW
+
+       // M
+       'message_image_obligatoire' => 'Il faut choisir une image', # NEW
+       'messages' => 'Messages', # NEW
+       'modifie_par_ailleurs' => '已經被修改過',
+
+       // N
+       'non_autorise' => '不被允許',
+       'non_implemente' => '尚未支援',
+
+       // P
+       'pas_de_modification' => '沒有修改過',
+       'pas_de_valeur' => '無指定值',
+
+       // S
+       'sauvegarder' => '儲存修改過的資料 ?',
+       'svp_copier_coller' => '對不起,我們建議您複製/貼上您的修改',
+
+       // T
+       'titre_config_crayons' => 'Configurer les crayons', # NEW
+       'titre_crayons' => 'Crayons', # NEW
+
+       // U
+       'update_impossible' => 'La mise à jour a échoué.', # NEW
+
+       // V
+       'veuillez_patienter' => '請稍後...'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons.xml b/www/plugins/crayons/lang/paquet-crayons.xml
new file mode 100644 (file)
index 0000000..4398114
--- /dev/null
@@ -0,0 +1,19 @@
+<traduction module="paquet-crayons" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/crayons/lang/" reference="fr">
+       <langue code="ar" />
+       <langue code="de" />
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=es">
+               <traducteur nom="dani" lien="http://trad.spip.net/auteur/dani" />
+       </langue>
+       <langue code="fr" />
+       <langue code="it" />
+       <langue code="nl" url="http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=nl">
+               <traducteur nom="Suske" lien="http://trad.spip.net/auteur/suske" />
+       </langue>
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/crayons/lang/paquet-crayons_ar.php b/www/plugins/crayons/lang/paquet-crayons_ar.php
new file mode 100644 (file)
index 0000000..bda2a8a
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=ar
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'هذا الملحق، {{المتوافر للاصدار ١.٩.٢ فقط}} يقدم وظائف تحرير سريعة من في صفحات الموقع العمومي. للاستفادة منه يجب انشاء صفحات نموذجية متوافقة معه.
+
+كما في صفحات الاصدار 1.9.2 النموذجية يكفي ادخال علامة {#EDIT} في كل مكان نريد تحريره. مثلاً، ليصبح العنوان قابل للتحرير:
+_ <code><h1 class="#EDIT{titre} علامات اخرى">#TITRE</h1></code>.',
+       'crayons_nom' => 'القلم',
+       'crayons_slogan' => 'هذا الملحق، {{المتوافر للاصدار ١'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_de.php b/www/plugins/crayons/lang/paquet-crayons_de.php
new file mode 100644 (file)
index 0000000..c65267d
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Änderungen in öffentlichen Seiten direkt erledigen, Vorausetzung für Wikis mit SPIP',
+       'crayons_nom' => 'Der Stift',
+       'crayons_slogan' => 'Änderungen in öffentlichen Seiten direkt erledigen, Vorausetzung für Wikis mit SPIP'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_en.php b/www/plugins/crayons/lang/paquet-crayons_en.php
new file mode 100644 (file)
index 0000000..6c6c838
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Quick editing from the public pages of the site.',
+       'crayons_nom' => 'Pencils',
+       'crayons_slogan' => 'Quick editing from the public pages of the site'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_es.php b/www/plugins/crayons/lang/paquet-crayons_es.php
new file mode 100644 (file)
index 0000000..2033181
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Modificación rápida desde las páginas públicas del sitio.',
+       'crayons_nom' => 'Lápices',
+       'crayons_slogan' => 'Edición rápida desde las páginas publicas del sitio'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_fr.php b/www/plugins/crayons/lang/paquet-crayons_fr.php
new file mode 100644 (file)
index 0000000..c6d29e6
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/crayons/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Édition rapide depuis les pages publiques du site.',
+       'crayons_nom' => 'Crayons',
+       'crayons_slogan' => 'Édition rapide depuis les pages publiques du site'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_it.php b/www/plugins/crayons/lang/paquet-crayons_it.php
new file mode 100644 (file)
index 0000000..4c0bccd
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Modifica rapida dalle pagine pubbliche del sito.',
+       'crayons_nom' => 'Pennarelli',
+       'crayons_slogan' => 'Modifica rapida dalle pagine pubbliche del sito'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_nl.php b/www/plugins/crayons/lang/paquet-crayons_nl.php
new file mode 100644 (file)
index 0000000..52bac09
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=nl
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Snel bewerken van de publieke pagina\'s van de site.',
+       'crayons_nom' => 'Potloden',
+       'crayons_slogan' => 'Snel bewerken van de publieke pagina\'s van de site.'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_ru.php b/www/plugins/crayons/lang/paquet-crayons_ru.php
new file mode 100644 (file)
index 0000000..8ad6491
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Позволяет редактировать информацию прямо на сайте, не заходя в административную часть.',
+       'crayons_nom' => 'Карандаш (Crayons)',
+       'crayons_slogan' => 'Позволяет редактировать информацию прямо на сайте, не заходя в административную часть'
+);
+
+?>
diff --git a/www/plugins/crayons/lang/paquet-crayons_sk.php b/www/plugins/crayons/lang/paquet-crayons_sk.php
new file mode 100644 (file)
index 0000000..887f14c
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-crayons?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'crayons_description' => 'Rýchle úpravy z verejne prístupnej stránky.',
+       'crayons_nom' => 'Farbičky',
+       'crayons_slogan' => 'Rýchle úpravy z verejne prístupnej stránky.'
+);
+
+?>
diff --git a/www/plugins/crayons/lib/JavaScriptPacker/class.JavaScriptPacker.php b/www/plugins/crayons/lib/JavaScriptPacker/class.JavaScriptPacker.php
new file mode 100644 (file)
index 0000000..ac82490
--- /dev/null
@@ -0,0 +1,773 @@
+<?php
+/* 7 December 2006. version 1.0
+ * 
+ * This is the php version of the Dean Edwards JavaScript 's Packer,
+ * Based on :
+ * 
+ * ParseMaster, version 1.0.2 (2005-08-19) Copyright 2005, Dean Edwards
+ * a multi-pattern parser.
+ * KNOWN BUG: erroneous behavior when using escapeChar with a replacement
+ * value that is a function
+ * 
+ * packer, version 2.0.2 (2005-08-19) Copyright 2004-2005, Dean Edwards
+ * 
+ * License: http://creativecommons.org/licenses/LGPL/2.1/
+ * 
+ * Ported to PHP by Nicolas Martin.
+ * modified by Mark Fabrizio Jr. to work with php 4 
+ * 
+ * ----------------------------------------------------------------------
+ * 
+ * examples of usage :
+ * $myPacker = new JavaScriptPacker($script, 62, true, false);
+ * $packed = $myPacker->pack();
+ * 
+ * or
+ * 
+ * $myPacker = new JavaScriptPacker($script, 'Normal', true, false);
+ * $packed = $myPacker->pack();
+ * 
+ * or (default values)
+ * 
+ * $myPacker = new JavaScriptPacker($script);
+ * $packed = $myPacker->pack();
+ * 
+ * 
+ * params of the constructor :
+ * $script:       the JavaScript to pack, string.
+ * $encoding:     level of encoding, int or string :
+ *                0,10,62,95 or 'None', 'Numeric', 'Normal', 'High ASCII'.
+ *                default: 62.
+ * $fastDecode:   include the fast decoder in the packed result, boolean.
+ *                default : true.
+ * $specialChars: if you are flagged your private and local variables
+ *                in the script, boolean.
+ *                default: false.
+ * 
+ * The pack() method return the compressed JavasScript, as a string.
+ * 
+ * see http://dean.edwards.name/packer/usage/ for more information.
+ * 
+ * Notes :
+ * # [del]need PHP 5 . Tested with PHP 5.1.2[/del]
+ *   this is a modified version for PHP 4
+ * 
+ * # The packed result may be different than with the Dean Edwards
+ *   version, but with the same length. The reason is that the PHP
+ *   function usort to sort array don't necessarily preserve the
+ *   original order of two equal member. The Javascript sort function
+ *   in fact preserve this order (but that's not require by the
+ *   ECMAScript standard). So the encoded keywords order can be
+ *   different in the two results.
+ * 
+ * # Be careful with the 'High ASCII' Level encoding if you use
+ *   UTF-8 in your files... 
+ */
+ /*
+ * modified by Mark Fabrizio Jr. to work with php 4
+ */
+
+
+class JavaScriptPacker {
+       var $IGNORE = '$1';
+
+       // validate parameters
+       var $_script = '';
+       var $_encoding = 62;
+       var $_fastDecode = true;
+       var $_specialChars = false;
+       
+       var $LITERAL_ENCODING = array(
+               'None' => 0,
+               'Numeric' => 10,
+               'Normal' => 62,
+               'High ASCII' => 95
+       );
+       
+// http://doc.spip.org/@JavaScriptPacker
+       function JavaScriptPacker($_script, $_encoding = 62, $_fastDecode = true, $_specialChars = false)
+       {
+               $this->_script = $_script . "\n";
+               if (array_key_exists($_encoding, $this->LITERAL_ENCODING))
+                       $_encoding = $this->LITERAL_ENCODING[$_encoding];
+               $this->_encoding = min((int)$_encoding, 95);
+               $this->_fastDecode = $_fastDecode;      
+               $this->_specialChars = $_specialChars;
+       }
+       
+// http://doc.spip.org/@pack
+       function pack() {
+               $this->_addParser('_basicCompression');
+               if ($this->_specialChars)
+                       $this->_addParser('_encodeSpecialChars');
+               if ($this->_encoding)
+                       $this->_addParser('_encodeKeywords');
+               
+               // go!
+               return $this->_pack($this->_script);
+       }
+       
+       // apply all parsing routines
+// http://doc.spip.org/@_pack
+       function _pack($script) {
+               for ($i = 0; isset($this->_parsers[$i]); $i++) {
+                       $script = call_user_func(array(&$this,$this->_parsers[$i]), $script);
+               }
+               return $script;
+       }
+       
+       // keep a list of parsing functions, they'll be executed all at once
+       var $_parsers = array();
+// http://doc.spip.org/@_addParser
+       function _addParser($parser) {
+               $this->_parsers[] = $parser;
+       }
+       
+       // zero encoding - just removal of white space and comments
+// http://doc.spip.org/@_basicCompression
+       function _basicCompression($script) {
+               $parser = new ParseMaster();
+               // make safe
+               $parser->escapeChar = '\\';
+               // protect strings
+               $parser->add('/\'[^\'\\n\\r]*\'/',$this->IGNORE);
+               $parser->add('/"[^"\\n\\r]*"/', $this->IGNORE);
+               // remove comments
+               $parser->add('/\\/\\/[^\\n\\r]*[\\n\\r]/', ' ');
+               $parser->add('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\//', ' ');
+               // protect regular expressions
+               $parser->add('/\\s+(\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?)/', '$2'); // IGNORE
+               $parser->add('/[^\\w\\x24\\/\'"*)\\?:]\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?/', $this->IGNORE);
+               // remove: ;;; doSomething();
+               if ($this->_specialChars) $parser->add('/;;;[^\\n\\r]+[\\n\\r]/');
+               // remove redundant semi-colons
+               $parser->add('/\\(;;\\)/', $this->IGNORE); // protect for (;;) loops
+               $parser->add('/;+\\s*([};])/', '$2');
+               // apply the above
+               $script = $parser->exec($script);
+
+               // remove white-space
+#              $parser->add('/(\\b|\\x24)\\s+(\\b|\\x24)/', '$2 $3');
+#              $parser->add('/([+\\-])\\s+([+\\-])/', '$2 $3');
+#              $parser->add('/\\s+/', '');
+# Modif fil@rezo.net pour conserver les \n
+               $parser->add('/(\\b|\\x24)[\\t ]+(\\b|\\x24)/', '$2 $3');
+               $parser->add('/([+\\-])[\\t ]+([+\\-])/', '$2 $3');
+               $parser->add('/[\\t ]+/', '');
+               $parser->add('/\\s+/', "\n");
+               // done
+               return $parser->exec($script);
+       }
+       
+// http://doc.spip.org/@_encodeSpecialChars
+       function _encodeSpecialChars($script) {
+               $parser = new ParseMaster();
+               // replace: $name -> n, $$name -> na
+               $parser->add('/((\\x24+)([a-zA-Z$_]+))(\\d*)/',
+                                        array('fn' => '_replace_name')
+               );
+               // replace: _name -> _0, double-underscore (__name) is ignored
+               $regexp = '/\\b_[A-Za-z\\d]\\w*/';
+               // build the word list
+               $keywords = $this->_analyze($script, $regexp, '_encodePrivate');
+               // quick ref
+               $encoded = $keywords['encoded'];
+               
+               $parser->add($regexp,
+                       array(
+                               'fn' => '_replace_encoded',
+                               'data' => $encoded
+                       )
+               );
+               return $parser->exec($script);
+       }
+       
+// http://doc.spip.org/@_encodeKeywords
+       function _encodeKeywords($script) {
+               // escape high-ascii values already in the script (i.e. in strings)
+               if ($this->_encoding > 62)
+                       $script = $this->_escape95($script);
+               // create the parser
+               $parser = new ParseMaster();
+               $encode = $this->_getEncoder($this->_encoding);
+               // for high-ascii, don't encode single character low-ascii
+               $regexp = ($this->_encoding > 62) ? '/\\w\\w+/' : '/\\w+/';
+               // build the word list
+               $keywords = $this->_analyze($script, $regexp, $encode);
+               $encoded = $keywords['encoded'];
+               
+               // encode
+               $parser->add($regexp,
+                       array(
+                               'fn' => '_replace_encoded',
+                               'data' => $encoded
+                       )
+               );
+               if (empty($script)) return $script;
+               else {
+                       //$res = $parser->exec($script);
+                       //$res = $this->_bootStrap($res, $keywords);
+                       //return $res;
+                       return $this->_bootStrap($parser->exec($script), $keywords);
+               }
+       }
+       
+// http://doc.spip.org/@_analyze
+       function _analyze($script, $regexp, $encode) {
+               // analyse
+               // retreive all words in the script
+               $all = array();
+               preg_match_all($regexp, $script, $all);
+               $_sorted = array(); // list of words sorted by frequency
+               $_encoded = array(); // dictionary of word->encoding
+               $_protected = array(); // instances of "protected" words
+               $all = $all[0]; // simulate the javascript comportement of global match
+               if (!empty($all)) {
+                       $unsorted = array(); // same list, not sorted
+                       $protected = array(); // "protected" words (dictionary of word->"word")
+                       $value = array(); // dictionary of charCode->encoding (eg. 256->ff)
+                       $this->_count = array(); // word->count
+                       $i = count($all); $j = 0; //$word = null;
+                       // count the occurrences - used for sorting later
+                       do {
+                               --$i;
+                               $word = '$' . $all[$i];
+                               if (!isset($this->_count[$word])) {
+                                       $this->_count[$word] = 0;
+                                       $unsorted[$j] = $word;
+                                       // make a dictionary of all of the protected words in this script
+                                       //  these are words that might be mistaken for encoding
+                                       //if (is_string($encode) && method_exists($this, $encode))
+                                       $values[$j] = call_user_func(array(&$this, $encode), $j);
+                                       $protected['$' . $values[$j]] = $j++;
+                               }
+                               // increment the word counter
+                               $this->_count[$word]++;
+                       } while ($i > 0);
+                       // prepare to sort the word list, first we must protect
+                       //  words that are also used as codes. we assign them a code
+                       //  equivalent to the word itself.
+                       // e.g. if "do" falls within our encoding range
+                       //      then we store keywords["do"] = "do";
+                       // this avoids problems when decoding
+                       $i = count($unsorted);
+                       do {
+                               $word = $unsorted[--$i];
+                               if (isset($protected[$word]) /*!= null*/) {
+                                       $_sorted[$protected[$word]] = substr($word, 1);
+                                       $_protected[$protected[$word]] = true;
+                                       $this->_count[$word] = 0;
+                               }
+                       } while ($i);
+                       
+                       // sort the words by frequency
+                       // Note: the javascript and php version of sort can be different :
+                       // in php manual, usort :
+                       // " If two members compare as equal,
+                       // their order in the sorted array is undefined."
+                       // so the final packed script is different of the Dean's javascript version
+                       // but equivalent.
+                       // the ECMAscript standard does not guarantee this behaviour,
+                       // and thus not all browsers (e.g. Mozilla versions dating back to at
+                       // least 2003) respect this. 
+                       usort($unsorted, array(&$this, '_sortWords'));
+                       $j = 0;
+                       // because there are "protected" words in the list
+                       //  we must add the sorted words around them
+                       do {
+                               if (!isset($_sorted[$i]))
+                                       $_sorted[$i] = substr($unsorted[$j++], 1);
+                               $_encoded[$_sorted[$i]] = $values[$i];
+                       } while (++$i < count($unsorted));
+               }
+               return array(
+                       'sorted'  => $_sorted,
+                       'encoded' => $_encoded,
+                       'protected' => $_protected);
+       }
+       
+       var $_count = array();
+// http://doc.spip.org/@_sortWords
+       function _sortWords($match1, $match2) {
+               return $this->_count[$match2] - $this->_count[$match1];
+       }
+       
+       // build the boot function used for loading and decoding
+// http://doc.spip.org/@_bootStrap
+       function _bootStrap($packed, $keywords) {
+               $ENCODE = $this->_safeRegExp('$encode\\($count\\)');
+
+               // $packed: the packed script
+               $packed = "'" . $this->_escape($packed) . "'";
+
+               // $ascii: base for encoding
+               $ascii = min(count($keywords['sorted']), $this->_encoding);
+               if ($ascii == 0) $ascii = 1;
+
+               // $count: number of words contained in the script
+               $count = count($keywords['sorted']);
+
+               // $keywords: list of words contained in the script
+               foreach ($keywords['protected'] as $i=>$value) {
+                       $keywords['sorted'][$i] = '';
+               }
+               // convert from a string to an array
+               ksort($keywords['sorted']);
+               $keywords = "'" . implode('|',$keywords['sorted']) . "'.split('|')";
+
+               $encode = ($this->_encoding > 62) ? '_encode95' : $this->_getEncoder($ascii);
+               $encode = $this->_getJSFunction($encode);
+               $encode = preg_replace('/_encoding/','$ascii', $encode);
+               $encode = preg_replace('/arguments\\.callee/','$encode', $encode);
+               $inline = '\\$count' . ($ascii > 10 ? '.toString(\\$ascii)' : '');
+
+               // $decode: code snippet to speed up decoding
+               if ($this->_fastDecode) {
+                       // create the decoder
+                       $decode = $this->_getJSFunction('_decodeBody');
+                       if ($this->_encoding > 62)
+                               $decode = preg_replace('/\\\\w/', '[\\xa1-\\xff]', $decode);
+                       // perform the encoding inline for lower ascii values
+                       elseif ($ascii < 36)
+                               $decode = preg_replace($ENCODE, $inline, $decode);
+                       // special case: when $count==0 there are no keywords. I want to keep
+                       //  the basic shape of the unpacking funcion so i'll frig the code...
+                       if ($count == 0)
+                               $decode = preg_replace($this->_safeRegExp('($count)\\s*=\\s*1'), '$1=0', $decode, 1);
+               }
+
+               // boot function
+               $unpack = $this->_getJSFunction('_unpack');
+               if ($this->_fastDecode) {
+                       // insert the decoder
+                       $this->buffer = $decode;
+                       $unpack = preg_replace_callback('/\\{/', array(&$this, '_insertFastDecode'), $unpack, 1);
+               }
+               $unpack = preg_replace('/"/', "'", $unpack);
+               if ($this->_encoding > 62) { // high-ascii
+                       // get rid of the word-boundaries for regexp matches
+                       $unpack = preg_replace('/\'\\\\\\\\b\'\s*\\+|\\+\s*\'\\\\\\\\b\'/', '', $unpack);
+               }
+               if ($ascii > 36 || $this->_encoding > 62 || $this->_fastDecode) {
+                       // insert the encode function
+                       $this->buffer = $encode;
+                       $unpack = preg_replace_callback('/\\{/', array(&$this, '_insertFastEncode'), $unpack, 1);
+               } else {
+                       // perform the encoding inline
+                       $unpack = preg_replace($ENCODE, $inline, $unpack);
+               }
+               // pack the boot function too
+               $unpackPacker = new JavaScriptPacker($unpack, 0, false, true);
+               $unpack = $unpackPacker->pack();
+               
+               // arguments
+               $params = array($packed, $ascii, $count, $keywords);
+               if ($this->_fastDecode) {
+                       $params[] = 0;
+                       $params[] = '{}';
+               }
+               $params = implode(',', $params);
+               
+               // the whole thing
+               return 'eval(' . $unpack . '(' . $params . "))\n";
+       }
+       
+       var $buffer;
+// http://doc.spip.org/@_insertFastDecode
+       function _insertFastDecode($match) {
+               return '{' . $this->buffer . ';';
+       }
+// http://doc.spip.org/@_insertFastEncode
+       function _insertFastEncode($match) {
+               return '{$encode=' . $this->buffer . ';';
+       }
+       
+       // mmm.. ..which one do i need ??
+// http://doc.spip.org/@_getEncoder
+       function _getEncoder($ascii) {
+               return $ascii > 10 ? $ascii > 36 ? $ascii > 62 ?
+                      '_encode95' : '_encode62' : '_encode36' : '_encode10';
+       }
+       
+       // zero encoding
+       // characters: 0123456789
+// http://doc.spip.org/@_encode10
+       function _encode10($charCode) {
+               return $charCode;
+       }
+       
+       // inherent base36 support
+       // characters: 0123456789abcdefghijklmnopqrstuvwxyz
+// http://doc.spip.org/@_encode36
+       function _encode36($charCode) {
+               return base_convert($charCode, 10, 36);
+       }
+       
+       // hitch a ride on base36 and add the upper case alpha characters
+       // characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+// http://doc.spip.org/@_encode62
+       function _encode62($charCode) {
+               $res = '';
+               if ($charCode >= $this->_encoding) {
+                       $res = $this->_encode62((int)($charCode / $this->_encoding));
+               }
+               $charCode = $charCode % $this->_encoding;
+               
+               if ($charCode > 35)
+                       return $res . chr($charCode + 29);
+               else
+                       return $res . base_convert($charCode, 10, 36);
+       }
+       
+       // use high-ascii values
+       // characters: Â¡Â¢Â£Â¤Â¥Â¦Â§Â¨Â©ÂªÂ«Â¬Â­Â®Â¯Â°Â±Â²Â³Â´ÂµÂ¶Â·Â¸Â¹ÂºÂ»Â¼Â½Â¾Â¿Ã\80Ã?Ã\82Ã\83Ã\84Ã\85Ã\86Ã\87Ã\88Ã\89Ã\8aÃ\8bÃ\8cÃ?Ã\8eÃ?Ã?Ã\91Ã\92Ã\93Ã\94Ã\95Ã\96Ã\97Ã\98Ã\99Ã\9aÃ\9bÃ\9cÃ?Ã\9eÃ\9fàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ
+// http://doc.spip.org/@_encode95
+       function _encode95($charCode) {
+               $res = '';
+               if ($charCode >= $this->_encoding)
+                       $res = $this->_encode95($charCode / $this->_encoding);
+               
+               return $res . chr(($charCode % $this->_encoding) + 161);
+       }
+       
+// http://doc.spip.org/@_safeRegExp
+       function _safeRegExp($string) {
+               return '/'.preg_replace('/\$/', '\\\$', $string).'/';
+       }
+       
+// http://doc.spip.org/@_encodePrivate
+       function _encodePrivate($charCode) {
+               return "_" . $charCode;
+       }
+       
+       // protect characters used by the parser
+// http://doc.spip.org/@_escape
+       function _escape($script) {
+               return preg_replace('/([\\\\\'])/', '\\\$1', $script);
+       }
+       
+       // protect high-ascii characters already in the script
+// http://doc.spip.org/@_escape95
+       function _escape95($script) {
+               return preg_replace_callback(
+                       '/[\\xa1-\\xff]/',
+                       array(&$this, '_escape95Bis'),
+                       $script
+               );
+       }
+// http://doc.spip.org/@_escape95Bis
+       function _escape95Bis($match) {
+               return '\x'.((string)dechex(ord($match)));
+       }
+       
+       
+// http://doc.spip.org/@_getJSFunction
+       function _getJSFunction($aName) {
+               $func = 'JSFUNCTION'.$aName;
+               if (isset($this->$func)){
+                       return $this->$func;
+               }
+               else 
+                       return '';
+       }
+       
+       // JavaScript Functions used.
+       // Note : In Dean's version, these functions are converted
+       // with 'String(aFunctionName);'.
+       // This internal conversion complete the original code, ex :
+       // 'while (aBool) anAction();' is converted to
+       // 'while (aBool) { anAction(); }'.
+       // The JavaScript functions below are corrected.
+       
+       // unpacking function - this is the boot strap function
+       //  data extracted from this packing routine is passed to
+       //  this function when decoded in the target
+       // NOTE ! : without the ';' final.
+       var $JSFUNCTION_unpack = 'function($packed, $ascii, $count, $keywords, $encode, $decode) {
+    while ($count--) {
+        if ($keywords[$count]) {
+            $packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]);
+        }
+    }
+    return $packed;
+}';
+/*
+'function($packed, $ascii, $count, $keywords, $encode, $decode) {
+    while ($count--)
+        if ($keywords[$count])
+            $packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]);
+    return $packed;
+}';
+*/
+       
+       // code-snippet inserted into the unpacker to speed up decoding
+       var $JSFUNCTION_decodeBody = '    if (!\'\'.replace(/^/, String)) {
+        // decode all the values we need
+        while ($count--) {
+            $decode[$encode($count)] = $keywords[$count] || $encode($count);
+        }
+        // global replacement function
+        $keywords = [function ($encoded) {return $decode[$encoded]}];
+        // generic match
+        $encode = function () {return \'\\\\w+\'};
+        // reset the loop counter -  we are now doing a global replace
+        $count = 1;
+    }
+';
+//};
+/*
+'      if (!\'\'.replace(/^/, String)) {
+        // decode all the values we need
+        while ($count--) $decode[$encode($count)] = $keywords[$count] || $encode($count);
+        // global replacement function
+        $keywords = [function ($encoded) {return $decode[$encoded]}];
+        // generic match
+        $encode = function () {return\'\\\\w+\'};
+        // reset the loop counter -  we are now doing a global replace
+        $count = 1;
+    }';
+*/
+       
+        // zero encoding
+        // characters: 0123456789
+        var $JSFUNCTION_encode10 = 'function($charCode) {
+    return $charCode;
+}';//;';
+       
+        // inherent base36 support
+        // characters: 0123456789abcdefghijklmnopqrstuvwxyz
+        var $JSFUNCTION_encode36 = 'function($charCode) {
+    return $charCode.toString(36);
+}';//;';
+       
+       // hitch a ride on base36 and add the upper case alpha characters
+       // characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+       var $JSFUNCTION_encode62 = 'function($charCode) {
+    return ($charCode < _encoding ? \'\' : arguments.callee(parseInt($charCode / _encoding))) +
+    (($charCode = $charCode % _encoding) > 35 ? String.fromCharCode($charCode + 29) : $charCode.toString(36));
+}';
+       
+       // use high-ascii values
+       // characters: Â¡Â¢Â£Â¤Â¥Â¦Â§Â¨Â©ÂªÂ«Â¬Â­Â®Â¯Â°Â±Â²Â³Â´ÂµÂ¶Â·Â¸Â¹ÂºÂ»Â¼Â½Â¾Â¿Ã\80Ã?Ã\82Ã\83Ã\84Ã\85Ã\86Ã\87Ã\88Ã\89Ã\8aÃ\8bÃ\8cÃ?Ã\8eÃ?Ã?Ã\91Ã\92Ã\93Ã\94Ã\95Ã\96Ã\97Ã\98Ã\99Ã\9aÃ\9bÃ\9cÃ?Ã\9eÃ\9fàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ
+       var $JSFUNCTION_encode95 = 'function($charCode) {
+    return ($charCode < _encoding ? \'\' : arguments.callee($charCode / _encoding)) +
+        String.fromCharCode($charCode % _encoding + 161);
+}'; 
+       
+}
+
+
+class ParseMaster {
+       var $ignoreCase = false;
+       var $escapeChar = '';
+       
+       // constants
+       var $EXPRESSION = 0;
+       var $REPLACEMENT = 1;
+       var $LENGTH = 2;
+       
+       // used to determine nesting levels
+       var $GROUPS = '/\\(/';//g
+       var $SUB_REPLACE = '/\\$\\d/';
+       var $INDEXED = '/^\\$\\d+$/';
+       var $TRIM = '/([\'"])\\1\\.(.*)\\.\\1\\1$/';
+       var $ESCAPE = '/\\\./';//g
+       var $QUOTE = '/\'/';
+       var $DELETED = '/\\x01[^\\x01]*\\x01/';//g
+       
+// http://doc.spip.org/@add
+       function add($expression, $replacement = '') {
+               // count the number of sub-expressions
+               //  - add one because each pattern is itself a sub-expression
+               $length = 1 + preg_match_all($this->GROUPS, $this->_internalEscape((string)$expression), $out);
+               
+               // treat only strings $replacement
+               if (is_string($replacement)) {
+                       // does the pattern deal with sub-expressions?
+                       if (preg_match($this->SUB_REPLACE, $replacement)) {
+                               // a simple lookup? (e.g. "$2")
+                               if (preg_match($this->INDEXED, $replacement)) {
+                                       // store the index (used for fast retrieval of matched strings)
+                                       $replacement = (int)(substr($replacement, 1)) - 1;
+                               } else { // a complicated lookup (e.g. "Hello $2 $1")
+                                       // build a function to do the lookup
+                                       $quote = preg_match($this->QUOTE, $this->_internalEscape($replacement))
+                                                ? '"' : "'";
+                                       $replacement = array(
+                                               'fn' => '_backReferences',
+                                               'data' => array(
+                                                       'replacement' => $replacement,
+                                                       'length' => $length,
+                                                       'quote' => $quote
+                                               )
+                                       );
+                               }
+                       }
+               }
+               // pass the modified arguments
+               if (!empty($expression)) $this->_add($expression, $replacement, $length);
+               else $this->_add('/^$/', $replacement, $length);
+       }
+       
+// http://doc.spip.org/@exec
+       function exec($string) {
+               // execute the global replacement
+               $this->_escaped = array();
+               
+               // simulate the _patterns.toSTring of Dean
+               $regexp = '/';
+               foreach ($this->_patterns as $reg) {
+                       $regexp .= '(' . substr($reg[$this->EXPRESSION], 1, -1) . ')|';
+               }
+               $regexp = substr($regexp, 0, -1) . '/';
+               $regexp .= ($this->ignoreCase) ? 'i' : '';
+               
+               $string = $this->_escape($string, $this->escapeChar);
+               $string = preg_replace_callback(
+                       $regexp,
+                       array(
+                               &$this,
+                               '_replacement'
+                       ),
+                       $string
+               );
+               $string = $this->_unescape($string, $this->escapeChar);
+               
+               return preg_replace($this->DELETED, '', $string);
+       }
+               
+// http://doc.spip.org/@reset
+       function reset() {
+               // clear the patterns collection so that this object may be re-used
+               $this->_patterns = array();
+       }
+
+       // private
+       var $_escaped = array();  // escaped characters
+       var $_patterns = array(); // patterns stored by index
+       
+       // create and add a new pattern to the patterns collection
+// http://doc.spip.org/@_add
+       function _add() {
+               $arguments = func_get_args();
+               $this->_patterns[] = $arguments;
+       }
+       
+       // this is the global replace function (it's quite complicated)
+// http://doc.spip.org/@_replacement
+       function _replacement($arguments) {
+               if (empty($arguments)) return '';
+               
+               $i = 1; $j = 0;
+               // loop through the patterns
+               while (isset($this->_patterns[$j])) {
+                       $pattern = $this->_patterns[$j++];
+                       // do we have a result?
+                       if (isset($arguments[$i]) && ($arguments[$i] != '')) {
+                               $replacement = $pattern[$this->REPLACEMENT];
+                               
+                               if (is_array($replacement) && isset($replacement['fn'])) {
+                                       
+                                       if (isset($replacement['data'])) $this->buffer = $replacement['data'];
+                                       return call_user_func(array(&$this, $replacement['fn']), $arguments, $i);
+                                       
+                               } elseif (is_int($replacement)) {
+                                       return $arguments[$replacement + $i];
+                               
+                               }
+                               $delete = ($this->escapeChar == '' ||
+                                          strpos($arguments[$i], $this->escapeChar) === false)
+                                       ? '' : "\x01" . $arguments[$i] . "\x01";
+                               return $delete . $replacement;
+                       
+                       // skip over references to sub-expressions
+                       } else {
+                               $i += $pattern[$this->LENGTH];
+                       }
+               }
+       }
+       
+// http://doc.spip.org/@_backReferences
+       function _backReferences($match, $offset) {
+               $replacement = $this->buffer['replacement'];
+               $quote = $this->buffer['quote'];
+               $i = $this->buffer['length'];
+               while ($i) {
+                       $replacement = str_replace('$'.$i--, $match[$offset + $i], $replacement);
+               }
+               return $replacement;
+       }
+       
+// http://doc.spip.org/@_replace_name
+       function _replace_name($match, $offset){
+               $length = strlen($match[$offset + 2]);
+               $start = $length - max($length - strlen($match[$offset + 3]), 0);
+               return substr($match[$offset + 1], $start, $length) . $match[$offset + 4];
+       }
+       
+// http://doc.spip.org/@_replace_encoded
+       function _replace_encoded($match, $offset) {
+               return $this->buffer[$match[$offset]];
+       }
+       
+       
+       // php : we cannot pass additional data to preg_replace_callback,
+       // and we cannot use &$this in create_function, so let's go to lower level
+       var $buffer;
+       
+       // encode escaped characters
+// http://doc.spip.org/@_escape
+       function _escape($string, $escapeChar) {
+               if ($escapeChar) {
+                       $this->buffer = $escapeChar;
+                       return preg_replace_callback(
+                               '/\\' . $escapeChar . '(.)' .'/',
+                               array(&$this, '_escapeBis'),
+                               $string
+                       );
+                       
+               } else {
+                       return $string;
+               }
+       }
+// http://doc.spip.org/@_escapeBis
+       function _escapeBis($match) {
+               $this->_escaped[] = $match[1];
+               return $this->buffer;
+       }
+       
+       // decode escaped characters
+// http://doc.spip.org/@_unescape
+       function _unescape($string, $escapeChar) {
+               if ($escapeChar) {
+                       $regexp = '/'.'\\'.$escapeChar.'/';
+                       $this->buffer = array('escapeChar'=> $escapeChar, 'i' => 0);
+                       return preg_replace_callback
+                       (
+                               $regexp,
+                               array(&$this, '_unescapeBis'),
+                               $string
+                       );
+                       
+               } else {
+                       return $string;
+               }
+       }
+// http://doc.spip.org/@_unescapeBis
+       function _unescapeBis() {
+               if (!empty($this->_escaped[$this->buffer['i']])) {
+                        $temp = $this->_escaped[$this->buffer['i']];
+               } else {
+                       $temp = '';
+               }
+               $this->buffer['i']++;
+               return $this->buffer['escapeChar'] . $temp;
+       }
+       
+// http://doc.spip.org/@_internalEscape
+       function _internalEscape($string) {
+               return preg_replace($this->ESCAPE, '', $string);
+       }
+}
+?>
diff --git a/www/plugins/crayons/modeles/uploader_item.html b/www/plugins/crayons/modeles/uploader_item.html
new file mode 100644 (file)
index 0000000..2130b72
--- /dev/null
@@ -0,0 +1,4 @@
+#ENV{erreur}
+<BOUCLE_d(DOCUMENTS){tous}{id_document}>
+&lt;doc#ID_DOCUMENT&gt; #TITRE - [(#LOGO_DOCUMENT|liens_absolus)]
+</BOUCLE_d>
diff --git a/www/plugins/crayons/modeles/uploader_liste.html b/www/plugins/crayons/modeles/uploader_liste.html
new file mode 100644 (file)
index 0000000..4a11ae5
--- /dev/null
@@ -0,0 +1,112 @@
+<style>
+.uploader {border:solid red 1px;}
+.uploader.hover {border:dotted red 1px;}
+.uploader li {border solid transparent 3px; padding-left:10px}
+.uploader li.loading {border:dotted red 3px;}
+.uploader li.ok {border:solid green 3px;}
+
+#uploader#ID_ARTICLE {
+       position: absolute;
+       top: 10px;
+       right: -180px;
+       width: 170px;
+       height: 100%;
+       max-height: 600px;
+       overflow: auto;
+       overflow-x: hidden;
+       background: #eee;
+       border: solid #ccc 1px;
+}
+
+#uploader#ID_ARTICLE.ferme {
+       width: 30px; height: 15px; overflow-x:hide;overflow-y:hide;overflow:hide;
+}
+</style>
+
+
+<div id="uploader#ID_ARTICLE" class="ferme">
+<i>Glissez un document ou une image dans cette zone pour l'ajouter à l'article.</i>
+
+<ul id="uploader_liste" >
+<BOUCLE_d(DOCUMENTS){tous}{id_article}{!par id_document}{0,10}>
+<li>#MODELE{uploader_item,id_document}</li>
+</BOUCLE_d>
+[<li class="pagination">(#PAGINATION)</li>]
+</B_d>
+</ul>
+
+
+</div>
+
+<!--
+/*
+
+$(function(){
+       var fileTemplate="<div id=\"{{id}}\">";
+       fileTemplate+="<div class=\"progressbar\"></div>";
+       fileTemplate+="<div class=\"preview\"></div>";
+       fileTemplate+="<div class=\"filename\">{{filename}}</div>";
+       fileTemplate+="</div>";
+       function slugify(text){
+               text=text.replace(/[^-a-zA-Z0-9,&\s]+/ig,'');
+               text=text.replace(/-/gi,"_");
+               text=text.replace(/\s/gi,"-");
+               return text;
+       }
+
+       $("#dropbox")
+       .html5Uploader({
+               onClientLoadStart:function(e,file){
+                       var upload=$("#upload");
+                       if(upload.is(":hidden")){
+                               upload.show();
+                       }
+                       upload.append(
+                               fileTemplate
+                                       .replace(/{{id}}/g, slugify(file.name))
+                                       .replace(/{{filename}}/g,file.name)
+                       );
+               },
+               onClientLoad:function(e,file){
+                       $("#"+slugify(file.name))
+                       .find(".preview")
+                       .append("<img src=\""+e.target.result+"\" alt=\"\">");
+               },
+               onServerLoadStart:function(e,file){
+                       $("#"+slugify(file.name))
+                       .find(".progressbar")
+                       .progressbar({value:0});
+               },
+               onServerProgress:function(e,file){
+                       if(e.lengthComputable){
+                               var percentComplete=(e.loaded/e.total)*100;
+                               $("#"+slugify(file.name))
+                               .find(".progressbar")
+                                       .progressbar({value:percentComplete});
+                       }
+               },
+               onServerLoad:function(e,file){
+                       $("#"+slugify(file.name))
+                       .find(".progressbar")
+                               .progressbar({value:100});
+               }
+       });
+
+       $(".download")
+       .mousedown(function(){
+               $(this).css({
+                       "background-image":"url('images/download-clicked.png')"
+               });
+       })
+       .mouseup(function(){
+               $(this).css({
+                       "background-image":"url('images/download.png')"
+               });
+       });
+
+
+});
+
+
+*/
+-->
\ No newline at end of file
diff --git a/www/plugins/crayons/paquet.xml b/www/plugins/crayons/paquet.xml
new file mode 100644 (file)
index 0000000..df6437f
--- /dev/null
@@ -0,0 +1,21 @@
+<paquet\r
+       prefix="crayons"\r
+       categorie="edition"\r
+       version="1.16.1"\r
+       etat="stable"\r
+       compatibilite="[1.9.0;*]"\r
+       logo="images/crayon-32.png"\r
+       documentation="http://www.spip-contrib.net/Les-Crayons"\r
+>\r
+       <nom>Crayons</nom>\r
+       \r
+       <auteur>Fil</auteur>\r
+       <auteur>toggg</auteur>\r
+       \r
+       <licence>GNU/GPL</licence>\r
+\r
+       <traduire gestionnaire="salvatore" module="crayons" reference="fr" />\r
+       \r
+       <pipeline nom="affichage_final" inclure="crayons_fonctions.php" />\r
+       <pipeline nom="header_prive" inclure="crayons_fonctions.php" action="insert_head" />\r
+</paquet>\r
diff --git a/www/plugins/crayons/plugin.xml b/www/plugins/crayons/plugin.xml
new file mode 100644 (file)
index 0000000..33c1c67
--- /dev/null
@@ -0,0 +1,59 @@
+<plugin>\r
+       <nom>\r
+       <multi>\r
+       Crayons\r
+       [ar]&#1575;&#1604;&#1602;&#1604;&#1605;\r
+       [it]Pennarelli\r
+       [de]Der Stift\r
+       [en]Pencils\r
+       [ru]Карандаш\r
+       </multi>\r
+       </nom>\r
+       <auteur>\r
+       Fil, toggg\r
+       </auteur>\r
+       <licence>\r
+               &#169; 2006-2013 - GNU/GPL\r
+       </licence>\r
+       <version>\r
+       1.16.1\r
+       </version>\r
+       <etat>\r
+       stable\r
+       </etat>\r
+       <description>\r
+       <multi>\r
+       &#201;dition rapide depuis les pages publiques du site.\r
+       [it] Modifica rapida dalle pagine pubbliche del sito.\r
+       [ar]&#1607;&#1584;&#1575; &#1575;&#1604;&#1605;&#1604;&#1581;&#1602;&#1548; {{&#1575;&#1604;&#1605;&#1578;&#1608;&#1575;&#1601;&#1585; &#1604;&#1604;&#1575;&#1589;&#1583;&#1575;&#1585; &#1633;.&#1641;.&#1634; &#1601;&#1602;&#1591;}} &#1610;&#1602;&#1583;&#1605; &#1608;&#1592;&#1575;&#1574;&#1601; &#1578;&#1581;&#1585;&#1610;&#1585; &#1587;&#1585;&#1610;&#1593;&#1577; &#1605;&#1606; &#1601;&#1610; &#1589;&#1601;&#1581;&#1575;&#1578; &#1575;&#1604;&#1605;&#1608;&#1602;&#1593; &#1575;&#1604;&#1593;&#1605;&#1608;&#1605;&#1610;. &#1604;&#1604;&#1575;&#1587;&#1578;&#1601;&#1575;&#1583;&#1577; &#1605;&#1606;&#1607; &#1610;&#1580;&#1576; &#1575;&#1606;&#1588;&#1575;&#1569; &#1589;&#1601;&#1581;&#1575;&#1578; &#1606;&#1605;&#1608;&#1584;&#1580;&#1610;&#1577; &#1605;&#1578;&#1608;&#1575;&#1601;&#1602;&#1577; &#1605;&#1593;&#1607;.\r
+\r
+&#1603;&#1605;&#1575; &#1601;&#1610; &#1589;&#1601;&#1581;&#1575;&#1578; &#1575;&#1604;&#1575;&#1589;&#1583;&#1575;&#1585; 1.9.2 &#1575;&#1604;&#1606;&#1605;&#1608;&#1584;&#1580;&#1610;&#1577; &#1610;&#1603;&#1601;&#1610; &#1575;&#1583;&#1582;&#1575;&#1604; &#1593;&#1604;&#1575;&#1605;&#1577; {#EDIT} &#1601;&#1610; &#1603;&#1604; &#1605;&#1603;&#1575;&#1606; &#1606;&#1585;&#1610;&#1583; &#1578;&#1581;&#1585;&#1610;&#1585;&#1607;. &#1605;&#1579;&#1604;&#1575;&#1611;&#1548; &#1604;&#1610;&#1589;&#1576;&#1581; &#1575;&#1604;&#1593;&#1606;&#1608;&#1575;&#1606; &#1602;&#1575;&#1576;&#1604; &#1604;&#1604;&#1578;&#1581;&#1585;&#1610;&#1585;:\r
+_ <code><h1 class="#EDIT{titre} &#1593;&#1604;&#1575;&#1605;&#1575;&#1578; &#1575;&#1582;&#1585;&#1609;">#TITRE</h1></code>.\r
+       [de]&#196;nderungen in &#246;ffentlichen Seiten direkt erledigen, Vorausetzung f&#252;r Wikis mit SPIP\r
+       [en]Quick editing from the public pages of the site.\r
+       [ru]Позволяет редактировать информацию прямо на сайте, не заходя в административную часть.\r
+       </multi>\r
+       </description>\r
+       <lien>http://www.spip-contrib.net/Les-Crayons</lien>\r
+       <prefix>\r
+       Crayons\r
+       </prefix>\r
+       <icon>\r
+       images/crayon-128.png\r
+       </icon>\r
+       <fonctions>crayons_fonctions.php</fonctions>\r
+       <pipeline>\r
+               <nom>affichage_final</nom>\r
+               <inclure>crayons_fonctions.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>header_prive</nom>\r
+               <action>insert_head</action>\r
+               <inclure>crayons_fonctions.php</inclure>\r
+       </pipeline>\r
+       <chemin dir='' />\r
+       <categorie>edition</categorie>\r
+       <necessite id="SPIP" version="[1.9.0;3.0.0]" />\r
+       <!-- utilise id="cfg" version="[1.14.1;]" / -->\r
+       <traduire gestionnaire="salvatore" module="crayons" reference="fr" />\r
+</plugin>\r
diff --git a/www/plugins/crayons/prive/squelettes/contenu/configurer_crayons.html b/www/plugins/crayons/prive/squelettes/contenu/configurer_crayons.html
new file mode 100644 (file)
index 0000000..14a7388
--- /dev/null
@@ -0,0 +1,5 @@
+#CACHE{0}\r
+[(#AUTORISER{configurer}|sinon_interdire_acces)]\r
+<div class="ajax">\r
+#FORMULAIRE_CONFIGURER_CRAYONS\r
+</div>\r
diff --git a/www/plugins/crayons/svn.revision b/www/plugins/crayons/svn.revision
new file mode 100644 (file)
index 0000000..7ffcffa
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/crayons
+Revision: 73111
+Dernier commit: 2013-05-31 10:42:21 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/crayons</origine>
+<revision>73111</revision>
+<commit>2013-05-31 10:42:21 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/crayons/tetecrayons.php b/www/plugins/crayons/tetecrayons.php
new file mode 100644 (file)
index 0000000..ffa6c8a
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// Compatibilite eventuelle pour les plugins.
+// Ce fichier est normallement inutile.
+
+include_spip('crayons_fonctions');
+
+?>
diff --git a/www/plugins/crayons/vues/article_intro.html b/www/plugins/crayons/vues/article_intro.html
new file mode 100644 (file)
index 0000000..f9fcdbf
--- /dev/null
@@ -0,0 +1,9 @@
+[(#REM)
+
+       Vue pour le crayon 'article_intro'
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+#INTRODUCTION
+</BOUCLE_a>
diff --git a/www/plugins/crayons/vues/article_intro2.html b/www/plugins/crayons/vues/article_intro2.html
new file mode 100644 (file)
index 0000000..9e62a1f
--- /dev/null
@@ -0,0 +1,9 @@
+[(#REM)
+
+       Vue pour le crayon 'article_intro3'
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+#INTRODUCTION
+</BOUCLE_a>
diff --git a/www/plugins/crayons/vues/article_intro3.html b/www/plugins/crayons/vues/article_intro3.html
new file mode 100644 (file)
index 0000000..9e62a1f
--- /dev/null
@@ -0,0 +1,9 @@
+[(#REM)
+
+       Vue pour le crayon 'article_intro3'
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+#INTRODUCTION
+</BOUCLE_a>
diff --git a/www/plugins/crayons/vues/article_introduction.html b/www/plugins/crayons/vues/article_introduction.html
new file mode 100644 (file)
index 0000000..d5ae81e
--- /dev/null
@@ -0,0 +1,9 @@
+[(#REM)
+
+       Vue pour le crayon 'article_introduction'
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+#INTRODUCTION
+</BOUCLE_a>
diff --git a/www/plugins/crayons/vues/article_texte.html b/www/plugins/crayons/vues/article_texte.html
new file mode 100644 (file)
index 0000000..5262113
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM)
+
+       Vue pour le crayon 'article_texte'
+
+       Juste pour le bonheur de tester les limites : la classe
+       imagereduire.NNN associee a #EDIT{texte} provoque l'application
+       du filtre |image_reduire{NNN,0}
+
+]
+#CACHE{0}
+
+[(#REM) met dans la variable r la valeur de la class ]
+[(#SET{r,[(#ENV{class}|match{\bimagereduire\.\d+\b}|match{\b\d+\b})]})]
+
+<BOUCLE_a(ARTICLES){id_article}{statut==.}>
+[(#GET{r}|?{
+       [(#TEXTE|image_reduire{#GET{r},0})]
+,
+       [(#TEXTE|image_reduire{500,0})]
+})]
+</BOUCLE_a>
+
+[<small>(#NOTES)</small>]
diff --git a/www/plugins/crayons/vues/document_fichier.html b/www/plugins/crayons/vues/document_fichier.html
new file mode 100644 (file)
index 0000000..163d7f3
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Vue pour le controleur de document
+
+]
+
+<BOUCLE_d(DOCUMENTS){id_document}>
+
+[(#VAL{<img}|concat{#ID_DOCUMENT}|concat{>}|propre)]
+
+</BOUCLE_d>
\ No newline at end of file
diff --git a/www/plugins/crayons/vues/extra.html b/www/plugins/crayons/vues/extra.html
new file mode 100644 (file)
index 0000000..4e80b8f
--- /dev/null
@@ -0,0 +1,31 @@
+[(#REM)
+
+       Vue pour le crayon 'extra'
+
+]
+#CACHE{0}
+
+<BOUCLE_a(AUTEURS){id_auteur}{tous}>
+[(#EXTRA**|extra_affichage{auteurs})]
+</BOUCLE_a>
+
+<BOUCLE_b(ARTICLES){id_article}{statut==.}>
+[(#EXTRA**|extra_affichage{articles})]
+</BOUCLE_b>
+
+<BOUCLE_c(BREVES){id_breve}{statut==.}>
+[(#EXTRA**|extra_affichage{breves})]
+</BOUCLE_c>
+
+<BOUCLE_d(RUBRIQUES){id_rubrique}{statut==.}>
+[(#EXTRA**|extra_affichage{rubriques})]
+</BOUCLE_d>
+
+<BOUCLE_e(SITES){id_syndic=#ENV{id_site}}{statut==.}>
+[(#EXTRA**|extra_affichage{sites})]
+</BOUCLE_e>
+
+<//B_d>
+<//B_c>
+<//B_b>
+<//B_a>
diff --git a/www/plugins/crayons/vues/extra_fonctions.php b/www/plugins/crayons/vues/extra_fonctions.php
new file mode 100644 (file)
index 0000000..9dacf6e
--- /dev/null
@@ -0,0 +1,7 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+       include_spip('inc/extra');
+       include_spip('inc/presentation');
+
+?>
\ No newline at end of file
diff --git a/www/plugins/crayons/vues/hyperlien.html b/www/plugins/crayons/vues/hyperlien.html
new file mode 100644 (file)
index 0000000..2c1d352
--- /dev/null
@@ -0,0 +1,30 @@
+[(#REM)
+
+       Vue pour le crayon 'hyperlien'
+
+]
+#CACHE{0}
+
+[(#REM) Cas general ]
+#SET{titre,#ENV*{nom_site}}
+#SET{url,#ENV*{url_site}}
+
+[(#REM) syndic-article ]
+[(#ENV{id_syndic_article}|?{
+       [(#SET{titre,#ENV*{titre}})]
+       [(#SET{url,#ENV*{url}})]
+})]
+
+[(#REM) breve ]
+[(#ENV{id_breve}|?{
+       [(#SET{titre,#ENV*{lien_titre}})]
+       [(#SET{url,#ENV*{lien_url}})]
+})]
+
+[(#ENV{id_article}|?{' '})<:voir_en_ligne:>&nbsp;:]
+
+[(#GET{url}|?{
+       <a href="[(#GET{url})]" class="spip_out">[(#GET{titre}|typo|sinon{[(#GET{url}|couper{80})]})]</a>
+,
+       [(#GET{titre}|typo|sinon{<:info_sans_titre:>})]
+})]
\ No newline at end of file
diff --git a/www/plugins/crayons/vues/id_parent.html b/www/plugins/crayons/vues/id_parent.html
new file mode 100644 (file)
index 0000000..046d205
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM)
+
+       Vue pour le crayon id_parent
+       Cf. controleurs/id_parent.html
+
+       nb: teste sur les articles uniquement
+]
+
+<BOUCLE_r(RUBRIQUES){id_rubrique=#ENV{id_rubrique}}>
+#TITRE
+</BOUCLE_r>
diff --git a/www/plugins/crayons/vues/logo.html b/www/plugins/crayons/vues/logo.html
new file mode 100644 (file)
index 0000000..57183f2
--- /dev/null
@@ -0,0 +1,37 @@
+[(#REM)
+
+       Vue du logo qu'on vient d'uploader
+
+       On doit hacker l'url du logo avec sa date pour eviter le cache du navigateur
+
+]
+
+[(#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})]}
+       |sinon{[(#ID_SYNDIC_ARTICLE|?{#LOGO_SYNDIC_ARTICLE_NORMAL})]}
+       |sinon{[(#ID_SYNDIC|?{#LOGO_SITE_NORMAL})]}
+       |sinon{[(#ID_MOT|?{#LOGO_MOT_NORMAL})]})]})]
+
+
+[(#REM) Si la class contient resize-XXX, on appliquera ce filtre au logo ]
+
+[(#SET{resize,[(#ENV{class}|match{\bresize-\d+\b}|replace{resize-})]})]
+
+
+[(#GET{image}|?{
+
+       [(#SET{logo,[(#GET{image}
+               |image_reduire{#GET{resize,0},#GET{resize,120}})]})]
+       [(#SET{url,[(#GET{logo}|extraire_attribut{src}|replace{\?.*$})]})]
+       [(#SET{url,[(#GET{url}|parametre_url{s,#EVAL{time()}})]})]
+       [(#SET{width,[(#GET{logo}|extraire_attribut{width})]})]
+
+       [(#GET{logo}|inserer_attribut{src,#GET{url}})]
+
+,
+       '<small><abbr title="logo">?</abbr></small>'
+})]
diff --git a/www/plugins/crayons/vues/mots_article_brut.html b/www/plugins/crayons/vues/mots_article_brut.html
new file mode 100644 (file)
index 0000000..4b0d461
--- /dev/null
@@ -0,0 +1,17 @@
+[(#REM)
+
+       Vue pour le crayon 'mots_article_brut'
+
+]
+#CACHE{0}
+<BOUCLE_a(ARTICLES){id_article}{lang}{statut==.}>
+<B_moex>
+<ul class="mots_article"><p>Mots-clé pour #TITRE (#ID_ARTICLE)</p>
+<BOUCLE_moex(MOTS){id_article}{doublons}>
+       <li class="#EDIT{id_mot} mots_article">#ID_GROUPE:#ID_MOT : [(#TITRE|entites_html)] </li>
+</BOUCLE_moex>
+</ul>
+</B_moex>
+<p>Pas de mot-clé existant</p>
+<//B_moex>
+</BOUCLE_a>
diff --git a/www/plugins/crayons/vues/qui.html b/www/plugins/crayons/vues/qui.html
new file mode 100644 (file)
index 0000000..a9b0b62
--- /dev/null
@@ -0,0 +1,21 @@
+[(#REM)
+
+       Vue pour le crayon 'qui'
+
+]
+#CACHE{0}
+
+<BOUCLE_a(AUTEURS){id_auteur}{tous}>
+[<a title="(#EMAIL|texte_backend)">][(#NOM|sinon{#EMAIL})][(#EMAIL|?{</a>})]
+</BOUCLE_a>
+
+<BOUCLE_c(SIGNATURES){id_signature}{statut==.}>
+[<a title="(#EMAIL|texte_backend)">][(#NOM|sinon{#EMAIL})][(#EMAIL|?{</a>})]
+</BOUCLE_c>
+
+<BOUCLE_d(FORUMS){id_forum}{statut==.}>
+[<a title="(#EMAIL|texte_backend)">][(#NOM|sinon{#EMAIL})][(#EMAIL|?{</a>})]
+</BOUCLE_d>
+
+<//B_c>
+<//B_a>
diff --git a/www/plugins/crayons/vues/rubrique_id_parent.html b/www/plugins/crayons/vues/rubrique_id_parent.html
new file mode 100644 (file)
index 0000000..bc18685
--- /dev/null
@@ -0,0 +1,5 @@
+
+<BOUCLE_parent(RUBRIQUES){id_rubrique=#ID_PARENT}>
+#TITRE
+</BOUCLE_parent>
+
diff --git a/www/plugins/crayons/vues/vignette.html b/www/plugins/crayons/vues/vignette.html
new file mode 100644 (file)
index 0000000..8d2225f
--- /dev/null
@@ -0,0 +1,18 @@
+[(#REM)
+
+       Vue pour le crayon 'vignette',
+       Ce crayons ne s'applique qu'aux documents
+
+]
+[(#SET{resize,[(#ENV{class}|match{\bresize-\d+\b}|replace{resize-})]})]
+
+[(#SET{image,[(#LOGO_DOCUMENT||image_reduire{#GET{resize,0},#GET{resize,120}})]})]
+
+[(#GET{image}|?{
+
+       [(#SET{url,[(#GET{image}|extraire_attribut{src}|replace{\?.*$})]})]
+       [(#SET{url,[(#GET{url}|parametre_url{s,#EVAL{time()}})]})]
+       [(#SET{width,[(#GET{image}|extraire_attribut{width})]})]
+
+       [(#GET{image}|inserer_attribut{src,#GET{url}})]
+})]
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/css/enluminurestypo.css b/www/plugins/enluminures_typographiques_v3/css/enluminurestypo.css
new file mode 100644 (file)
index 0000000..876c5b3
--- /dev/null
@@ -0,0 +1,50 @@
+.texteencadre-spip {\r
+       color: #000033;\r
+       background: #EEF;\r
+       border-bottom: 2px solid #0066CC;\r
+       border-left: 1px solid #3399FF;\r
+       border-right: 2px solid #0066CC;\r
+       border-top: 1px solid #3399FF;\r
+       margin: 1em 0;  \r
+       padding: .25em; \r
+       position: relative;\r
+}\r
+\r
+.caractencadre-spip {\r
+       color: #F60;\r
+       font-weight: bold;\r
+}\r
+\r
+.caractencadre2-spip {\r
+       color: #009;\r
+       font-weight: bold;\r
+}\r
+\r
+acronym.spip_acronym {\r
+       cursor: help;\r
+       border-bottom: 1px dotted;\r
+}\r
+\r
+/* ne marche pas sur MSIE, a refaire en jQuery */\r
+a[hreflang]:after {\r
+content: "\0000a0[" attr(hreflang) "]";\r
+color: #999;\r
+background: transparent;\r
+font-size:x-small;\r
+}\r
+\r
+sup, sup.typo_exposants {\r
+       font-size: 78%;\r
+       font-variant: normal;\r
+       vertical-align: 24%;\r
+}\r
+\r
+sub {\r
+       font-size: 60%;\r
+       font-variant: normal;\r
+       vertical-align: -20%;\r
+}\r
+\r
+.caps {\r
+       font-variant: small-caps;\r
+}
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/css/enluminurestypo_prive.css b/www/plugins/enluminures_typographiques_v3/css/enluminurestypo_prive.css
new file mode 100644 (file)
index 0000000..0bce269
--- /dev/null
@@ -0,0 +1,25 @@
+h2.spip, h3.spip, h4.spip, h5.spip, h6.spip {\r
+       border-left: 1px solid #ccd;\r
+    color: #666;\r
+       padding-left: 1em;\r
+       text-align: left;\r
+       margin-left: 15px;\r
+}\r
+h2.spip {\r
+    border-left-width: 16px;\r
+       margin-left: 0;\r
+}\r
+h3.spip {\r
+    border-left-width: 10px;\r
+       margin-left: 6px;\r
+}\r
+h4.spip {\r
+    border-left-width: 6px;\r
+       margin-left: 10px;\r
+}\r
+h5.spip {\r
+    border-left-width: 2px;\r
+       margin-left: 14px;\r
+}\r
+\r
+acronym, abbr { border-bottom: .1em dotted; cursor: help; }\r
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/inserer_colonne.gif b/www/plugins/enluminures_typographiques_v3/editeur/inserer_colonne.gif
new file mode 100644 (file)
index 0000000..b669d4f
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/editeur/inserer_colonne.gif differ
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/inserer_ligne.gif b/www/plugins/enluminures_typographiques_v3/editeur/inserer_ligne.gif
new file mode 100644 (file)
index 0000000..157d373
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/editeur/inserer_ligne.gif differ
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/supprimer_ligne.png b/www/plugins/enluminures_typographiques_v3/editeur/supprimer_ligne.png
new file mode 100644 (file)
index 0000000..1514d51
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/editeur/supprimer_ligne.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/table.css b/www/plugins/enluminures_typographiques_v3/editeur/table.css
new file mode 100644 (file)
index 0000000..de52e21
--- /dev/null
@@ -0,0 +1,33 @@
+body{\r
+       padding: 1em 2em 1em 1em;\r
+       text-align:center;\r
+       font: 12px Verdana, Geneva, Arial, Helvetica, sans-serif;\r
+}\r
+a img{border:none}\r
+#enregistrer{\r
+       display:block;\r
+       width:10em;\r
+       margin:1em auto;\r
+       padding:0.5em;\r
+       font-size:14px;\r
+       text-align:center;\r
+       text-decoration:none;\r
+       background:#eee;\r
+       border:1px outset #aaa;\r
+}\r
+div{text-align:left;margin-bottom:0.5em;}\r
+div span{float:left;width:10em}\r
+input{width:60%}\r
+#ihm{\r
+       border-collapse:collapse;\r
+       border:3px ridge gray;\r
+       width:85%;\r
+}\r
+#ihm td{border:3px ridge gray;text-align:center}\r
+#ihm td td{border:none}\r
+#ihm img{margin:4px}\r
+textarea{ width:100%}\r
+.first_c a img {display:block}\r
+.last_l, .last_c {background:#eee}\r
+.first_l, .first_c {background: #F0E68C}\r
+.first_c, .last_c {width:24px;}\r
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/table.js b/www/plugins/enluminures_typographiques_v3/editeur/table.js
new file mode 100644 (file)
index 0000000..c673451
--- /dev/null
@@ -0,0 +1,482 @@
+/* ce code s'inspire du travail de http://www.spip-contrib.net/_courcy_ \r
+  * il a été en grande partie ré-écrit pour : \r
+  * - générer une syntaxe de tableau SPIP et non HTML (l'éditeur de couleur de cellules disparaît donc aussi)\r
+  * - pour permettre non seulement de créer un tableau mais aussi de modifier un tableau existant\r
+  * - pour intégrer les éléments HTML titre et résumé de tableau \r
+  */\r
+/******************************************\r
+   * FONCTIONNEMENT Général \r
+ *********************BUT****************************************\r
+  * Le but de ce script est de permettre à l'utilisateur de créer son propre \r
+   * tableau sans s'encombrer de la syntaxe SPIP. Si un tableau à syntaxe SPIP est \r
+   * sélectionné avant l'appel de l'assistant, les données  sont récupérées par l'assistant.\r
+   * Si rien n'est sélectionné l'appel de l'assistant, un nouveau tableau est créé au point\r
+   * d'insertion.   \r
+   ************Structure de donnees ***********************************\r
+   *  \r
+   * Classe ihm qui gère l'interface homme-machine de l'assistant et sa construction\r
+   * On trouve en autres les méthodes permettant d'insérer et de supprimer lignes et colonnes\r
+   * \r
+   * Classe Cellule qui contient les informations relatives à une cellule\r
+   * Ses attributs sont des informations relatives a une cellule  (contenu)\r
+   * chaque objet cellule est contenu dans le tableau lc qui est un tableau bidimensionnel de cellules\r
+   * ce tableau a autant d'éléments que de ligne * colonne dans le tableau \r
+   *\r
+   * \r
+   *******************ALGORITHME*************************************\r
+   * Le tableau est sauvé en mémoire dans la variable lc\r
+   * La fonction construit_tableau( ) de la classe ihm construit l'interface pour manipuler les données du tableau\r
+   * qui (re)initialisera la valeur innerHTML de <div id=tableau></div>\r
+   * toute modification des valeurs dans l'assistant modifie lc\r
+   * toute modification de l'interface (ajout/suppression de ligne/colonne)   modifie lc puis appelle la fonction construit_tableau \r
+   * simple mais efficace+\r
+   *\r
+   * La validation des modifications déclenche construit_code_tableau qui construit le code SPIP du tableau\r
+   */\r
+   \r
+   \r
+   /********INITIALISATION**************/ \r
+    //classe ihm : classe générique de gestion de tableau \r
+    function ihm() {\r
+               this.titre_t = "";\r
+               this.resume_t = "";\r
+               /* méthodes */\r
+               this.construit_tableau = construit_tableau;\r
+               this.bouton_insere_ligne = bouton_insere_ligne;\r
+               this.bouton_supprime_ligne = bouton_supprime_ligne;\r
+               this.bouton_insere_colonne = bouton_insere_colonne;\r
+               this.bouton_supprime_colonne = bouton_supprime_colonne;\r
+               this.insere_commande_ligne = insere_commande_ligne;\r
+               this.insere_commande_colonne = insere_commande_colonne;\r
+               this.insere_ligne = insere_ligne;\r
+               this.supprime_ligne = supprime_ligne;\r
+               this.insere_colonne = insere_colonne;\r
+               this.supprime_colonne = supprime_colonne;               \r
+\r
+           /*******CONStrUIT tableAU**********/\r
+               function construit_tableau(){\r
+                       var texte = "";\r
+                       texte+="<table id='ihm' cellspacing='"+cellspacing+"'>\n";\r
+                       for (i=0;i<nl+2;i++){//on rajoute deux lignes en plus pour l'interface\r
+                               texte+="<tr>\n";\r
+                               for (j=0;j<nc+2;j++){//on rajoute deux lignes  en plus pour l'interface\r
+                                       var position = "" ;\r
+                                       if (i==0 && j==0)       position = "coin"; //on est dans le coin on met le menu\r
+                                       if (i==0 && j>0)        position = "1st_l"; //on est sur la premiere ligne on insere des colonnes\r
+                                       if (i>0 && j==0)        position = "1st_c"; //on est sur la premiere colonne on insere des lignes\r
+                                       if (i==nl+1 && j>0) position = "last_l"; //on est dans la zone non éditée de la derniere ligne\r
+                                       if (i>0 && j==nc+1) position = "last_c"; //on est dans la zone non éditée la derniere colonne\r
+                                       switch (position) {\r
+                                               case "coin" :   texte+="<td></td>\n"; break;\r
+                                               case "1st_l" :  texte+="<td class='first_l'>"+this.insere_commande_colonne(j-1)+"</td>\n"; break;\r
+                                               case "1st_c" :  texte+="<td class='first_c'>"+this.insere_commande_ligne(i-1)+"</td>\n"; break;\r
+                                               case "last_l" : texte+="<td class='last_l'></td>\n"; break;\r
+                                               case "last_c" : texte+="<td class='last_c'></td>\n"; break;\r
+                                               default: //on est dans la partie éditable du tableau\r
+                                                       texte+="<td>"+ lc[i-1][j-1].insere() +"</td>\n";\r
+                                       }\r
+                               }//fin du for j\r
+                               texte+="</tr>";\r
+                       }//fin du for i\r
+                       texte+="</table>";\r
+                       //win=window.open('');\r
+                       //win.document.write("<textarea cols='100' rows='50'>"+texte+"</textarea>");\r
+                       table.innerHTML=texte;//on modifie le texte de ce noeud\r
+               }\r
+               /**\r
+               *cette fonction crée  un bouton  pour l'insertion d'une ligne\r
+               */\r
+               function bouton_insere_ligne(ligne){\r
+                       var texte = "<a href='javascript:ihm_tableau.insere_ligne("+ligne+")'><img ";\r
+                       texte += " title='Insérer une ligne au-dessus' ";\r
+                       texte += " alt='Insérer une ligne au-dessus' ";\r
+                       texte += "src='"+tableau_edit_images_path+"inserer_ligne.gif' value=''></a>\n";\r
+                       return texte;\r
+               }\r
+\r
+               /**\r
+               *cette fonction crée un bouton  pour la supression d'une ligne\r
+               */\r
+               function bouton_supprime_ligne(ligne){\r
+                       if (nl == 1) return "";\r
+                       var texte="<a href='javascript:ihm_tableau.supprime_ligne("+ligne+")'><img  ";\r
+                       texte += " title='Supprimer cette ligne' ";\r
+                       texte += " alt='Supprimer cette ligne' ";\r
+                       texte += "src='"+tableau_edit_images_path+"supprimer_ligne.png' value='ligne' /></a>\n";\r
+                       return texte;\r
+               }\r
+\r
+               /**\r
+                *cette fonction crée un bouton  pour l'insertion d'une colonne\r
+                */\r
+               function bouton_insere_colonne(colonne){        \r
+                       var texte="<a href='javascript:ihm_tableau.insere_colonne("+colonne+")'> <img ";\r
+                       texte+=" title='Insérer une colonne avant' ";\r
+                       texte+=" alt='Insérer une colonne avant' ";\r
+                       texte+="src='"+tableau_edit_images_path+"inserer_colonne.gif' value='colonne'></a>\n";  \r
+                       return texte;\r
+               }\r
+               /**\r
+                *cette fonction crée un bouton  pour la supression d'une colonne \r
+                */\r
+               function bouton_supprime_colonne(colonne){\r
+                       if (nc == 1) return "";\r
+                       var texte="<a href='javascript:ihm_tableau.supprime_colonne("+colonne+")'><img";\r
+                       texte+=" title='Supprimer cette colonne'";\r
+                       texte+=" alt='Supprimer cette colonne'";\r
+                       texte+=" src='"+tableau_edit_images_path+"supprimer_ligne.png' value='colonne' /></a>\n";\r
+                       return texte;\r
+               }\r
+               /**\r
+               *cette fonction met en forme les commandes pour une ligne\r
+               */\r
+               function insere_commande_ligne(ligne){  \r
+                       var texte;\r
+\r
+                       texte = this.bouton_insere_ligne(ligne);\r
+                       if (ligne<nl){\r
+                                texte += this.bouton_supprime_ligne(ligne);\r
+                       }\r
+                       return texte;\r
+               }\r
+\r
+               /**\r
+                *cette fonction met en forme les commandes pour une colonne\r
+                */\r
+               function insere_commande_colonne(colonne){\r
+                       var texte="";\r
+\r
+                       texte+= this.bouton_insere_colonne(colonne);\r
+                       if (colonne<nc){\r
+                               texte += this.bouton_supprime_colonne(colonne);\r
+                       }\r
+                       return texte;\r
+               }\r
+       \r
+               /*********LES CALLBACKS depuis les boutons de l'IHM ****************************************/\r
+               function insere_ligne(num_ligne){\r
+                       //création d'un tableau temporaire bidimensionnel de cellules\r
+                   var lctemp = new tableau_cellules(nl+1, nc);\r
+                       \r
+                       lctemp.insL(num_ligne);         //insertion d'une ligne dans le tableau lc\r
+                       lc=lctemp.getT();                       //on a une ligne en plus\r
+\r
+                       nl++;\r
+                       this.construit_tableau();\r
+               }\r
+       \r
+               function supprime_ligne(num_ligne){\r
+                       //création d'un tableau temporaire bidimensionnel de cellule\r
+                   var lctemp = new tableau_cellules(nl-1, nc);\r
+\r
+                       lctemp.supL(num_ligne);         //supression d'une ligne dans le tableau lc\r
+                       lc=lctemp.getT();                       //on a une ligne en moins\r
+\r
+                       nl--;\r
+                       this.construit_tableau();\r
+               }\r
+               function insere_colonne(num_colonne){\r
+                       //création d'un tableau temporaire bidimensionnel de cellule\r
+                   var lctemp = new tableau_cellules(nl, nc+1);\r
+\r
+                       lctemp.insC(num_colonne);       //insertion d'une colonne dans le tableau lc\r
+                       lc=lctemp.getT();\r
+\r
+                       nc++;                                           //on a une ligne en plus\r
+                       this.construit_tableau();\r
+               }\r
+               function supprime_colonne(num_colonne){\r
+                       //création d'un tableau temporaire bidimensionnel de cellules\r
+                   var lctemp = new tableau_cellules(nl, nc-1);\r
+                                       \r
+                       lctemp.supC(num_colonne);       //supression d'une colonne dans le tableau lc\r
+                       lc=lctemp.getT();                       //on remplace le tableau lc par le tableau temp\r
+                       \r
+                       nc--;                                           //on a une colonne en moins\r
+                       this.construit_tableau();\r
+               }\r
+    }\r
+\r
+    //classe cellule\r
+    function cellule(i,j){\r
+               this.l=i;\r
+               this.c=j;\r
+       this.content='';\r
+\r
+               /* les méthodes getters et setters */\r
+               this.setC = function(c){this.c = c}\r
+               this.getC = function(){return this.c}\r
+               this.setL = function(l){this.l = l}\r
+               this.getL = function(){return this.l}\r
+\r
+               /* les méthodes  de la classe cellule */\r
+               this.insere = insere;\r
+\r
+               /* cette fonction insere une zone de texte dans la cellule */\r
+               function insere(){\r
+\r
+                       var texte ="<textarea cols='10' rows='2'";      \r
+                       // on sauve le contenu\r
+                       texte+=" onchange='lc[" + this.l + "][" + this.c + "].content=this.value;'>";                   \r
+                       texte+=this.content;                    \r
+                       texte+="</textarea> \n";        \r
+                       return texte;\r
+               }\r
+    } //fin de la classe "cellule"\r
+       \r
+       function tableau_cellules(nb_l,nb_c){\r
+               this.t = new Array();\r
+               for (var i=0; i<nb_l; i++){\r
+               this.t[i]=new Array(); \r
+               for (var j=0; j<nb_c; j++){\r
+                       this.t[i][j]=new cellule(i,j);\r
+               }                       \r
+               }\r
+\r
+               this.getT = function(){return this.t}\r
+\r
+               this.insL = function(num_ligne) {\r
+                       //insertion d'une ligne dans le tableau lc\r
+                       for (var i=0;i<nl+1;i++){\r
+                               for (var j=0;j<nc;j++){\r
+                                       if (i<num_ligne){\r
+                                               //recopiage simple\r
+                                               this.t[i][j]=lc[i][j];\r
+                                       }\r
+                                       if (i>num_ligne){\r
+                                               //on incrémente de 1\r
+                                               this.t[i][j]=lc[i-1][j];\r
+                                               this.t[i][j].setL(i); \r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               this.supL = function(num_ligne){\r
+                       for (i=0;i<nl-1;i++){\r
+                               for (j=0;j<nc;j++){\r
+                                       if (i<num_ligne){\r
+                                               //recopiage simple\r
+                                               this.t[i][j]=lc[i][j];\r
+                                       }else{\r
+                                               this.t[i][j]=lc[i+1][j];\r
+                                               this.t[i][j].setL(i); \r
+                                       }\r
+                               }\r
+                       }\r
+               \r
+               }\r
+               \r
+               this.insC = function(num_colonne){\r
+                       for (i=0;i<nl;i++){\r
+                               for (j=0;j<nc+1;j++){\r
+                                       if (j<num_colonne){\r
+                                               //recopiage simple\r
+                                               this.t[i][j]=lc[i][j];\r
+                                       }\r
+                                       if (j>num_colonne){\r
+                                               //on incrémente de 1\r
+                                               this.t[i][j]=lc[i][j-1];\r
+                                               this.t[i][j].setC(j);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+               this.supC = function(num_colonne){\r
+                       for (i=0;i<nl;i++){\r
+                               for (j=0;j<nc-1;j++){\r
+                                       if (j<num_colonne){\r
+                                               //recopiage simple\r
+                                               this.t[i][j]=lc[i][j];\r
+                                       }else{\r
+                                               this.t[i][j]=lc[i][j+1];\r
+                                               this.t[i][j].setC(j);                                           \r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+\r
+       }\r
+       \r
+       function selection(zone){\r
+               this.s1 = "";\r
+               this.s2 = "";\r
+               this.s3 = "";\r
+               this.t_SPIP = new Array(); // les lignes du tableau SPIP\r
+               this.t = new Array(); // le tableau des valeurs à modifier\r
+               this.premiere_ligne = "";\r
+\r
+               this.avec_entete = avec_entete;\r
+               this.recup_caption = recup_caption;\r
+               this.recup_summary = recup_summary;\r
+               this.compte_lignes = compte_lignes;\r
+               this.recup_ligne = recup_ligne;\r
+               this.recup_cellule = recup_cellule;\r
+               this.contenu = contenu;\r
+               this.existe = existe;\r
+               \r
+               var lignes = new Array(); // les lignes brutes de la zone d'édition SPIP\r
+               var ligne_cour = ""; // la ligne brute en cours de traitement lors de la reconstitution du tableau SPIP\r
+               var j=0;\r
+               var init_i; // début du contenu du tableau de données (1 si tableau avec entête, 0 sinon)\r
+               \r
+               if ((clientVer >= 4) && is_ie && is_win)\r
+               {\r
+                       var theSelection = false;\r
+\r
+                       theSelection = top.opener.document.selection.createRange().text; // Get text selection\r
+                       if (theSelection) {\r
+                               this.s2 = theSelection;\r
+                       } else {\r
+                               this.s1 = top.opener.document.getElementById("text_area").value;\r
+                       }\r
+               }\r
+               else {\r
+                       var selLength = zone.textLength;\r
+                       var selStart = zone.selectionStart;\r
+                       var selEnd = zone.selectionEnd;\r
+\r
+                       if (selEnd == 1 || selEnd == 2) selEnd = selLength;\r
+       \r
+                       // Raccourcir la selection par double-clic si dernier caractere est espace      \r
+                       if (selEnd - selStart > 0 && (zone.value).substring(selEnd-1,selEnd) == ' ') selEnd = selEnd-1;\r
+                       this.s1 = (zone.value).substring(0,selStart);\r
+                       this.s2 = (zone.value).substring(selStart, selEnd)\r
+                       this.s3 = (zone.value).substring(selEnd, selLength);\r
+               }\r
+\r
+               lignes = this.s2.split("\n");\r
+                       \r
+               if (this.avec_entete()) init_i = 1;     \r
+               for (i=init_i;i<lignes.length;i++) {\r
+                       ligne_cour += lignes[i] + "\n";\r
+                       if (lignes[i].match(/\|.?$/)) {\r
+                               ligne_cour = ligne_cour.replace(/\|(left|right|center)/g, "££$1"); //pour distinguer les barres verticales des codes d'inclusion d'image et de document\r
+                               this.t_SPIP[j++] = ligne_cour;\r
+                               ligne_cour = "";\r
+                       }\r
+               }\r
+               this.premiere_ligne = this.t_SPIP[0];\r
+\r
+               this.contenu();\r
+\r
+\r
+               function avec_entete(){\r
+                       return (lignes[0].search(/^\|\|/) != -1); // si double pipe en tête de la première ligne(resumé)\r
+               }\r
+               function recup_caption(){\r
+                       return lignes[0].match(/^\|\|([^\|]*)/)[1];\r
+               }\r
+               function recup_summary(){\r
+                       return lignes[0].match(/^\|\|([^\|])*\|([^\|]*)/)[2];\r
+               }\r
+               function compte_lignes(){\r
+                       return (this.t_SPIP.length);\r
+               }\r
+               function recup_ligne(num_ligne){\r
+                       var ligne_encodee = this.t_SPIP[num_ligne].split("|");\r
+                       var ligne_decodee = new Array();\r
+                       \r
+                       for (var i=0; i<ligne_encodee.length; i++){\r
+                               ligne_decodee[i] = ligne_encodee[i].replace(/££/g,"|");\r
+                       }\r
+                       return (ligne_decodee);\r
+               }\r
+               function contenu(){\r
+                       for (var i=0; i<this.t_SPIP.length; i++){\r
+                               this.t[i] = this.recup_ligne(i); //t est un tableau bidimensionnel avec les valeurs à modifier\r
+                       }\r
+               }\r
+               function recup_cellule(i,j){\r
+                       return (this.t[i][j+1] ? this.t[i][j+1] : "");\r
+               }\r
+               function existe() {return (this.s2!="")} //indique si un tableau SPIP a été sélectionné\r
+       }\r
+       var ancien_tableau;\r
+\r
+    //nombre de lignes et nombre de colonnes\r
+    var nl;\r
+    var nc;\r
+\r
+    //création d'un tableau bidimensionnel de cellules\r
+    var lc=new Array();\r
+\r
+    var cellspacing=0;\r
+\r
+    //noeud ou l'on va ecrire le tableau\r
+    var table;\r
+    var debug;\r
+       \r
+       var ihm_tableau = new ihm();\r
+       \r
+       function init(){\r
+               ancien_tableau = new selection(top.opener.zone_selection);\r
+       \r
+               if (ancien_tableau.existe() & ancien_tableau.avec_entete()) {\r
+                       document.getElementById("titre_t").value = ancien_tableau.recup_caption() ;     //récupération du titre du tableau\r
+                       document.getElementById("resume_t").value = ancien_tableau.recup_summary() ;//récupération du résumé du tableau\r
+               }\r
+\r
+               nl= (ancien_tableau.existe()) ? ancien_tableau.compte_lignes() : 3;\r
+               nc= (ancien_tableau.existe()) ? ancien_tableau.t[0].length - 2 : 3;\r
+\r
+               for (i=0;i<nl;i++){\r
+         lc[i]=new Array(); //2 lignes au depart\r
+          for (j=0;j<nc;j++){\r
+                lc[i][j]=new cellule(i,j);\r
+                if (ancien_tableau.existe()) lc[i][j].content = ancien_tableau.recup_cellule(i,j);\r
+           }                   \r
+        }\r
+               \r
+               table=document.getElementById("table");\r
+               debug=document.getElementById("debug");\r
+\r
+               /*********CONStrUCTION DE L'INTERFACE UTILISATEUR**********************/\r
+               ihm_tableau.construit_tableau();\r
+       }\r
+    function d(s){debug.innerHTML+=s;}\r
+    \r
+    /****génération du code SPIP du tableau ******/\r
+    \r
+    function construit_code_tableau(){\r
+       var le_titre = document.getElementById("titre_t").value;\r
+               var le_resume = document.getElementById("resume_t").value;\r
+       var texte="";\r
+       var la_ligne="";\r
+\r
+               texte += "||" + le_titre + "|" + le_resume + "||\n";\r
+               for (var j=0;j<nc;j++){\r
+                       //on supprime les accolades éventuelles avant de placer les accolades d'entete de tableau\r
+                       var cont_cell = lc[0][j].content.replace(/(\{)*([^\}]*)(\})*/,"$2");\r
+                       la_ligne += "|{{" + (cont_cell=="" ? " " : cont_cell) + "}}";\r
+               }\r
+               texte += la_ligne + "|\n";\r
+\r
+               for (i=1;i<nl;i++){\r
+                       for (j=0;j<nc;j++) {texte += "|" + lc[i][j].content;}\r
+                       texte += "|\n";\r
+               }//fin du for i\r
+               return texte;   \r
+    }\r
+       \r
+    /**********LES FONCTIONS DE CREATION DE L'INTERFACE**********/\r
+\r
+       function enregistre(){\r
+               if (ancien_tableau.existe()) {\r
+                       if ((clientVer >= 4) && is_ie && is_win) {\r
+                               top.opener.document.selection.createRange().text = construit_code_tableau();\r
+                       } else {\r
+                               top.opener.zone_selection.value = ancien_tableau.s1 + construit_code_tableau() + ancien_tableau.s3;\r
+                       }\r
+               } else { //insertion d'un nouveau tableau\r
+                       if (top.opener.zone_selection.createTextRange && top.opener.zone_selection.caretPos) { //IE\r
+                               var caretPos = top.opener.zone_selection.caretPos;\r
+                               caretPos.text = caretPos.text + construit_code_tableau();\r
+                               top.opener.zone_selection.focus();\r
+                       } else {\r
+                               top.opener.zone_selection.value = ancien_tableau.s1 + construit_code_tableau() + ancien_tableau.s3;\r
+                       }\r
+               }\r
+               window.close();         \r
+       }
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/table_rtl.css b/www/plugins/enluminures_typographiques_v3/editeur/table_rtl.css
new file mode 100644 (file)
index 0000000..650455c
--- /dev/null
@@ -0,0 +1,33 @@
+body{
+       padding: 1em 1em 1em 2em;
+       text-align: center;
+       font: 12px Verdana, Geneva, Arial, Helvetica, sans-serif;
+}
+a img{border:none}
+#enregistrer{
+       display:block;
+       width:10em;
+       margin:1em auto;
+       padding:0.5em;
+       font-size:14px;
+       text-align:center;
+       text-decoration:none;
+       background:#eee;
+       border:1px outset #aaa;
+}
+div{text-align:right;margin-bottom:0.5em;}
+div span{float:right;width:10em}
+input{width:60%}
+#ihm{
+       border-collapse:collapse;
+       border:3px ridge gray;
+       width:85%;
+}
+#ihm td{border:3px ridge gray;text-align:center}
+#ihm td td{border:none}
+#ihm img{margin:4px}
+textarea{ width:100%}
+.first_c a img {display:block}
+.last_l, .last_c {background:#eee}
+.first_l, .first_c {background: #F0E68C}
+.first_c, .last_c {width:24px;}
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/table_rtl.js b/www/plugins/enluminures_typographiques_v3/editeur/table_rtl.js
new file mode 100644 (file)
index 0000000..7810439
--- /dev/null
@@ -0,0 +1,482 @@
+/* ce code s'inspire du travail de http://www.spip-contrib.net/_courcy_ 
+  * il a été en grande partie ré-écrit pour : 
+  * - générer une syntaxe de tableau SPIP et non HTML (l'éditeur de couleur de cellules disparaît donc aussi)
+  * - pour permettre non seulement de créer un tableau mais aussi de modifier un tableau existant
+  * - pour intégrer les éléments HTML titre et résumé de tableau 
+  */
+/******************************************
+   * FONCTIONNEMENT Général 
+ *********************BUT****************************************
+  * Le but de ce script est de permettre à l'utilisateur de créer son propre 
+   * tableau sans s'encombrer de la syntaxe SPIP. Si un tableau à syntaxe SPIP est 
+   * sélectionné avant l'appel de l'assistant, les données  sont récupérées par l'assistant.
+   * Si rien n'est sélectionné l'appel de l'assistant, un nouveau tableau est créé au point
+   * d'insertion.   
+   ************Structure de donnees ***********************************
+   *  
+   * Classe ihm qui gère l'interface homme-machine de l'assistant et sa construction
+   * On trouve en autres les méthodes permettant d'insérer et de supprimer lignes et colonnes
+   * 
+   * Classe Cellule qui contient les informations relatives à une cellule
+   * Ses attributs sont des informations relatives a une cellule  (contenu)
+   * chaque objet cellule est contenu dans le tableau lc qui est un tableau bidimensionnel de cellules
+   * ce tableau a autant d'éléments que de ligne * colonne dans le tableau 
+   *
+   * 
+   *******************ALGORITHME*************************************
+   * Le tableau est sauvé en mémoire dans la variable lc
+   * La fonction construit_tableau( ) de la classe ihm construit l'interface pour manipuler les données du tableau
+   * qui (re)initialisera la valeur innerHTML de <div id=tableau></div>
+   * toute modification des valeurs dans l'assistant modifie lc
+   * toute modification de l'interface (ajout/suppression de ligne/colonne)   modifie lc puis appelle la fonction construit_tableau 
+   * simple mais efficace+
+   *
+   * La validation des modifications déclenche construit_code_tableau qui construit le code SPIP du tableau
+   */
+   
+   
+   /********INITIALISATION**************/ 
+    //classe ihm : classe générique de gestion de tableau 
+    function ihm() {
+               this.titre_t = "";
+               this.resume_t = "";
+               /* méthodes */
+               this.construit_tableau = construit_tableau;
+               this.bouton_insere_ligne = bouton_insere_ligne;
+               this.bouton_supprime_ligne = bouton_supprime_ligne;
+               this.bouton_insere_colonne = bouton_insere_colonne;
+               this.bouton_supprime_colonne = bouton_supprime_colonne;
+               this.insere_commande_ligne = insere_commande_ligne;
+               this.insere_commande_colonne = insere_commande_colonne;
+               this.insere_ligne = insere_ligne;
+               this.supprime_ligne = supprime_ligne;
+               this.insere_colonne = insere_colonne;
+               this.supprime_colonne = supprime_colonne;               
+
+           /*******CONStrUIT tableAU**********/
+               function construit_tableau(){
+                       var texte = "";
+                       texte+="<table id='ihm' cellspacing='"+cellspacing+"'>\n";
+                       for (i=0;i<nl+2;i++){//on rajoute deux lignes en plus pour l'interface
+                               texte+="<tr>\n";
+                               for (j=0;j<nc+2;j++){//on rajoute deux lignes  en plus pour l'interface
+                                       var position = "" ;
+                                       if (i==0 && j==0)       position = "coin"; //on est dans le coin on met le menu
+                                       if (i==0 && j>0)        position = "1st_l"; //on est sur la premiere ligne on insere des colonnes
+                                       if (i>0 && j==0)        position = "1st_c"; //on est sur la premiere colonne on insere des lignes
+                                       if (i==nl+1 && j>0) position = "last_l"; //on est dans la zone non éditée de la derniere ligne
+                                       if (i>0 && j==nc+1) position = "last_c"; //on est dans la zone non éditée la derniere colonne
+                                       switch (position) {
+                                               case "coin" :   texte+="<td></td>\n"; break;
+                                               case "1st_l" :  texte+="<td class='first_l'>"+this.insere_commande_colonne(j-1)+"</td>\n"; break;
+                                               case "1st_c" :  texte+="<td class='first_c'>"+this.insere_commande_ligne(i-1)+"</td>\n"; break;
+                                               case "last_l" : texte+="<td class='last_l'></td>\n"; break;
+                                               case "last_c" : texte+="<td class='last_c'></td>\n"; break;
+                                               default: //on est dans la partie éditable du tableau
+                                                       texte+="<td>"+ lc[i-1][j-1].insere() +"</td>\n";
+                                       }
+                               }//fin du for j
+                               texte+="</tr>";
+                       }//fin du for i
+                       texte+="</table>";
+                       //win=window.open('');
+                       //win.document.write("<textarea cols='100' rows='50'>"+texte+"</textarea>");
+                       table.innerHTML=texte;//on modifie le texte de ce noeud
+               }
+               /**
+               *cette fonction crée  un bouton  pour l'insertion d'une ligne
+               */
+               function bouton_insere_ligne(ligne){
+                       var texte = "<a href='javascript:ihm_tableau.insere_ligne("+ligne+")'><img ";
+                       texte += " title='&#1573;&#1583;&#1585;&#1575;&#1580; &#1587;&#1591;&#1585; &#1601;&#1608;&#1602;' ";
+                       texte += " alt='&#1573;&#1583;&#1585;&#1575;&#1580; &#1587;&#1591;&#1585; &#1601;&#1608;&#1602;' ";
+                       texte += "src='"+tableau_edit_images_path+"inserer_ligne.gif' value=''></a>\n";
+                       return texte;
+               }
+
+               /**
+               *cette fonction crée un bouton  pour la supression d'une ligne
+               */
+               function bouton_supprime_ligne(ligne){
+                       if (nl == 1) return "";
+                       var texte="<a href='javascript:ihm_tableau.supprime_ligne("+ligne+")'><img  ";
+                       texte += " title='&#1581;&#1584;&#1601; &#1607;&#1584;&#1575; &#1575;&#1604;&#1587;&#1591;&#1585;' ";
+                       texte += " alt='&#1581;&#1584;&#1601; &#1607;&#1584;&#1575; &#1575;&#1604;&#1587;&#1591;&#1585;' ";
+                       texte += "src='"+tableau_edit_images_path+"supprimer_ligne.png' value='ligne' /></a>\n";
+                       return texte;
+               }
+
+               /**
+                *cette fonction crée un bouton  pour l'insertion d'une colonne
+                */
+               function bouton_insere_colonne(colonne){        
+                       var texte="<a href='javascript:ihm_tableau.insere_colonne("+colonne+")'> <img ";
+                       texte+=" title='&#1573;&#1583;&#1585;&#1575;&#1580; &#1593;&#1605;&#1608;&#1583; &#1602;&#1576;&#1604;' ";
+                       texte+=" alt='&#1573;&#1583;&#1585;&#1575;&#1580; &#1593;&#1605;&#1608;&#1583; &#1602;&#1576;&#1604;' ";
+                       texte+="src='"+tableau_edit_images_path+"inserer_colonne.gif' value='colonne'></a>\n";  
+                       return texte;
+               }
+               /**
+                *cette fonction crée un bouton  pour la supression d'une colonne 
+                */
+               function bouton_supprime_colonne(colonne){
+                       if (nc == 1) return "";
+                       var texte="<a href='javascript:ihm_tableau.supprime_colonne("+colonne+")'><img";
+                       texte+=" title='&#1581;&#1584;&#1601; &#1607;&#1584;&#1575; &#1575;&#1604;&#1593;&#1605;&#1608;&#1583;'";
+                       texte+=" alt='&#1581;&#1584;&#1601; &#1607;&#1584;&#1575; &#1575;&#1604;&#1593;&#1605;&#1608;&#1583;'";
+                       texte+=" src='"+tableau_edit_images_path+"supprimer_ligne.png' value='colonne' /></a>\n";
+                       return texte;
+               }
+               /**
+               *cette fonction met en forme les commandes pour une ligne
+               */
+               function insere_commande_ligne(ligne){  
+                       var texte;
+
+                       texte = this.bouton_insere_ligne(ligne);
+                       if (ligne<nl){
+                                texte += this.bouton_supprime_ligne(ligne);
+                       }
+                       return texte;
+               }
+
+               /**
+                *cette fonction met en forme les commandes pour une colonne
+                */
+               function insere_commande_colonne(colonne){
+                       var texte="";
+
+                       texte+= this.bouton_insere_colonne(colonne);
+                       if (colonne<nc){
+                               texte += this.bouton_supprime_colonne(colonne);
+                       }
+                       return texte;
+               }
+       
+               /*********LES CALLBACKS depuis les boutons de l'IHM ****************************************/
+               function insere_ligne(num_ligne){
+                       //création d'un tableau temporaire bidimensionnel de cellules
+                   var lctemp = new tableau_cellules(nl+1, nc);
+                       
+                       lctemp.insL(num_ligne);         //insertion d'une ligne dans le tableau lc
+                       lc=lctemp.getT();                       //on a une ligne en plus
+
+                       nl++;
+                       this.construit_tableau();
+               }
+       
+               function supprime_ligne(num_ligne){
+                       //création d'un tableau temporaire bidimensionnel de cellule
+                   var lctemp = new tableau_cellules(nl-1, nc);
+
+                       lctemp.supL(num_ligne);         //supression d'une ligne dans le tableau lc
+                       lc=lctemp.getT();                       //on a une ligne en moins
+
+                       nl--;
+                       this.construit_tableau();
+               }
+               function insere_colonne(num_colonne){
+                       //création d'un tableau temporaire bidimensionnel de cellule
+                   var lctemp = new tableau_cellules(nl, nc+1);
+
+                       lctemp.insC(num_colonne);       //insertion d'une colonne dans le tableau lc
+                       lc=lctemp.getT();
+
+                       nc++;                                           //on a une ligne en plus
+                       this.construit_tableau();
+               }
+               function supprime_colonne(num_colonne){
+                       //création d'un tableau temporaire bidimensionnel de cellules
+                   var lctemp = new tableau_cellules(nl, nc-1);
+                                       
+                       lctemp.supC(num_colonne);       //supression d'une colonne dans le tableau lc
+                       lc=lctemp.getT();                       //on remplace le tableau lc par le tableau temp
+                       
+                       nc--;                                           //on a une colonne en moins
+                       this.construit_tableau();
+               }
+    }
+
+    //classe cellule
+    function cellule(i,j){
+               this.l=i;
+               this.c=j;
+       this.content='';
+
+               /* les méthodes getters et setters */
+               this.setC = function(c){this.c = c}
+               this.getC = function(){return this.c}
+               this.setL = function(l){this.l = l}
+               this.getL = function(){return this.l}
+
+               /* les méthodes  de la classe cellule */
+               this.insere = insere;
+
+               /* cette fonction insere une zone de texte dans la cellule */
+               function insere(){
+
+                       var texte ="<textarea cols='10' rows='2'";      
+                       // on sauve le contenu
+                       texte+=" onchange='lc[" + this.l + "][" + this.c + "].content=this.value;'>";                   
+                       texte+=this.content;                    
+                       texte+="</textarea> \n";        
+                       return texte;
+               }
+    } //fin de la classe "cellule"
+       
+       function tableau_cellules(nb_l,nb_c){
+               this.t = new Array();
+               for (var i=0; i<nb_l; i++){
+               this.t[i]=new Array(); 
+               for (var j=0; j<nb_c; j++){
+                       this.t[i][j]=new cellule(i,j);
+               }                       
+               }
+
+               this.getT = function(){return this.t}
+
+               this.insL = function(num_ligne) {
+                       //insertion d'une ligne dans le tableau lc
+                       for (var i=0;i<nl+1;i++){
+                               for (var j=0;j<nc;j++){
+                                       if (i<num_ligne){
+                                               //recopiage simple
+                                               this.t[i][j]=lc[i][j];
+                                       }
+                                       if (i>num_ligne){
+                                               //on incrémente de 1
+                                               this.t[i][j]=lc[i-1][j];
+                                               this.t[i][j].setL(i); 
+                                       }
+                               }
+                       }
+               }
+               
+               this.supL = function(num_ligne){
+                       for (i=0;i<nl-1;i++){
+                               for (j=0;j<nc;j++){
+                                       if (i<num_ligne){
+                                               //recopiage simple
+                                               this.t[i][j]=lc[i][j];
+                                       }else{
+                                               this.t[i][j]=lc[i+1][j];
+                                               this.t[i][j].setL(i); 
+                                       }
+                               }
+                       }
+               
+               }
+               
+               this.insC = function(num_colonne){
+                       for (i=0;i<nl;i++){
+                               for (j=0;j<nc+1;j++){
+                                       if (j<num_colonne){
+                                               //recopiage simple
+                                               this.t[i][j]=lc[i][j];
+                                       }
+                                       if (j>num_colonne){
+                                               //on incrémente de 1
+                                               this.t[i][j]=lc[i][j-1];
+                                               this.t[i][j].setC(j);
+                                       }
+                               }
+                       }
+               }
+
+               this.supC = function(num_colonne){
+                       for (i=0;i<nl;i++){
+                               for (j=0;j<nc-1;j++){
+                                       if (j<num_colonne){
+                                               //recopiage simple
+                                               this.t[i][j]=lc[i][j];
+                                       }else{
+                                               this.t[i][j]=lc[i][j+1];
+                                               this.t[i][j].setC(j);                                           
+                                       }
+                               }
+                       }
+               }
+
+       }
+       
+       function selection(zone){
+               this.s1 = "";
+               this.s2 = "";
+               this.s3 = "";
+               this.t_SPIP = new Array(); // les lignes du tableau SPIP
+               this.t = new Array(); // le tableau des valeurs à modifier
+               this.premiere_ligne = "";
+
+               this.avec_entete = avec_entete;
+               this.recup_caption = recup_caption;
+               this.recup_summary = recup_summary;
+               this.compte_lignes = compte_lignes;
+               this.recup_ligne = recup_ligne;
+               this.recup_cellule = recup_cellule;
+               this.contenu = contenu;
+               this.existe = existe;
+               
+               var lignes = new Array(); // les lignes brutes de la zone d'édition SPIP
+               var ligne_cour = ""; // la ligne brute en cours de traitement lors de la reconstitution du tableau SPIP
+               var j=0;
+               var init_i; // début du contenu du tableau de données (1 si tableau avec entête, 0 sinon)
+               
+               if ((clientVer >= 4) && is_ie && is_win)
+               {
+                       var theSelection = false;
+
+                       theSelection = top.opener.document.selection.createRange().text; // Get text selection
+                       if (theSelection) {
+                               this.s2 = theSelection;
+                       } else {
+                               this.s1 = top.opener.document.getElementById("text_area").value;
+                       }
+               }
+               else {
+                       var selLength = zone.textLength;
+                       var selStart = zone.selectionStart;
+                       var selEnd = zone.selectionEnd;
+
+                       if (selEnd == 1 || selEnd == 2) selEnd = selLength;
+       
+                       // Raccourcir la selection par double-clic si dernier caractere est espace      
+                       if (selEnd - selStart > 0 && (zone.value).substring(selEnd-1,selEnd) == ' ') selEnd = selEnd-1;
+                       this.s1 = (zone.value).substring(0,selStart);
+                       this.s2 = (zone.value).substring(selStart, selEnd)
+                       this.s3 = (zone.value).substring(selEnd, selLength);
+               }
+
+               lignes = this.s2.split("\n");
+                       
+               if (this.avec_entete()) init_i = 1;     
+               for (i=init_i;i<lignes.length;i++) {
+                       ligne_cour += lignes[i] + "\n";
+                       if (lignes[i].match(/\|.?$/)) {
+                               ligne_cour = ligne_cour.replace(/\|(left|right|center)/g, "££$1"); //pour distinguer les barres verticales des codes d'inclusion d'image et de document
+                               this.t_SPIP[j++] = ligne_cour;
+                               ligne_cour = "";
+                       }
+               }
+               this.premiere_ligne = this.t_SPIP[0];
+
+               this.contenu();
+
+
+               function avec_entete(){
+                       return (lignes[0].search(/^\|\|/) != -1); // si double pipe en tête de la première ligne(resumé)
+               }
+               function recup_caption(){
+                       return lignes[0].match(/^\|\|([^\|]*)/)[1];
+               }
+               function recup_summary(){
+                       return lignes[0].match(/^\|\|([^\|])*\|([^\|]*)/)[2];
+               }
+               function compte_lignes(){
+                       return (this.t_SPIP.length);
+               }
+               function recup_ligne(num_ligne){
+                       var ligne_encodee = this.t_SPIP[num_ligne].split("|");
+                       var ligne_decodee = new Array();
+                       
+                       for (var i=0; i<ligne_encodee.length; i++){
+                               ligne_decodee[i] = ligne_encodee[i].replace(/££/g,"|");
+                       }
+                       return (ligne_decodee);
+               }
+               function contenu(){
+                       for (var i=0; i<this.t_SPIP.length; i++){
+                               this.t[i] = this.recup_ligne(i); //t est un tableau bidimensionnel avec les valeurs à modifier
+                       }
+               }
+               function recup_cellule(i,j){
+                       return (this.t[i][j+1] ? this.t[i][j+1] : "");
+               }
+               function existe() {return (this.s2!="")} //indique si un tableau SPIP a été sélectionné
+       }
+       var ancien_tableau;
+
+    //nombre de lignes et nombre de colonnes
+    var nl;
+    var nc;
+
+    //création d'un tableau bidimensionnel de cellules
+    var lc=new Array();
+
+    var cellspacing=0;
+
+    //noeud ou l'on va ecrire le tableau
+    var table;
+    var debug;
+       
+       var ihm_tableau = new ihm();
+       
+       function init(){
+               ancien_tableau = new selection(top.opener.zone_selection);
+       
+               if (ancien_tableau.existe() & ancien_tableau.avec_entete()) {
+                       document.getElementById("titre_t").value = ancien_tableau.recup_caption() ;     //récupération du titre du tableau
+                       document.getElementById("resume_t").value = ancien_tableau.recup_summary() ;//récupération du résumé du tableau
+               }
+
+               nl= (ancien_tableau.existe()) ? ancien_tableau.compte_lignes() : 3;
+               nc= (ancien_tableau.existe()) ? ancien_tableau.t[0].length - 2 : 3;
+
+               for (i=0;i<nl;i++){
+         lc[i]=new Array(); //2 lignes au depart
+          for (j=0;j<nc;j++){
+                lc[i][j]=new cellule(i,j);
+                if (ancien_tableau.existe()) lc[i][j].content = ancien_tableau.recup_cellule(i,j);
+           }                   
+        }
+               
+               table=document.getElementById("table");
+               debug=document.getElementById("debug");
+
+               /*********CONStrUCTION DE L'INTERFACE UTILISATEUR**********************/
+               ihm_tableau.construit_tableau();
+       }
+    function d(s){debug.innerHTML+=s;}
+    
+    /****génération du code SPIP du tableau ******/
+    
+    function construit_code_tableau(){
+       var le_titre = document.getElementById("titre_t").value;
+               var le_resume = document.getElementById("resume_t").value;
+       var texte="";
+       var la_ligne="";
+
+               texte += "||" + le_titre + "|" + le_resume + "||\n";
+               for (var j=0;j<nc;j++){
+                       //on supprime les accolades éventuelles avant de placer les accolades d'entete de tableau
+                       var cont_cell = lc[0][j].content.replace(/(\{)*([^\}]*)(\})*/,"$2");
+                       la_ligne += "|{{" + (cont_cell=="" ? " " : cont_cell) + "}}";
+               }
+               texte += la_ligne + "|\n";
+
+               for (i=1;i<nl;i++){
+                       for (j=0;j<nc;j++) {texte += "|" + lc[i][j].content;}
+                       texte += "|\n";
+               }//fin du for i
+               return texte;   
+    }
+       
+    /**********LES FONCTIONS DE CREATION DE L'INTERFACE**********/
+
+       function enregistre(){
+               if (ancien_tableau.existe()) {
+                       if ((clientVer >= 4) && is_ie && is_win) {
+                               top.opener.document.selection.createRange().text = construit_code_tableau();
+                       } else {
+                               top.opener.zone_selection.value = ancien_tableau.s1 + construit_code_tableau() + ancien_tableau.s3;
+                       }
+               } else { //insertion d'un nouveau tableau
+                       if (top.opener.zone_selection.createTextRange && top.opener.zone_selection.caretPos) { //IE
+                               var caretPos = top.opener.zone_selection.caretPos;
+                               caretPos.text = caretPos.text + construit_code_tableau();
+                               top.opener.zone_selection.focus();
+                       } else {
+                               top.opener.zone_selection.value = ancien_tableau.s1 + construit_code_tableau() + ancien_tableau.s3;
+                       }
+               }
+               window.close();         
+       }
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/editeur/tableau_edit.html b/www/plugins/enluminures_typographiques_v3/editeur/tableau_edit.html
new file mode 100644 (file)
index 0000000..a278b92
--- /dev/null
@@ -0,0 +1,24 @@
+#CACHE{24*3600}
+<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>
+<html lang='#LANG' dir='#LANG_DIR'>
+  <head>
+    <title>Editeur de table</title>
+       <meta http-equiv="Content-Type" content="text/html; charset=#CHARSET" />
+       <link rel="stylesheet" href="[(#CHEMIN{editeur/table.css}|direction_css)]" type="text/css" media="screen" />
+       <script type="text/javascript">
+               tableau_edit_images_path = "[(#CHEMIN{editeur/table.css}|dirname)/]";
+       </script>
+    <script src="#CHEMIN{javascript/spip_barre.js}" type="text/javascript"></script>
+    <script src="#CHEMIN{editeur/table(#LANG_DIR|=={rtl}|?{'_rtl',''}).js}" type="text/javascript"></script>
+  </head>
+  <body onload="init();">
+
+  <form action="table.html" method="post">
+  <div><label><span><:enlumtypo:tableau_titre:></span><input id='titre_t' value='' onchange='ihm_tableau.titre_t=this.value;' /></label></div>
+  <div><label><span><:enlumtypo:tableau_resume:></span><input id='resume_t' value='' onchange='ihm_tableau.resume_t=this.value;' /></label></div>
+  </form>
+  <div id='table'></div>
+  <div id='debug'></div>
+  <a id="enregistrer" href="javascript:enregistre()"><:enlumtypo:tableau_enregistrer:></a>
+  </body>
+</html>
diff --git a/www/plugins/enluminures_typographiques_v3/enluminures_typo_pipelines.php b/www/plugins/enluminures_typographiques_v3/enluminures_typo_pipelines.php
new file mode 100644 (file)
index 0000000..6a9587a
--- /dev/null
@@ -0,0 +1,213 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+function typoenluminee_porte_plume_barre_pre_charger($barres){\r
+       $barre = &$barres['edition'];\r
+       \r
+       $barre->cacher('stroke_through');\r
+\r
+       $module_barre = "barre_outils";\r
+       if (intval($GLOBALS['spip_version_branche'])>2)\r
+               $module_barre = "barreoutils";\r
+       \r
+       $barre->set('header1', array(\r
+               // groupe formatage paragraphe\r
+               "dropMenu"    => array(\r
+                       // bouton <cadre>\r
+                       array(\r
+                               "id"          => 'intertitre',\r
+                               "name"        => _T('barre_intertitre'),\r
+                               "className"   => 'outil_intertitre1', \r
+                               "openWith" => "\n{{{",\r
+                               "closeWith" => "}}}\n",\r
+                               "display"     => true,\r
+                               "selectionType" => "line",\r
+                       ),\r
+                       array(\r
+                               "id"          => 'intertitre2',\r
+                               "name"        => _T('enlumtypo:barre_intertitre2'),\r
+                               "className"   => 'outil_intertitre2', \r
+                               "openWith" => "\n{{{**",\r
+                               "closeWith" => "}}}\n",\r
+                               "display"     => true,\r
+                               "selectionType" => "line",\r
+                       ),\r
+                       array(\r
+                               "id"          => 'intertitre3',\r
+                               "name"        => _T('enlumtypo:barre_intertitre3'),\r
+                               "className"   => 'outil_intertitre3', \r
+                               "openWith" => "\n{{{***",\r
+                               "closeWith" => "}}}\n",\r
+                               "display"     => true,\r
+                               "selectionType" => "line",\r
+                       ),\r
+                       array(\r
+                               "id"          => 'alignerdroite',\r
+                               "name"        => _T('enlumtypo:barre_alignerdroite'),\r
+                               "className"   => 'outil_alignerdroite', \r
+                               "openWith" => "\n[/",\r
+                               "closeWith" => "/]\n",\r
+                               "display"     => true,\r
+                               "selectionType" => "line",\r
+                       ),\r
+                       array(\r
+                               "id"          => 'alignergauche',\r
+                               "name"        => _T('enlumtypo:barre_alignergauche'),\r
+                               "className"   => 'outil_alignergauche', \r
+                               "openWith" => "\n[!",\r
+                               "closeWith" => "!]\n",\r
+                               "display"     => true,\r
+                               "lang"        => array('ar','fa'),\r
+                               "selectionType" => "line",\r
+                       ),\r
+                       array(\r
+                               "id"          => 'cadretexte',\r
+                               "name"        => _T('enlumtypo:barre_encadrer'),\r
+                               "className"   => 'outil_cadretexte', \r
+                               "openWith" => "\n[(",\r
+                               "closeWith" => ")]\n",\r
+                               "display"     => true,\r
+                               "selectionType" => "line",\r
+                       ),\r
+                       // code spip\r
+                       array(\r
+                               "id"          => 'barre_cadre',\r
+                               "name"        => _T($module_barre.':barre_cadre'),\r
+                               "className"   => "outil_barre_cadre", \r
+                               "openWith"    => "\n&lt;cadre&gt;", \r
+                               "closeWith"   => "&lt;/cadre&gt;\n",\r
+                               "display"     => true,\r
+                               "selectionType" => "line",\r
+                       ),\r
+               ),\r
+       ));\r
+       \r
+       $barre->set('bold', array(\r
+               // groupe formatage texte\r
+               "dropMenu"    => array(\r
+                       // Mise en évidence (gras + couleur)\r
+                       array(\r
+                               "id"          => 'miseenevidence',\r
+                               "name"        => _T('enlumtypo:barre_miseenevidence'),\r
+                               "className"   => "outil_miseenevidence",\r
+                               "openWith"    => "[*", \r
+                               "closeWith"   => "*]",\r
+                               "display"     => true,\r
+                               "selectionType" => "word",\r
+                       ),\r
+                       // Mise en évidence2 (gras + autre couleur)\r
+                       array(\r
+                               "id"          => 'miseenevidence2',\r
+                               "name"        => _T('enlumtypo:barre_miseenevidence2'),\r
+                               "className"   => "outil_miseenevidence2",\r
+                               "openWith"    => "[**", \r
+                               "closeWith"   => "*]",\r
+                               "display"     => true,\r
+                               "selectionType" => "word",\r
+                       ),\r
+                       // montrer une suppression\r
+                       array(\r
+                               "id"        => 'stroke_through_et',\r
+                               "name"      => _T('enlumtypo:barre_barre'), // :-)\r
+                               "className" => "outil_stroke_through_et", \r
+                               "openWith" => "<del>", \r
+                               "closeWith" => "</del>",\r
+                               "display"   => true,\r
+                               "selectionType" => "word",\r
+                       ),\r
+                       // Mise en exposant\r
+                       array(\r
+                               "id"          => 'exposant',\r
+                               "name"        => _T('enlumtypo:barre_exposant'),\r
+                               "className"   => "outil_exposant",\r
+                               "openWith"    => "<sup>", \r
+                               "closeWith"   => "</sup>",\r
+                               "display"     => true,\r
+                               "selectionType" => "word",\r
+                       ),\r
+                       // Mise en indice\r
+                       array(\r
+                               "id"          => 'indice',\r
+                               "name"        => _T('enlumtypo:barre_indice'),\r
+                               "className"   => "outil_indice",\r
+                               "openWith"    => "<sub>", \r
+                               "closeWith"   => "</sub>",\r
+                               "display"     => true,\r
+                               "selectionType" => "word",\r
+                       ),\r
+                       // cadre spip\r
+                       array(\r
+                               "id"          => 'barre_code',\r
+                               "name"        => _T($module_barre.':barre_code'),\r
+                               "className"   => "outil_barre_code", \r
+                               "openWith"    => "&lt;code&gt;", \r
+                               "closeWith"   => "&lt;/code&gt;",\r
+                               "display"     => true,\r
+                               "selectionType" => "word",\r
+                       ),\r
+               ),\r
+       ));\r
+       \r
+       // Appel Tableau\r
+       $barre->ajouterApres('notes', array(\r
+               "id"          => 'barre_tableau',\r
+               "name"        => _T('enlumtypo:barre_tableau'),\r
+               "className"   => "outil_barre_tableau",\r
+               "replaceWith" => 'function(markitup) { zone_selection = markitup.textarea; window.open("?exec=tableau_edit", "","scrollbars=yes,resizable=yes,width=700,height=600") }',\r
+               "display"     => true,\r
+               "selectionType" => "line",\r
+       ));\r
+       \r
+       $barre->set('quote', array(\r
+               "dropMenu"    => array(\r
+                       // poesie spip\r
+                       array(\r
+                               "id"          => 'barre_poesie',\r
+                               "name"        => _T($module_barre.':barre_poesie'),\r
+                               "className"   => "outil_barre_poesie", \r
+                               "openWith"    => "\n&lt;poesie&gt;", \r
+                               "closeWith"   => "&lt;/poesie&gt;\n",\r
+                               "display"     => true,\r
+                               "selectionType" => "line",\r
+                       ),\r
+               ),\r
+       ));     \r
+       \r
+       // Petites capitales\r
+       $barre->ajouterApres('italic', array(\r
+               "id"          => 'petitescapitales',\r
+               "name"        => _T('enlumtypo:barre_petitescapitales'),\r
+               "className"   => "outil_petitescapitales",\r
+               "openWith"    => "<sc>", \r
+               "closeWith"   => "</sc>",\r
+               "display"     => true,\r
+               "selectionType" => "word",\r
+       ));\r
+       \r
+       return $barres;\r
+}\r
+\r
+function typoenluminee_porte_plume_lien_classe_vers_icone($flux){\r
+       return array_merge($flux, array(\r
+               'outil_intertitre1' => array('spt-v1.png','-10px -226px'), //'intertitre.png'\r
+               'outil_intertitre2' => array('intertitre2.png','0'),\r
+               'outil_intertitre3' => array('intertitre3.png','0'),\r
+               'outil_alignerdroite' => array('right.png','0'),\r
+               'outil_alignergauche' => array('left.png','0'),\r
+               'outil_stroke_through_et' => array('spt-v1.png','-10px -946px'), //'text_strikethrough.png'\r
+               'outil_cadretexte' => array('cadretexte.png','0'),\r
+               'outil_speciaux' => array('tag.png','0'),\r
+               'outil_barre_code' => array('page_white_code_red.png','0'),\r
+               'outil_barre_cadre' => array('page_white_code.png','0'),\r
+\r
+               'outil_miseenevidence' => array('miseenevidence.png','0'),\r
+               'outil_miseenevidence2' => array('miseenevidence2.png','0'),\r
+               'outil_exposant' => array('exposant.png','0'),\r
+               'outil_indice' => array('indice.png','0'),\r
+               'outil_petitescapitales' => array('petitescapitales.png','0'),\r
+               'outil_barre_poesie' => array('poesie.png','0'),\r
+               \r
+               'outil_barre_tableau' => array('barre-tableau.png','0'),\r
+       ));\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/enluminures_typographiques_v3/exec/tableau_edit.php b/www/plugins/enluminures_typographiques_v3/exec/tableau_edit.php
new file mode 100644 (file)
index 0000000..a99aa00
--- /dev/null
@@ -0,0 +1,8 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+function exec_tableau_edit_dist() {\r
+       include_spip("public/assembler"); // Pour pouvoir utiliser recuperer_fond\r
+       echo recuperer_fond('editeur/tableau_edit');\r
+}\r
+?>
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/fonds/cfg_bte.html b/www/plugins/enluminures_typographiques_v3/fonds/cfg_bte.html
new file mode 100644 (file)
index 0000000..213a301
--- /dev/null
@@ -0,0 +1,14 @@
+<!-- titre=Enluminures Typo V3-->\r
+<!-- icone=img_pack/e.gif-->\r
+[(#SET{logo,\r
+<img src='#DOSSIER_SQUELETTE/../img_pack/moinecopiste.gif' width='59' height='85' alt='Logo Enluminures Typographiques' style="float:#LANG_RIGHT;" />\r
+})]\r
+<!-- descriptif=\r
+#GET{logo}\r
+<h4>Configuration des Enluminures Typographique V3</h4>\r
+-->\r
+#CACHE{0}\r
+\r
+<div class="ajax">\r
+       #FORMULAIRE_CONFIGURER_TYPOENLUMINEE\r
+</div>\r
diff --git a/www/plugins/enluminures_typographiques_v3/formulaires/configurer_typoenluminee.html b/www/plugins/enluminures_typographiques_v3/formulaires/configurer_typoenluminee.html
new file mode 100644 (file)
index 0000000..aaebf34
--- /dev/null
@@ -0,0 +1,106 @@
+<div class="formulaire_spip formulaire_configurer formulaire_#FORM">\r
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+       \r
+<form method="post" action="#ENV{action}"><div>[(#ENV{_cfg_}|form_hidden)]<input type="hidden" name="_meta_casier" value="bte" /></div>\r
+       #ACTION_FORMULAIRE{#ENV{action}}\r
+\r
+<ul><li class="fieldset"><fieldset><legend><:enlumtypo:cfg_puces:></legend></li>\r
+       <?php if (isset($GLOBALS['barre_typo_pas_de_fausses_puces'])) { ?>\r
+       <li><p class="explication">Configuré dans le mes_options par 'barre_typo_pas_de_fausses_puces'&nbsp;:<br /><?php if ($GLOBALS['barre_typo_pas_de_fausses_puces'] === true) { ?>Remplacement<?php } else { ?>Conserver le traitement par défaut de SPIP<?php } ?></p></li>\r
+       <?php } else { ?>\r
+       <li><label for="sc_puces">Puces</label>\r
+       <p class="explication">Remplacement des fausses puces de SPIP (- en début de ligne) par de vraies listes à puces (-* en début de ligne)</p>\r
+       <select name="puces" id="sc_puces" class="forml">\r
+               <option value="Oui"[ selected="(#ENV{puces,Non}|=={Oui}|?{selected})"]>Remplacement</option>\r
+               <option value="Non"[ selected="(#ENV{puces,Non}|=={Non}|?{selected})"]>Conserver le traitement par défaut de SPIP</option>\r
+       </select></li>\r
+       <?php } ?>\r
+</fieldset></ul>\r
+<fieldset><legend><:enlumtypo:cfg_titraille:></legend>\r
+       <p>Les valeurs par défaut sont basées sur la valeur historique de SPIP pour {{{}}} <=> H3. En HTML, il n'y a pas de H7 ce qui explique la balise choisie pour le niveau 5.</p>\r
+       <p>N'oubliez pas que la titraille sert à donner un sens dans la hiérarchisation des idées d'un texte, et <strong>surtout pas</strong> à obtenir un effet de taille de texte !</p>\r
+       <ul><li><p class="explication">Titraille de premier niveau&nbsp;: {{{}}} ou {{{* }}}</p></li>\r
+       <?php if (isset($GLOBALS['config_intertitre'])) { ?>\r
+       <li><p class="explication">Configuré dans le mes_options par 'debut_intertitre' et 'fin_intertitre'</p></li>\r
+       <?php } else { ?>\r
+       <li>\r
+       <label for="sc_titraille1open">Balise <strong>ouvrante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille1open" id="sc_titraille1open" value="[(#ENV{titraille1open,'<h3 class="spip">'})]" size="30" class="fondl" /><br />\r
+       <label for="sc_titraille1open">Balise <strong>fermante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille1close" id="sc_titraille1close" value="[(#ENV{titraille1close,'</h3>'})]" size="30" class="fondl" />\r
+       <?php } ?>\r
+       </li>\r
+       <li><p class="explication">Titraille de deuxième niveau&nbsp;: {{{** }}}</p></li>\r
+       <?php if (isset($GLOBALS['config_intertitre'])) { ?>\r
+       <li><p class="explication">Configuré dans le mes_options par 'debut_intertitre_2' et 'fin_intertitre_2'</p></li>\r
+       <?php } else { ?>\r
+       <li>\r
+       <label for="sc_titraille2open">Balise <strong>ouvrante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille2open" id="sc_titraille2open" value="[(#ENV{titraille2open,'<h4 class="spip">'})]" size="30" class="fondl" /><br />\r
+       <label for="sc_titraille2open">Balise <strong>fermante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille2close" id="sc_titraille2close" value="[(#ENV{titraille2close,'</h4>'})]" size="30" class="fondl" />\r
+       <?php } ?>\r
+       </li>\r
+       <li><p class="explication">Titraille de troisième niveau&nbsp;: {{{*** }}}</p></li>\r
+       <?php if (isset($GLOBALS['config_intertitre'])) { ?>\r
+       <li><p class="explication">Configuré dans le mes_options par 'debut_intertitre_3' et 'fin_intertitre_3'</p></li>\r
+       <?php } else { ?>\r
+       <li>\r
+       <label for="sc_titraille3open">Balise <strong>ouvrante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille3open" id="sc_titraille3open" value="[(#ENV{titraille3open,'<h5 class="spip">'})]" size="30" class="fondl" /><br />\r
+       <label for="sc_titraille3open">Balise <strong>fermante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille3close" id="sc_titraille3close" value="[(#ENV{titraille3close,'</h5>'})]" size="30" class="fondl" />\r
+       <?php } ?>\r
+       </li>\r
+       <li><p class="explication">Titraille de quatrième niveau&nbsp;: {{{**** }}}</p></li>\r
+       <?php if (isset($GLOBALS['config_intertitre'])) { ?>\r
+       <li><p class="explication">Configuré dans le mes_options par 'debut_intertitre_4' et 'fin_intertitre_4'</p></li>\r
+       <?php } else { ?>\r
+       <li>\r
+       <label for="sc_titraille4open">Balise <strong>ouvrante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille4open" id="sc_titraille4open" value="[(#ENV{titraille4open,'<h6 class="spip">'})]" size="30" class="fondl" /><br />\r
+       <label for="sc_titraille4open">Balise <strong>fermante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille4close" id="sc_titraille4close" value="[(#ENV{titraille4close,'</h6>'})]" size="30" class="fondl" />\r
+       <?php } ?>\r
+       </li>\r
+       <li><p class="explication">Titraille de cinquième niveau&nbsp;: {{{***** }}}</p></li>\r
+       <?php if (isset($GLOBALS['config_intertitre'])) { ?>\r
+       <li><p class="explication">Configuré dans le mes_options par 'debut_intertitre_5' et 'fin_intertitre_5'</p></li>\r
+       <?php } else { ?>\r
+       <li>\r
+       <label for="sc_titraille5open">Balise <strong>ouvrante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille5open" id="sc_titraille5open" value="[(#ENV{titraille5open,'<strong class="spip titraille5">'})]" size="30" class="fondl" /><br />\r
+       <label for="sc_titraille5open">Balise <strong>fermante</strong>&nbsp;:</label>\r
+       <input type="text" name="titraille5close" id="sc_titraille5close" value="[(#ENV{titraille5close,'</strong>'})]" size="30" class="fondl" />\r
+       <?php } ?>\r
+       </li>\r
+       </ul>\r
+</fieldset>\r
+<ul><li class="fieldset"><fieldset><legend><:enlumtypo:cfg_insertcss:></legend></li>\r
+       <?php if (isset($GLOBALS['BarreTypoEnrichie_Preserve_Header'])) { \r
+?>\r
+       <li><p class="explication">Configuré dans le mes_options par 'BarreTypoEnrichie_Preserve_Header'\r
+       <?php \r
+       echo ($GLOBALS['BarreTypoEnrichie_Preserve_Header']=='Oui')?"Ne pas faire l'insertion automatique":"Insertion automatique";\r
+       ?>\r
+       </p></li>\r
+       <?php\r
+       } else { ?>\r
+       <li><label for="sc_insertcss">&#35;INSERT_HEAD</label>\r
+       <p class="explication">Insertion automatique des CSS spécifiques à la BTE dans l'espace public (via &#35;INSERT_HEAD dans les squelettes)</p>\r
+       <select name="insertcss" id="sc_insertcss" class="forml">\r
+               <option value="Oui"[ selected="(#ENV{insertcss,Oui}|=={Oui}|?{selected})"]>Insertion automatique</option>\r
+               <option value="Non"[ selected="(#ENV{insertcss,Oui}|=={Non}|?{selected})"]>Ne pas faire l'insertion automatique</option>\r
+       </select></li>\r
+       <?php } ?>\r
+</fieldset></ul>\r
+\r
+\r
+       <p class="boutons">\r
+               <input type="submit" name="reinit" class="submit" value="<:mediabox:bouton_reinitialiser:>" />\r
+               <input type="submit" name="enregistrer" class="submit" value="<:bouton_valider:>" />\r
+       </p>\r
+\r
+</form>\r
+</div>
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/avances.png b/www/plugins/enluminures_typographiques_v3/icones_barre/avances.png
new file mode 100644 (file)
index 0000000..628cf2d
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/avances.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/barre-tableau.png b/www/plugins/enluminures_typographiques_v3/icones_barre/barre-tableau.png
new file mode 100644 (file)
index 0000000..c895a1f
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/barre-tableau.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/barre-wiki.png b/www/plugins/enluminures_typographiques_v3/icones_barre/barre-wiki.png
new file mode 100644 (file)
index 0000000..8d1a035
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/barre-wiki.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/cadretexte.png b/www/plugins/enluminures_typographiques_v3/icones_barre/cadretexte.png
new file mode 100644 (file)
index 0000000..29c4ec9
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/cadretexte.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/center.png b/www/plugins/enluminures_typographiques_v3/icones_barre/center.png
new file mode 100644 (file)
index 0000000..38a0659
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/center.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/eacute-maj.png b/www/plugins/enluminures_typographiques_v3/icones_barre/eacute-maj.png
new file mode 100644 (file)
index 0000000..4deee16
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/eacute-maj.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/exposant.png b/www/plugins/enluminures_typographiques_v3/icones_barre/exposant.png
new file mode 100644 (file)
index 0000000..4cb2cfe
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/exposant.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/indice.png b/www/plugins/enluminures_typographiques_v3/icones_barre/indice.png
new file mode 100644 (file)
index 0000000..357b7fe
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/indice.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/intertitre2.png b/www/plugins/enluminures_typographiques_v3/icones_barre/intertitre2.png
new file mode 100644 (file)
index 0000000..da86b80
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/intertitre2.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/intertitre3.png b/www/plugins/enluminures_typographiques_v3/icones_barre/intertitre3.png
new file mode 100644 (file)
index 0000000..34f3a6a
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/intertitre3.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/left.png b/www/plugins/enluminures_typographiques_v3/icones_barre/left.png
new file mode 100644 (file)
index 0000000..21bfe4c
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/left.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/listenum.png b/www/plugins/enluminures_typographiques_v3/icones_barre/listenum.png
new file mode 100644 (file)
index 0000000..0492387
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/listenum.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/listepuces.png b/www/plugins/enluminures_typographiques_v3/icones_barre/listepuces.png
new file mode 100644 (file)
index 0000000..fc1d35a
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/listepuces.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence.png b/www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence.png
new file mode 100644 (file)
index 0000000..1dfa7dd
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence2.png b/www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence2.png
new file mode 100644 (file)
index 0000000..87a3c72
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/miseenevidence2.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/oelig-maj.png b/www/plugins/enluminures_typographiques_v3/icones_barre/oelig-maj.png
new file mode 100644 (file)
index 0000000..c335cf1
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/oelig-maj.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/oelig.png b/www/plugins/enluminures_typographiques_v3/icones_barre/oelig.png
new file mode 100644 (file)
index 0000000..89bdb5a
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/oelig.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code.png b/www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code.png
new file mode 100644 (file)
index 0000000..0c76bd1
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code_red.png b/www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code_red.png
new file mode 100644 (file)
index 0000000..87a6914
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/page_white_code_red.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/petitescapitales.png b/www/plugins/enluminures_typographiques_v3/icones_barre/petitescapitales.png
new file mode 100644 (file)
index 0000000..9122ea2
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/petitescapitales.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/poesie.png b/www/plugins/enluminures_typographiques_v3/icones_barre/poesie.png
new file mode 100644 (file)
index 0000000..3c5bbfe
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/poesie.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/right.png b/www/plugins/enluminures_typographiques_v3/icones_barre/right.png
new file mode 100644 (file)
index 0000000..79d3b19
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/right.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/tag.png b/www/plugins/enluminures_typographiques_v3/icones_barre/tag.png
new file mode 100644 (file)
index 0000000..e093032
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/tag.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/icones_barre/text_strikethrough.png b/www/plugins/enluminures_typographiques_v3/icones_barre/text_strikethrough.png
new file mode 100644 (file)
index 0000000..612058a
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/icones_barre/text_strikethrough.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/img_pack/e.gif b/www/plugins/enluminures_typographiques_v3/img_pack/e.gif
new file mode 100644 (file)
index 0000000..8a27a20
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/img_pack/e.gif differ
diff --git a/www/plugins/enluminures_typographiques_v3/img_pack/moinecopiste.gif b/www/plugins/enluminures_typographiques_v3/img_pack/moinecopiste.gif
new file mode 100644 (file)
index 0000000..c16f858
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/img_pack/moinecopiste.gif differ
diff --git a/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_ar.php b/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_ar.php
new file mode 100644 (file)
index 0000000..a54972a
--- /dev/null
@@ -0,0 +1,46 @@
+<?php\r
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+\r
+// Aide des boutons supplémentaires de la barre typo\r
+'barre_intertitre2' => '{2{&#1593;&#1606;&#1608;&#1575;&#1606; &#1601;&#1602;&#1585;&#1577; &#1605;&#1587;&#1578;&#1608;&#1609; 2}2}',\r
+'barre_intertitre3' => '{3{&#1593;&#1606;&#1608;&#1575;&#1606; &#1601;&#1602;&#1585;&#1577; &#1605;&#1587;&#1578;&#1608;&#1609; 3}3}',\r
+'barre_miseenevidence' => '[*&#1573;&#1576;&#1585;&#1575;&#1586;*]',\r
+'barre_miseenevidence2' => '[**&#1573;&#1576;&#1585;&#1575;&#1586;*] &#1575;&#1604;&#1606;&#1589; (&#1604;&#1608;&#1606; &#1570;&#1582;&#1585;)',\r
+\r
+'barre_exposant' => '&#1578;&#1581;&#1608;&#1610;&#1604; &#1575;&#1604;&#1609;\r
+ &lt;sup&gt;&#1606;&#1589; &#1601;&#1608;&#1602;&#1610;&lt;/sup&gt;',\r
\r
+ 'barre_indice' => '&#1578;&#1581;&#1608;&#1610;&#1604; &#1575;&#1604;&#1609;\r
+&lt;sub&gt;&#1606;&#1589; &#1587;&#1601;&#1604;&#1610;&lt;/sub&gt;',\r
\r
+'barre_petitescapitales' => '&#1578;&#1581;&#1608;&#1610;&#1604; &#1575;&#1604;&#1609; &lt;sc&gt;&#1581;&#1585;&#1608;&#1601; &#1603;&#1576;&#1610;&#1585;&#1577; &#1605;&#1589;&#1594;&#1585;&#1577;&lt;/sc&gt;',\r
+'barre_centrer' => '[|&#1578;&#1608;&#1587;&#1610;&#1591;|] &#1575;&#1604;&#1601;&#1602;&#1585;&#1577;',\r
+'barre_alignerdroite' => '&#1605;&#1581;&#1575;&#1584;&#1575;&#1577; &#1575;&#1604;&#1609; [/&#1575;&#1604;&#1610;&#1605;&#1610;&#1606;/]',\r
+'barre_alignergauche' => '&#1605;&#1581;&#1575;&#1584;&#1575;&#1577; &#1575;&#1604;&#1609; [!&#1575;&#1604;&#1610;&#1587;&#1575;&#1585;!]',\r
+'barre_encadrer' => '&#1608;&#1590;&#1593; &#1601;&#1610; [(&#1573;&#1591;&#1575;&#1585;)]',\r
+\r
+'barre_barre' => '&lt;del&gt;&#1588;&#1591;&#1576;&lt;/del&gt; &#1575;&#1604;&#1606;&#1589;',\r
+\r
+'barre_avances' => '&#1575;&#1604;&#1575;&#1578;&#1580;&#1575;&#1607;&#1548; &#1575;&#1604;&#1575;&#1578;&#1580;&#1575;&#1607;!',\r
+'barre_boutonsavances' => '&#1573;&#1583;&#1575;&#1585;&#1577; &#1573;&#1590;&#1575;&#1601;&#1610;&#1577; &#1604;&#1604;&#1605;&#1581;&#1575;&#1584;&#1575;&#1577; &#1604;&#1604;&#1575;&#1587;&#1578;&#1582;&#1583;&#1575;&#1605; &#1576;&#1578;&#1593;&#1602;&#1604;',\r
+'barre_tableau' => '&#1573;&#1583;&#1585;&#1575;&#1580; &#1580;&#1583;&#1608;&#1604; &#1571;&#1608; &#1578;&#1593;&#1583;&#1610;&#1604; &#1580;&#1583;&#1608;&#1604; (&#1578;&#1581;&#1583;&#1610;&#1583;&#1607; &#1571;&#1608;&#1604;&#1575;&#1611;)',\r
+\r
+'barre_formatages_speciaux' => '&#1578;&#1606;&#1587;&#1610;&#1602;&#1575;&#1578; &#1582;&#1575;&#1589;&#1577;',\r
+'barre_code' => '&#1578;&#1606;&#1587;&#1610;&#1602; &lt;code&gt;&#1603;&#1585;&#1605;&#1608;&#1586; &#1576;&#1585;&#1605;&#1580;&#1610;&#1577;&lt;/code&gt;',\r
+'barre_cadre' => '&#1608;&#1590;&#1593; &#1601;&#1610; &lt;cadre&gt;&#1573;&#1591;&#1575;&#1585;&lt;/cadre&gt;',\r
+'barre_poesie' => '&lt;poesie&gt;&#1588;&#1593;&#1585;&lt;/poesie&gt;',\r
+\r
+'cfg_puces' => '&#1605;&#1593;&#1575;&#1604;&#1580;&#1577; &#1575;&#1604;&#1604;&#1608;&#1575;&#1574;&#1581;',\r
+'cfg_titraille' => '&#1593;&#1606;&#1575;&#1608;&#1610;&#1606;',\r
+'cfg_insertcss' => '&#1575;&#1583;&#1585;&#1575;&#1580; &#1608;&#1585;&#1602;&#1577; &#1575;&#1606;&#1605;&#1575;&#1591;',\r
+\r
+'tableau_enregistrer' => '&#1581;&#1601;&#1592;',\r
+'tableau_prem_ligne' => '&#1575;&#1604;&#1587;&#1591;&#1585; &#1575;&#1604;&#1571;&#1608;&#1604;',\r
+'tableau_resume' => '&#1575;&#1604;&#1582;&#1604;&#1575;&#1589;&#1577;',\r
+'tableau_titre' => '&#1575;&#1604;&#1593;&#1606;&#1608;&#1575;&#1606;'\r
+\r
+);\r
+?>\r
diff --git a/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_en.php b/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_en.php
new file mode 100644 (file)
index 0000000..5c1d65f
--- /dev/null
@@ -0,0 +1,44 @@
+<?php\r
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+\r
+// Aide des boutons supplémentaires de la barre typo\r
+'barre_intertitre2' => 'Turn into a {2{2nd-level subtitle}2}',\r
+'barre_intertitre3' => 'Turn into a {3{3rd-level subtitle}3}',\r
+'barre_miseenevidence' => '[*Emphasize*] the text',\r
+'barre_miseenevidence2' => '[**Emphasize*] the text(2nd colour)',\r
+\r
+'barre_exposant' => 'Superscript',\r
+\r
+'barre_indice' => 'Subscript',\r
+\r
+'barre_petitescapitales' => 'Small caps',\r
+'barre_centrer' => '[|Centre|] the paragraph',\r
+'barre_alignerdroite' => '[/Right-align/] the paragraph',\r
+'barre_alignergauche' => '[!left-align!] the paragraph',\r
+'barre_encadrer' => '[(Place a border)] round the paragraph',\r
+\r
+'barre_barre' => '&lt;del&gt;Strikethrough&lt;/del&gt;',\r
+\r
+'barre_avances' => 'Meaning, not apparence!',\r
+'barre_boutonsavances' => 'Extra justifications, use with caution!',\r
+'barre_tableau' => 'Insert/modify (select it first) a table',\r
+\r
+'barre_formatages_speciaux' => 'Special formats',\r
+'barre_code' => 'Turn into &lt;code&gt;programming code&lt;/code&gt;',\r
+'barre_cadre' => 'Put in a &lt;cadre&gt;text box&lt;/cadre&gt;',\r
+'barre_poesie' => 'display as &lt;poesie&gt;poetry&lt;/poesie&gt;',\r
+\r
+'cfg_puces' => 'Bullets',\r
+'cfg_titraille' => 'Headings',\r
+'cfg_insertcss' => 'Insert CSS',\r
+\r
+'tableau_enregistrer' => 'Save',\r
+'tableau_prem_ligne' => 'First row',\r
+'tableau_resume' => 'Summary',\r
+'tableau_titre' => 'Title'\r
+\r
+);\r
+?>\r
diff --git a/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_es.php b/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_es.php
new file mode 100644 (file)
index 0000000..e3dafac
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+// This is a SPIP language file  --  Esto es un archivo de idioma SPIP\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+\r
+// Aide des boutons supplémentaires de la barre typo\r
+'barre_intertitre2' => 'Transformar en {2{intert&iacute;tulos nivel dos}2}',\r
+'barre_intertitre3' => 'Transformar en {3{intert&iacute;tulos nivel tres}3}',\r
+'barre_miseenevidence' => 'Poner el texto en [*evidencia*]',\r
+'barre_exposant' => 'Poner el texto en &lt;sup&gt;potencia&lt;/sup&gt;',\r
+'barre_petitescapitales' => 'Poner el texto en &lt;sc&gt;may&uacute;sculas peque&ntilde;as&lt;/sc&gt;',\r
+'barre_centrer' => '[|Centrar|] el p&aacute;rrafo',\r
+'barre_alignerdroite' => '[/Al&iacute;nea a la derecha/] el p&aacute;rrafo',\r
+'barre_encadrer' => '[(Encuadrar)] el p&aacute;rrafo',\r
+\r
+'barre_poesie' => 'Mettre en forme comme une &lt;poesie&gt;po&eacute;sie&lt;/poesie&gt;',\r
+\r
+'barre_avances' => 'Du sens, du sens&nbsp;!',\r
+'barre_boutonsavances' => 'Mises en sens suppl&eacute;mentaires, &agrave; utiliser avec mod&eacute;ration et discernement&nbsp;!',\r
+\r
+'cfg_puces' => 'Traitement des puces',\r
+'cfg_titraille' => 'Titraille',\r
+'cfg_insertcss' => 'Insertion CSS'\r
+\r
+);\r
+?>\r
diff --git a/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_fr.php b/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_fr.php
new file mode 100644 (file)
index 0000000..669838e
--- /dev/null
@@ -0,0 +1,45 @@
+<?php\r
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+\r
+// Aide des boutons supplémentaires de la barre typo\r
+'barre_intertitre2' => 'Transformer en {{{**intertitre niveau deux}}}',\r
+'barre_intertitre3' => 'Transformer en {{{***intertitre niveau trois}}}',\r
+'barre_miseenevidence' => 'Mettre le texte en [*&eacute;vidence*]',\r
+'barre_miseenevidence2' => 'Mettre le texte en [**&eacute;vidence*] (2e couleur)',\r
+\r
+'barre_exposant' => 'Mettre le texte en &lt;sup&gt;exposant&lt;/sup&gt;',\r
+\r
+'barre_indice' => 'Mettre le texte en &lt;sub&gt;indice&lt;/sub&gt;',\r
+\r
+'barre_petitescapitales' => 'Mettre le texte en &lt;sc&gt;petites capitales&lt;/sc&gt;',\r
+'barre_centrer' => '[|Centrer|] le paragraphe',\r
+'barre_alignerdroite' => '[/Aligne &agrave; droite/] le paragraphe',\r
+'barre_alignergauche' => '[!Aligne &agrave; gauche!] le paragraphe',\r
+'barre_encadrer' => '[(Encadrer)] le paragraphe',\r
+\r
+'barre_barre' => '&lt;del&gt;Barrer&lt;/del&gt; le texte',\r
+\r
+'barre_avances' => 'Du sens, du sens&nbsp;!',\r
+'barre_boutonsavances' => 'Mises en sens suppl&eacute;mentaires, &agrave; utiliser avec mod&eacute;ration et discernement&nbsp;!',\r
+'barre_tableau' => 'Ins&eacute;rer/modifier (le s&eacute;lectionner avant) un tableau',\r
+\r
+'barre_formatages_speciaux' => 'Formatage sp&eacute;ciaux',\r
+'barre_code' => 'Mettre en forme un &lt;code&gt;code informatique&lt;/code&gt;',\r
+'barre_cadre' => 'Placer dans une &lt;cadre&gt;zone de saisie de texte&lt;/cadre&gt;',\r
+'barre_poesie' => 'Mettre en forme comme une &lt;poesie&gt;po&eacute;sie&lt;/poesie&gt;',\r
+\r
+'cfg_puces' => 'Traitement des puces',\r
+'cfg_titraille' => 'Titraille',\r
+'cfg_insertcss' => 'Insertion CSS',\r
+'configuration_typoenluminee' => 'Enluminures Typographiques',\r
+\r
+'tableau_enregistrer' => 'Enregistrer',\r
+'tableau_prem_ligne' => 'Premi&egrave;re ligne',\r
+'tableau_resume' => 'R&eacute;sum&eacute;',\r
+'tableau_titre' => 'Titre'\r
+\r
+);\r
+?>\r
diff --git a/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_it.php b/www/plugins/enluminures_typographiques_v3/lang/enlumtypo_it.php
new file mode 100644 (file)
index 0000000..39a60a8
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+\r
+// Aide des boutons supplémentaires de la barre typo\r
+'barre_intertitre2' => 'Converti in {2{sottotitolo 2o-livello}2}',\r
+'barre_intertitre3' => 'Converti in {3{sottotitolo 3o-livello}3}',\r
+'barre_miseenevidence' => '[*Evidenziare*] il testo',\r
+'barre_exposant' => 'Sovrimpressione',\r
+'barre_petitescapitales' => 'Maiuscoletto',\r
+'barre_centrer' => '[|Centrare|] il paragrafo',\r
+'barre_alignerdroite' => '[/allinea a destra/] il paragrafo',\r
+'barre_encadrer' => '[(Riquadro)] attorno al paragrafo',\r
+\r
+'barre_poesie' => 'stile poetico',\r
+\r
+'barre_avances' => 'Allineamento&nbsp;!',\r
+'barre_boutonsavances' => 'Formattazione supplementare, utilizzare con moderazione e discernimento&nbsp;!',\r
+\r
+'cfg_puces' => 'Traitement des puces',\r
+'cfg_titraille' => 'Titraille',\r
+'cfg_insertcss' => 'Insertion CSS'\r
+\r
+);\r
+?>
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/lang/paquet-typoenluminee_fr.php b/www/plugins/enluminures_typographiques_v3/lang/paquet-typoenluminee_fr.php
new file mode 100644 (file)
index 0000000..bfe2583
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+// Ceci est un fichier langue de SPIP -- This is a SPIP language file
+
+///  Fichier produit par PlugOnet
+// Module: paquet-typoenluminee
+// Langue: fr
+// Date: 08-01-2012 17:02:08
+// Items: 2
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+// T
+       'typoenluminee_description' => 'Ce plugin ajoute des raccourcis typographiques et des boutons au porte plume. Par exemple :\r
+-* Paragraphes :\r
+-** {{Sous-titres}} <code>{{{**</code>Texte du titre<code>}}}</code>, le nombre d\'étoiles (*) variant de 2 à 5, la barre de raccourcis ne proposant que 2 et 3\r
+-** {{Centrer}} <code>[|</code>Paragraphe centré<code>|]</code>\r
+-** {{Aligner à droite}} <code>[/</code>Paragraphe aligné à droite<code>/]</code>\r
+-** {{Encadrer}} <code>[(</code>Paragraphe à encadrer<code>)]</code>\r
+-* Caractères :\r
+-** {{Mise en évidence}} <code>[*</code>texte en évidence<code>*]</code>\r
+-** {{Mise en évidence variante}} <code>[**</code>texte en évidence (autre couleur)<code>*]</code>\r
+-** {{Mise en exposant}} {&lt;sup&gt;}texte en exposant{&lt;/sup&gt;}\r
+-** {{Petites capitales}} {&lt;sc&gt;}texte en petite capitales{&lt;/sc&gt;}\r
+-** {{Biffé}} {&lt;del&gt;}texte biffé{&lt;/del&gt;}
+
+',
+       'typoenluminee_slogan' => 'Plein de raccourcis pour la mise en forme !',
+);
+?>
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/paquet.xml b/www/plugins/enluminures_typographiques_v3/paquet.xml
new file mode 100644 (file)
index 0000000..047b319
--- /dev/null
@@ -0,0 +1,35 @@
+<paquet
+       prefix="typoenluminee"
+       categorie="edition"
+       version="3.3.2"
+       etat="stable"
+       compatibilite="[2.0.3;3.0.99]"
+       logo="prive/themes/spip/images/typoenluminee-32.png"
+       documentation="http://www.spip-contrib.net/Enluminures-typographiques-V3-pour-SPIP-2-avec"
+>      
+
+       <nom>Enluminures typographiques</nom>
+       <!-- Plein de raccourcis pour la mise en forme ! -->
+
+       <auteur lien="http://www.spip-contrib.net/_Jacques-PYRAT_">Jacques</auteur>
+       <auteur lien="http://www.spip-contrib.net/_Francois-Schreuer_">François</auteur>
+
+       <copyright>2007</copyright>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>
+
+       <pipeline nom="pre_propre" inclure="typoenluminee.php" />
+       <pipeline nom="post_propre" inclure="typoenluminee.php" />
+       <pipeline nom="pre_typo" inclure="typoenluminee.php" />
+       <pipeline nom="post_typo" inclure="typoenluminee.php" />
+       <pipeline nom="nettoyer_raccourcis_typo" inclure="typoenluminee.php" />
+       <pipeline nom="insert_head_css" inclure="typoenluminee_pipelines.php" />
+       <pipeline nom="insert_head" inclure="typoenluminee_pipelines.php" />
+       <pipeline nom="header_prive" inclure="typoenluminee_pipelines.php" />
+       <pipeline nom="porte_plume_barre_pre_charger" inclure="enluminures_typo_pipelines.php" />
+       <pipeline nom="porte_plume_lien_classe_vers_icone" inclure="enluminures_typo_pipelines.php" />
+       
+       <menu nom="configurer_typoenluminee" titre="enlumtypo:configuration_typoenluminee" parent="menu_squelette" icone="images/typoenluminee-16.png" />
+
+       <necessite nom="porte_plume" compatibilite="[1.2.2;[" />
+</paquet>
diff --git a/www/plugins/enluminures_typographiques_v3/plugin.xml b/www/plugins/enluminures_typographiques_v3/plugin.xml
new file mode 100644 (file)
index 0000000..aba71e0
--- /dev/null
@@ -0,0 +1,70 @@
+<plugin>\r
+       <nom>Enluminures typographiques</nom>\r
+       <slogan>Plein de raccourcis pour la mise en forme !</slogan>\r
+       <auteur>[Jacques->http://www.spip-contrib.net/_Jacques-PYRAT_], &#224; partir des raccourcis mis en place par [Fran&#231;ois->http://www.spip-contrib.net/_Francois-Schreuer_]</auteur>\r
+       <licence>&#169; 2007 GNU/GPL</licence>\r
+       <lien>http://www.spip-contrib.net/Enluminures-typographiques-V3-pour-SPIP-2-avec</lien>\r
+       <version>3.3.2</version>\r
+       <etat>stable</etat>\r
+       <description>Ce plugin ajoute des raccourcis typographiques et des boutons au porte plume. Par exemple :\r
+-* Paragraphes :\r
+-** {{Sous-titres}} <code>{{{**</code>Texte du titre<code>}}}</code>, le nombre d'&#233;toiles (*) variant de 2 &#224; 5, la barre de raccourcis ne proposant que 2 et 3\r
+-** {{Centrer}} <code>[|</code>Paragraphe centr&#233;<code>|]</code>\r
+-** {{Aligner &#224; droite}} <code>[/</code>Paragraphe align&#233; &#224; droite<code>/]</code>\r
+-** {{Encadrer}} <code>[(</code>Paragraphe &#224; encadrer<code>)]</code>\r
+-* Caract&#232;res :\r
+-** {{Mise en &#233;vidence}} <code>[*</code>texte en &#233;vidence<code>*]</code>\r
+-** {{Mise en &#233;vidence variante}} <code>[**</code>texte en &#233;vidence (autre couleur)<code>*]</code>\r
+-** {{Mise en exposant}} {&lt;sup&gt;}texte en exposant{&lt;/sup&gt;}\r
+-** {{Petites capitales}} {&lt;sc&gt;}texte en petite capitales{&lt;/sc&gt;}\r
+-** {{Biff&#233;}} {&lt;del&gt;}texte biff&#233;{&lt;/del&gt;}\r
+\r
+{{Param&#233;trage}} : vous pouvez modifier le fonctionnement du plugin par votre fichier ecrire/mes_options.php ou en installant le plugin cfg (les options de cfg sont priortitaires par rapport &#224; celles de mes_options.php !)\r
+       </description>\r
+       <prefix>typoenluminee</prefix>\r
+       <icon>img_pack/moinecopiste.gif</icon>\r
+\r
+       <pipeline>\r
+               <nom>pre_propre</nom>\r
+               <inclure>typoenluminee.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>post_propre</nom>\r
+               <inclure>typoenluminee.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>pre_typo</nom>\r
+               <inclure>typoenluminee.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>post_typo</nom>\r
+               <inclure>typoenluminee.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>nettoyer_raccourcis_typo</nom>\r
+               <inclure>typoenluminee.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>insert_head_css</nom>\r
+               <inclure>typoenluminee_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>insert_head</nom>\r
+               <inclure>typoenluminee_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>header_prive</nom>\r
+               <inclure>typoenluminee_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>porte_plume_barre_pre_charger</nom>\r
+               <inclure>enluminures_typo_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>porte_plume_lien_classe_vers_icone</nom>\r
+               <inclure>enluminures_typo_pipelines.php</inclure>\r
+       </pipeline>\r
+       <categorie>edition</categorie>\r
+       <necessite id="SPIP" version="[2.0.3;3.0.99]" />\r
+       <necessite id="porte_plume" version="[1.2.2;]" />\r
+</plugin>\r
diff --git a/www/plugins/enluminures_typographiques_v3/prive/squelettes/contenu/configurer_typoenluminee.html b/www/plugins/enluminures_typographiques_v3/prive/squelettes/contenu/configurer_typoenluminee.html
new file mode 100644 (file)
index 0000000..7926bbf
--- /dev/null
@@ -0,0 +1,5 @@
+[(#AUTORISER{configurer,typoenluminee}|sinon_interdire_acces)]\r
+<h1 class="grostitre"><:enlumtypo:configuration_typoenluminee:></h1>\r
+<div class="ajax">\r
+       #FORMULAIRE_CONFIGURER_TYPOENLUMINEE\r
+</div>
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-16.png b/www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-16.png
new file mode 100644 (file)
index 0000000..edb0d98
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-16.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-32.png b/www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-32.png
new file mode 100644 (file)
index 0000000..76fbc36
Binary files /dev/null and b/www/plugins/enluminures_typographiques_v3/prive/themes/spip/images/typoenluminee-32.png differ
diff --git a/www/plugins/enluminures_typographiques_v3/svn.revision b/www/plugins/enluminures_typographiques_v3/svn.revision
new file mode 100644 (file)
index 0000000..9924c51
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/porte_plume_extras/enluminures_typographiques_v3
+Revision: 66428
+Dernier commit: 2012-10-02 11:00:02 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/porte_plume_extras/enluminures_typographiques_v3</origine>
+<revision>66428</revision>
+<commit>2012-10-02 11:00:02 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/typoenluminee.php b/www/plugins/enluminures_typographiques_v3/typoenluminee.php
new file mode 100644 (file)
index 0000000..82bcfc9
--- /dev/null
@@ -0,0 +1,258 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/*\r
+  * Ce plugin rajoute des raccourcis typographique et ameliore les possibilites de la barre typographique pour les redacteurs\r
+*/\r
+\r
+       /*\r
+        *    Fonctions de ces filtres :\r
+        *     Ils rajoutent quelques racourcis typo a SPIP\r
+        *\r
+        *     Syntaxe des raccourcis :\r
+        *           [/texte/] : aligner le texte a droite\r
+        *           [!texte!] : aligner le texte a gauche\r
+        *           [|texte|] : centrer le texte\r
+        *           [(texte)] : encadrer le texte (occupe toute la largeur de la page, a mettre autour d'un paragraphe)\r
+        *           [*texte*] : encadrer/surligner le texte (une partie a l'interieur d'un paragraphe)\r
+        *           [**texte*] : variante encadrer/surligner le texte (une partie a l'interieur d'un paragraphe)\r
+        *           <sup>texte</sup> : mettre en exposant le texte selectionne\r
+        *           <sub>texte</sub> : mettre en indice le texte selectionne\r
+        *\r
+        *     Styles pour les encadrements a rajouter dans votre feuille de style :\r
+        *            .texteencadre-spip {\r
+        *              background: #FFE;\r
+        *              border-bottom: 2px solid #999999;\r
+        *              border-left: 1px solid #EEEEEE;\r
+        *              border-right: 2px solid #999999;\r
+        *              border-top: 1px solid #EEEEEE;\r
+        *              padding: .25em;\r
+        *           }\r
+        *           .caractencadre-spip {\r
+        *              border: 1px solid #666;\r
+        *              padding: 0px .5em 0px .5em;\r
+        *           }\r
+        *\r
+       */\r
+\r
+// Gerer les variables de personnalisation, fonction depreciee sous SPIP 2.0\r
+// A suivre sur la methode...\r
+if(!function_exists('tester_variable')) {\r
+       function tester_variable($var, $val){\r
+               if (!isset($GLOBALS[$var]))     $GLOBALS[$var] = $val;\r
+       }\r
+}\r
+\r
+function typoenluminee_pre_propre($texte) {\r
+       if(!$texte) return $texte;\r
+\r
+       static $chercher_raccourcis=NULL;\r
+       static $remplacer_raccourcis=NULL;\r
+       \r
+       if ($chercher_raccourcis===NULL) {\r
+       \r
+               // tous les elements block doivent etre introduits ici\r
+               // pour etre pris en charge par paragrapher\r
+       \r
+               // Definition des differents intertitres possibles, si pas deja definies\r
+               if ((!function_exists('lire_config')) OR (isset($GLOBALS['config_intertitre']))) {\r
+                       tester_variable('debut_intertitre', '<h3 class="spip">');\r
+                       tester_variable('fin_intertitre', '</h3>');\r
+                       tester_variable('debut_intertitre_2', '<h4 class="spip">');\r
+                       tester_variable('fin_intertitre_2', '</h4>');\r
+                       tester_variable('debut_intertitre_3', '<h5 class="spip">');\r
+                       tester_variable('fin_intertitre_3', '</h5>');\r
+                       tester_variable('debut_intertitre_4', '<h6 class="spip">');\r
+                       tester_variable('fin_intertitre_4', '</h6>');\r
+                       tester_variable('debut_intertitre_5', '<strong class="spip titraille5">');\r
+                       tester_variable('fin_intertitre_5', '</strong>');\r
+               } else {\r
+                       $GLOBALS['debut_intertitre'] = lire_config('bte/titraille1open','<h3 class="spip">');\r
+                       $GLOBALS['fin_intertitre'] = lire_config('bte/titraille1close','</h3>');\r
+                       $GLOBALS['debut_intertitre_2'] = lire_config('bte/titraille2open','<h4 class="spip">');\r
+                       $GLOBALS['fin_intertitre_2'] = lire_config('bte/titraille2close','</h4>');\r
+                       $GLOBALS['debut_intertitre_3'] = lire_config('bte/titraille3open','<h5 class="spip">');\r
+                       $GLOBALS['fin_intertitre_3'] = lire_config('bte/titraille3close','</h5>');\r
+                       $GLOBALS['debut_intertitre_4'] = lire_config('bte/titraille4open','<h6 class="spip">');\r
+                       $GLOBALS['fin_intertitre_4'] = lire_config('bte/titraille4close','</h6>');\r
+                       $GLOBALS['debut_intertitre_5'] = lire_config('bte/titraille5open','<strong class="spip titraille5">');\r
+                       $GLOBALS['fin_intertitre_5'] = lire_config('bte/titraille5close','</strong>');\r
+               }\r
+       \r
+               tester_variable('toujours_paragrapher', false);\r
+       \r
+               global $debut_intertitre, $fin_intertitre;\r
+               global $debut_intertitre_2, $fin_intertitre_2;\r
+               global $debut_intertitre_3, $fin_intertitre_3;\r
+               global $debut_intertitre_4, $fin_intertitre_4;\r
+               global $debut_intertitre_5, $fin_intertitre_5;\r
+       \r
+               $chercher_raccourcis=array();\r
+               $remplacer_raccourcis=array();\r
+       \r
+               /* 9b */        $chercher_raccourcis[]="/(^|[^{])[{][{][{]\*\*\*\*\*(.*)[}][}][}]($|[^}])/SUms";\r
+               /* 9 */         $chercher_raccourcis[]="/(^|[^{])[{][{][{]\*\*\*\*(.*)[}][}][}]($|[^}])/SUms";\r
+               /* 7 */         $chercher_raccourcis[]="/(^|[^{])[{][{][{]\*\*\*(.*)[}][}][}]($|[^}])/SUms";\r
+               /* 5 */         $chercher_raccourcis[]="/(^|[^{])[{][{][{]\*\*(.*)[}][}][}]($|[^}])/SUms";\r
+               /* 3 */         $chercher_raccourcis[]="/(^|[^{])[{][{][{]\*(.*)[}][}][}]($|[^}])/SUms";\r
+               /* 1 */         $chercher_raccourcis[]="/(^|[^{])[{][{][{](.*)[}][}][}]($|[^}])/SUms";\r
+               /* 11 */        $chercher_raccourcis[]="/\{(§|§)\{/S"; # Â§ Pour gerer l'unicode aussi !\r
+               /* 12 */        $chercher_raccourcis[]="/\}(§|§)\}/S"; # ne pas sauvergarder ce fichier en utf8 !\r
+\r
+               /* 9b */        $remplacer_raccourcis[]="\$1\n\n$debut_intertitre_5\$2$fin_intertitre_5\n\n\$3";\r
+               /*  9 */        $remplacer_raccourcis[]="\$1\n\n$debut_intertitre_4\$2$fin_intertitre_4\n\n\$3";\r
+               /*  7 */        $remplacer_raccourcis[]="\$1\n\n$debut_intertitre_3\$2$fin_intertitre_3\n\n\$3";\r
+               /*  5 */        $remplacer_raccourcis[]="\$1\n\n$debut_intertitre_2\$2$fin_intertitre_2\n\n\$3";\r
+               /*  3 */        $remplacer_raccourcis[]="\$1\n\n$debut_intertitre\$2$fin_intertitre\n\n\$3";\r
+               /*  1 */        $remplacer_raccourcis[]="\$1\n\n$debut_intertitre\$2$fin_intertitre\n\n\$3";\r
+               /* 11 */        $remplacer_raccourcis[]="<sc>";\r
+               /* 12 */        $remplacer_raccourcis[]="</sc>";\r
+       }\r
+\r
+       // Conversion des intertitres d'enluminures type {n{titre}n}\r
+       // ou n est un nombre en intertitres avec des etoiles type {{{* (avec n etoiles)\r
+       // {1{ sera converti en {{{* ; {2{ sera converti en {{{** ; etc.\r
+       // Ne faire la recherche que s'il y a au moins un titre ancienne mode a convertir\r
+       if (strpos($texte, '{2{')!==false\r
+               OR strpos($texte, '{3{')!==false\r
+               OR strpos($texte, '{4{')!==false\r
+               OR strpos($texte, '{5{')!==false) {\r
+                       $texte=preg_replace_callback ("/\{(\d)\{(.*)\}(\\1)\}/Ums",\r
+                                                       create_function (\r
+                                                               '$matches',\r
+                                                               'return "{{{".str_repeat("*",$matches[1]).trim($matches[2])."}}}";'\r
+                                                       ),\r
+                                                       $texte);\r
+       }\r
+       $texte = preg_replace($chercher_raccourcis, $remplacer_raccourcis, $texte);\r
+\r
+       return $texte;\r
+}\r
+\r
+function typoenluminee_post_propre($texte) {\r
+       if(!$texte) return $texte;\r
+       static $cherche1 = NULL;\r
+       static $remplace1 = NULL;\r
+       if ($cherche1===NULL) {\r
+               # Le remplacement des intertitres de premier niveau a deja ete effectue dans inc/texte.php\r
+               $cherche1 = array();\r
+               $remplace1 = array();\r
+               $cherche1[] = /* 15 */  ",\[/(.*)/\],Ums";\r
+               $cherche1[] = /* 16 */  ",\[!(.*)!\],Ums";\r
+               $cherche1[] = /* 17 */  ",\[\|(.*)\|\],Ums";\r
+               $cherche1[] = /* 19 */  ",\[\((.*)\)\],Ums";\r
+               $cherche1[] = /* 21 */  "/\[\*\*/S";\r
+               $cherche1[] = /* 21b */         "/\[\*/S";\r
+               $cherche1[] = /* 22 */  "/\*\]/S";\r
+       \r
+               $remplace1[] = /* 15 */         "<div class=\"spip\" style=\"text-align:right;\">$1</div>";\r
+               $remplace1[] = /* 16 */         "<div class=\"spip\" style=\"text-align:left;\">$1</div>";\r
+               $remplace1[] = /* 17 */         "<div class=\"spip\" style=\"text-align:center;\">$1</div>";\r
+               $remplace1[] = /* 19 */         "<div class=\"texteencadre-spip spip\">$1</div>";\r
+               $remplace1[] = /* 21 */         "<strong class=\"caractencadre2-spip spip\">";\r
+               $remplace1[] = /* 21b */        "<strong class=\"caractencadre-spip spip\">";\r
+               $remplace1[] = /* 22 */ "</strong>";\r
+       }\r
+       $texte = preg_replace($cherche1, $remplace1, $texte);\r
+       $texte = paragrapher($texte,$GLOBALS['toujours_paragrapher']); // il faut reparagrapher a cause des raccourcis typo que l'on a ajoute (block div)\r
+       return $texte;\r
+}\r
+\r
+\r
+function typoenluminee_pre_typo($texte) {\r
+       if(!$texte) return $texte;\r
+       static $local_barre_typo_pas_de_fausses_puces = null;\r
+       static $chercher_raccourcis;\r
+       static $remplacer_raccourcis;\r
+       global $debut_italique, $fin_italique;\r
+       if (!isset($GLOBALS['barre_typo_pas_de_fork_typo']) OR $GLOBALS['barre_typo_pas_de_fork_typo'] === true)\r
+               return $texte;\r
+\r
+       if ($local_barre_typo_pas_de_fausses_puces===null){\r
+               // remplace les fausses listes a puce par de vraies ?\r
+               // (recherche en debut de lignes - suivi d'un ou plusieurs caracteres blancs, en mode multiligne)\r
+               // Mettre $GLOBALS['barre_typo_pas_de_fausses_puces'] = true; dans mes_options.php pour avoir ce comportement\r
+               if (isset($GLOBALS['barre_typo_pas_de_fausses_puces'])) {\r
+                       $local_barre_typo_pas_de_fausses_puces = $GLOBALS['barre_typo_pas_de_fausses_puces'];\r
+               } else {\r
+                       if (function_exists('lire_config')) {\r
+                               $local_barre_typo_pas_de_fausses_puces = (lire_config('bte/puces','Non') == 'Oui')?true:false;\r
+                       }\r
+               }\r
+               global $class_spip;\r
+               tester_variable('debut_italique', "<i$class_spip>");\r
+               tester_variable('fin_italique', '</i>');\r
+               \r
+               $chercher_raccourcis = array(\r
+                       /* 9 */         "/(?<![{\d])[{](?![{\d])/S", // Expressions complexes car on n'a pas encore traite les titres ici\r
+                       /* 10 */        "/(?<![}\d])[}](?![}\d])/S", // puisque italique utilisent les memes caracteres en nombre inferieur\r
+               );\r
+       \r
+               $remplacer_raccourcis = array(\r
+                       /* 9 */         $debut_italique,\r
+                       /* 10 */        $fin_italique,\r
+               );\r
+       }\r
+       if ($local_barre_typo_pas_de_fausses_puces === true) {\r
+               $texte =  preg_replace('/^-\s+/m','-* ',$texte);\r
+       }\r
+\r
+       $texte = str_replace('<-->','&harr;',$texte);\r
+       $texte = str_replace('-->','&rarr;',$texte);\r
+       $texte = str_replace('<--','&larr;',$texte);\r
+       $texte = str_replace('<==>','&hArr;',$texte);\r
+       $texte = str_replace('==>','&rArr;',$texte);\r
+       $texte = str_replace('<==','&lArr;',$texte);\r
+       $texte = str_ireplace('(c)','&copy;',$texte);\r
+       $texte = str_ireplace('(r)','&reg;',$texte);\r
+       $texte = str_ireplace('(tm)','&trade;',$texte);\r
+       $texte = str_replace('...','&hellip;',$texte);\r
+       $texte = preg_replace($chercher_raccourcis, $remplacer_raccourcis, $texte);\r
+       \r
+       /*\r
+               Cas particulier pour le gras\r
+               Il ne faut pas traiter la mise en gras ici si le texte contient un tableau\r
+       */\r
+       if (!preg_match(',.(\|([[:space:]]*{{[^}]+}}[[:space:]]*|<))+.,sS', $texte)) {\r
+               $chercher_raccourcisg = array(\r
+                       /* 7 */         "/(?<![{])[{][{](?![{])/S", // Expressions complexes car on n'a pas encore traite les titres ici\r
+                       /* 8 */         "/(?<![}])[}][}](?![}])/S" // En gros, verification qu'on n'est pas a l'interieur d'un titre\r
+               );\r
+               $remplacer_raccourcisg = array(\r
+                       /* 7 */         "<strong class=\"spip\">",\r
+                       /* 8 */         "</strong>"\r
+               );\r
+               $texte = preg_replace($chercher_raccourcisg, $remplacer_raccourcisg, $texte);\r
+       }\r
+       return $texte;\r
+}\r
+\r
+function typoenluminee_post_typo($texte) {\r
+       if(!$texte) return $texte;\r
+       if (!isset($GLOBALS['barre_typo_pas_de_fork_typo']) OR $GLOBALS['barre_typo_pas_de_fork_typo'] === true)\r
+               return $texte;\r
+       $texte = str_replace('[^','<sup>',$texte);\r
+       $texte = str_replace('^]','</sup>',$texte);\r
+       $texte = str_replace('[**','<strong class="caractencadre2-spip spip">',$texte);\r
+       $texte = str_replace('[*','<strong class="caractencadre-spip spip">',$texte);\r
+       $texte = str_replace('*]','</strong>',$texte);\r
+       \r
+       // Correction des & en &amp;\r
+       $texte = preg_replace('/&([A-Za-z#0-9]*);/','@@@amp:\1:amp@@@',$texte); // echapement des entites html deja presentes\r
+       $texte = str_replace('&','&amp;',$texte);\r
+       $texte = preg_replace('/@@@amp:([A-Za-z#0-9]*):amp@@@/','&\1;',$texte);\r
+       // Raccourci typographique <sc></sc>\r
+       $texte = str_replace('<sc>', '<span class="caps">', $texte);\r
+       $texte = str_replace('</sc>', '</span>', $texte);\r
+       return $texte;\r
+}\r
+\r
+function typoenluminee_nettoyer_raccourcis_typo($texte){\r
+       $texte = preg_replace(',\{[1-5]\{,','',$texte);\r
+       $texte = preg_replace(',\}[1-5]\},','',$texte);\r
+       $texte = preg_replace(',\{\{\{\*+,','{{{',$texte);\r
+       $texte = str_replace('&hellip;','...',$texte);\r
+       return $texte;\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/enluminures_typographiques_v3/typoenluminee_pipelines.php b/www/plugins/enluminures_typographiques_v3/typoenluminee_pipelines.php
new file mode 100644 (file)
index 0000000..cac292e
--- /dev/null
@@ -0,0 +1,30 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+// insert le css pour les styles supplementaires de la BTE dans le <head> du document (#INSERT_HEAD)\r
+function TypoEnluminee_insert_head_css($flux) {\r
+       static $done = false;\r
+       if (!$done) {\r
+               $done = true;\r
+               if (isset($GLOBALS['BarreTypoEnrichie_Preserve_Header']) OR !function_exists('lire_config'))\r
+                       global $BarreTypoEnrichie_Preserve_Header;\r
+               else\r
+                       $BarreTypoEnrichie_Preserve_Header = lire_config('bte/insertcss','Oui');\r
+               if ($BarreTypoEnrichie_Preserve_Header == 'Oui')\r
+                       $flux .= "\n".'<link rel="stylesheet" href="'.find_in_path('css/enluminurestypo.css').'" type="text/css" media="all" />';\r
+       }\r
+       return $flux;\r
+}\r
+\r
+// insert le css pour les styles supplementaires de la BTE dans le <head> du document (#INSERT_HEAD)\r
+function TypoEnluminee_insert_head($flux) {\r
+       $flux = TypoEnluminee_insert_head_css($flux);\r
+       return $flux;\r
+}\r
+function TypoEnluminee_header_prive($texte) {\r
+       $texte.= '<link rel="stylesheet" type="text/css" href="' . _DIR_PLUGIN_TYPOENLUMINEE . 'css/enluminurestypo.css" />' . "\n";\r
+       $texte.= '<link rel="stylesheet" type="text/css" href="' . _DIR_PLUGIN_TYPOENLUMINEE . 'css/enluminurestypo_prive.css" />' . "\n";\r
+       return $texte;\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/classes/facteur.php b/www/plugins/facteur/classes/facteur.php
new file mode 100755 (executable)
index 0000000..ca3edab
--- /dev/null
@@ -0,0 +1,424 @@
+<?php\r
+/*\r
+ * Plugin Facteur 2\r
+ * (c) 2009-2011 Collectif SPIP\r
+ * Distribue sous licence GPL\r
+ *\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+include_spip('inc/charsets');\r
+include_spip('inc/texte');\r
+include_spip('inc/filtres');\r
+\r
+if (!class_exists('PHPMailer')) {\r
+       include_spip('phpmailer-php5/class.phpmailer');\r
+       include_spip('phpmailer-php5/class.smtp');\r
+}\r
+\r
+include_spip('facteur_fonctions');\r
+\r
+class Facteur extends PHPMailer {\r
+\r
+       /**\r
+        * @param $email\r
+        * @param $objet\r
+        * @param $message_html\r
+        * @param $message_texte\r
+        * @param array $options\r
+        *\r
+        */\r
+       function Facteur($email, $objet, $message_html, $message_texte, $options = array()) {\r
+               $defaut = array(\r
+                       'adresse_envoi' => $GLOBALS['meta']['facteur_adresse_envoi'],\r
+                       'adresse_envoi_email' => $GLOBALS['meta']['facteur_adresse_envoi_email'],\r
+                       'adresse_envoi_nom' => $GLOBALS['meta']['facteur_adresse_envoi_nom'],\r
+                       'cc' => $GLOBALS['meta']['facteur_cc'],\r
+                       'bcc' => $GLOBALS['meta']['facteur_bcc'],\r
+                       'smtp' => $GLOBALS['meta']['facteur_smtp'],\r
+                       'smtp_host' => $GLOBALS['meta']['facteur_smtp_host'],\r
+                       'smtp_port' => $GLOBALS['meta']['facteur_smtp_port'],\r
+                       'smtp_auth' => $GLOBALS['meta']['facteur_smtp_auth'],\r
+                       'smtp_username' => $GLOBALS['meta']['facteur_smtp_username'],\r
+                       'smtp_password' => $GLOBALS['meta']['facteur_smtp_password'],\r
+                       'smtp_secure' => $GLOBALS['meta']['facteur_smtp_secure'],\r
+                       'smtp_sender' => $GLOBALS['meta']['facteur_smtp_sender'],\r
+                       'filtre_images' => $GLOBALS['meta']['facteur_filtre_images'],\r
+                       'filtre_iso_8859' => $GLOBALS['meta']['facteur_filtre_iso_8859'],\r
+               );\r
+               $options = array_merge($defaut, $options);\r
+\r
+               if (defined('_FACTEUR_DEBUG_SMTP')) {\r
+                       $this->SMTPDebug = _FACTEUR_DEBUG_SMTP ;\r
+               }\r
+               if ($options['adresse_envoi'] == 'oui'\r
+                 AND $options['adresse_envoi_email'])\r
+                       $this->From = $options['adresse_envoi_email'];\r
+               else\r
+                       $this->From = (isset($GLOBALS['meta']["email_envoi"]) AND $GLOBALS['meta']["email_envoi"])?\r
+                               $GLOBALS['meta']["email_envoi"]\r
+                               :$GLOBALS['meta']['email_webmaster'];\r
+\r
+               // Si plusieurs emails dans le from, pas de Name !\r
+               if (strpos($this->From,",")===false){\r
+                       if ($options['adresse_envoi'] == 'oui'\r
+                         AND $options['adresse_envoi_nom'])\r
+                               $this->FromName = $options['adresse_envoi_nom'];\r
+                       else\r
+                               $this->FromName = strip_tags(extraire_multi($GLOBALS['meta']['nom_site']));\r
+               }\r
+\r
+               $this->CharSet = "utf-8";\r
+               $this->Mailer = 'mail';\r
+               $this->Subject = unicode_to_utf_8(charset2unicode($objet,$GLOBALS['meta']['charset']));\r
+\r
+               //Pour un envoi multiple de mail, $email doit être un tableau avec les adresses.\r
+               if (is_array($email)) {\r
+                       foreach ($email as $cle => $adresseMail) {\r
+                               if (!$this->AddAddress($adresseMail))\r
+                                       spip_log("Erreur AddAddress $adresseMail : ".print_r($this->ErrorInfo,true),'facteur');\r
+                       }\r
+               }\r
+               else\r
+                       if (!$this->AddAddress($email))\r
+                               spip_log("Erreur AddAddress $email : ".print_r($this->ErrorInfo,true),'facteur');\r
+\r
+               if (!empty($options['smtp_sender'])) {\r
+                       $this->Sender = $options['smtp_sender'];\r
+                       $this->AddCustomHeader("Errors-To: ".$this->Sender);\r
+               }\r
+\r
+               if (!empty($options['cc'])) {\r
+                       $this->AddCC( $options['cc'] );\r
+               }\r
+               if (!empty($options['bcc'])) {\r
+                       $this->AddBCC( $options['bcc'] );\r
+               }\r
+               \r
+               if (isset($options['smtp']) AND $options['smtp'] == 'oui') {\r
+                       $this->Mailer   = 'smtp';\r
+                       $this->Host     = $options['smtp_host'];\r
+                       $this->Port     = $options['smtp_port'];\r
+                       if ($options['smtp_auth'] == 'oui') {\r
+                               $this->SMTPAuth = true;\r
+                               $this->Username = $options['smtp_username'];\r
+                               $this->Password = $options['smtp_password'];\r
+                       }\r
+                       else {\r
+                               $this->SMTPAuth = false;\r
+                       }\r
+                       if (intval(phpversion()) == 5) {\r
+                       if ($options['smtp_secure'] == 'ssl')\r
+                               $this->SMTPSecure = 'ssl';\r
+                       if ($options['smtp_secure'] == 'tls')\r
+                               $this->SMTPSecure = 'tls';\r
+                       }\r
+               }\r
+\r
+               if (!empty($message_html)) {\r
+                       $message_html = unicode_to_utf_8(charset2unicode($message_html,$GLOBALS['meta']['charset']));\r
+                       $this->Body = $message_html;\r
+                       $this->IsHTML(true);\r
+                       if ($options['filtre_images'])\r
+                               $this->JoindreImagesHTML();\r
+                       $this->UrlsAbsolues();\r
+               }\r
+               if (!empty($message_texte)) {\r
+                       $message_texte = unicode_to_utf_8(charset2unicode($message_texte,$GLOBALS['meta']['charset']));\r
+                       if (!$this->Body) {\r
+                               $this->IsHTML(false);\r
+                               $this->Body = $message_texte;\r
+                       }\r
+                       else {\r
+                               $this->AltBody = $message_texte;\r
+                       }\r
+               }\r
+\r
+               if ($options['filtre_iso_8859'])\r
+                       $this->ConvertirUtf8VersIso8859();\r
+\r
+       }\r
+       \r
+       /*\r
+        * Transforme du HTML en texte brut, mais proprement, c'est-à-dire en essayant\r
+        * de garder les titrages, les listes, etc\r
+        *\r
+        * @param string $html Le HTML à transformer\r
+        * @return string Retourne un texte brut formaté correctement\r
+        */\r
+       function html2text($html){\r
+               // On remplace tous les sauts de lignes par un espace\r
+               $html = str_replace("\n", ' ', $html);\r
+               \r
+               // Supprimer tous les liens internes\r
+               $texte = preg_replace("/\<a href=['\"]#(.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2", $html);\r
+       \r
+               // Supprime feuille style\r
+               $texte = preg_replace(";<style[^>]*>[^<]*</style>;i", "", $texte);\r
+       \r
+               // Remplace tous les liens      \r
+               $texte = preg_replace("/\<a[^>]*href=['\"](.*?)['\"][^>]*>(.*?)<\/a>/ims", "\\2 (\\1)", $texte);\r
+       \r
+               // Les titres\r
+               $texte = preg_replace(";<h1[^>]*>;i", "\n= ", $texte);\r
+               $texte = str_replace("</h1>", " =\n\n", $texte);\r
+               $texte = preg_replace(";<h2[^>]*>;i", "\n== ", $texte);\r
+               $texte = str_replace("</h2>", " ==\n\n", $texte);\r
+               $texte = preg_replace(";<h3[^>]*>;i", "\n=== ", $texte);\r
+               $texte = str_replace("</h3>", " ===\n\n", $texte);\r
+               \r
+               // Une fin de liste\r
+               $texte = preg_replace(";</(u|o)l>;i", "\n\n", $texte);\r
+               \r
+               // Une saut de ligne *après* le paragraphe\r
+               $texte = preg_replace(";<p[^>]*>;i", "\n", $texte);\r
+               $texte = preg_replace(";</p>;i", "\n\n", $texte);\r
+               // Les sauts de ligne interne\r
+               $texte = preg_replace(";<br[^>]*>;i", "\n", $texte);\r
+       \r
+               //$texte = str_replace('<br /><img class=\'spip_puce\' src=\'puce.gif\' alt=\'-\' border=\'0\'>', "\n".'-', $texte);\r
+               $texte = preg_replace (';<li[^>]*>;i', "\n".'- ', $texte);\r
+       \r
+       \r
+               // accentuation du gras\r
+               // <b>texte</b> -> **texte**\r
+               $texte = preg_replace (';<b[^>]*>;i','**' ,$texte);\r
+               $texte = str_replace ('</b>','**' ,$texte);\r
+       \r
+               // accentuation du gras\r
+               // <strong>texte</strong> -> **texte**\r
+               $texte = preg_replace (';<strong[^>]*>;i','**' ,$texte);\r
+               $texte = str_replace ('</strong>','**' ,$texte);\r
+       \r
+       \r
+               // accentuation de l'italique\r
+               // <em>texte</em> -> *texte*\r
+               $texte = preg_replace (';<em[^>]*>;i','/' ,$texte);\r
+               $texte = str_replace ('</em>','*' ,$texte);\r
+               \r
+               // accentuation de l'italique\r
+               // <i>texte</i> -> *texte*\r
+               $texte = preg_replace (';<i[^>]*>;i','/' ,$texte);\r
+               $texte = str_replace ('</i>','*' ,$texte);\r
+       \r
+               $texte = str_replace('&oelig;', 'oe', $texte);\r
+               $texte = str_replace("&nbsp;", " ", $texte);\r
+               $texte = filtrer_entites($texte);\r
+       \r
+               // On supprime toutes les balises restantes\r
+               $texte = supprimer_tags($texte);\r
+       \r
+               $texte = str_replace("\x0B", "", $texte); \r
+               $texte = str_replace("\t", "", $texte) ;\r
+               $texte = preg_replace(";[ ]{3,};", "", $texte);\r
+       \r
+               // espace en debut de ligne\r
+               $texte = preg_replace("/(\r\n|\n|\r)[ ]+/", "\n", $texte);\r
+       \r
+               //marche po\r
+               // Bring down number of empty lines to 4 max\r
+               $texte = preg_replace("/(\r\n|\n|\r){3,}/m", "\n\n", $texte);\r
+       \r
+               //saut de lignes en debut de texte\r
+               $texte = preg_replace("/^(\r\n|\n|\r)*/", "\n\n", $texte);\r
+               //saut de lignes en debut ou fin de texte\r
+               $texte = preg_replace("/(\r\n|\n|\r)*$/", "\n\n", $texte);\r
+       \r
+               // Faire des lignes de 75 caracteres maximum\r
+               //$texte = wordwrap($texte);\r
+       \r
+               return $texte;\r
+       }\r
+       \r
+       /**\r
+        * Transformer les urls des liens et des images en url absolues\r
+        * sans toucher aux images embarquees de la forme "cid:..."\r
+        */\r
+       function UrlsAbsolues($base=null){\r
+               include_spip('inc/filtres_mini');\r
+               if (preg_match_all(',(<(a|link)[[:space:]]+[^<>]*href=["\']?)([^"\' ><[:space:]]+)([^<>]*>),imsS',\r
+                 $this->Body, $liens, PREG_SET_ORDER)) {\r
+                       foreach ($liens as $lien) {\r
+                               if (strncmp($lien[3],"cid:",4)!==0){\r
+                                       $abs = url_absolue($lien[3], $base);\r
+                                       if ($abs <> $lien[3] and !preg_match('/^#/',$lien[3]))\r
+                                               $this->Body = str_replace($lien[0], $lien[1].$abs.$lien[4], $this->Body);\r
+                               }\r
+                       }\r
+               }\r
+               if (preg_match_all(',(<(img|script)[[:space:]]+[^<>]*src=["\']?)([^"\' ><[:space:]]+)([^<>]*>),imsS',\r
+                 $this->Body, $liens, PREG_SET_ORDER)) {\r
+                       foreach ($liens as $lien) {\r
+                               if (strncmp($lien[3],"cid:",4)!==0){\r
+                                       $abs = url_absolue($lien[3], $base);\r
+                                       if ($abs <> $lien[3])\r
+                                               $this->Body = str_replace($lien[0], $lien[1].$abs.$lien[4], $this->Body);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       function JoindreImagesHTML() {\r
+               $image_types = array(\r
+                                                       'gif'   => 'image/gif',\r
+                                                       'jpg'   => 'image/jpeg',\r
+                                                       'jpeg'  => 'image/jpeg',\r
+                                                       'jpe'   => 'image/jpeg',\r
+                                                       'bmp'   => 'image/bmp',\r
+                                                       'png'   => 'image/png',\r
+                                                       'tif'   => 'image/tiff',\r
+                                                       'tiff'  => 'image/tiff',\r
+                                                       'swf'   => 'application/x-shockwave-flash'\r
+                                               );\r
+               $src_found = array();\r
+               $images_embeded = array();\r
+               if (preg_match_all(\r
+                       '/["\'](([^"\']+)\.('.implode('|', array_keys($image_types)).'))([?][^"\']+)?([#][^"\']+)?["\']/Uims',\r
+                       $this->Body, $images, PREG_SET_ORDER)) {\r
+\r
+                       $adresse_site = $GLOBALS['meta']['adresse_site'].'/';\r
+                       foreach($images as $im){\r
+                               $src_orig = $im[1].$im[4].$im[5];\r
+                               if (!isset($src_found[$src_orig])){ // deja remplace ? rien a faire (ie la meme image presente plusieurs fois)\r
+                                       // examiner le src et voir si embedable\r
+                                       $src = $im[1];\r
+                                       if ($src AND strncmp($src,$adresse_site,strlen($adresse_site))==0)\r
+                                               $src = _DIR_RACINE . substr($src,strlen($adresse_site));\r
+                                       if ($src\r
+                                         AND !preg_match(",^[a-z0-9]+://,i",$src)\r
+                                         AND (\r
+                                             file_exists($f=$src) // l'image a ete generee depuis le meme cote que l'envoi\r
+                                             OR (_DIR_RACINE AND file_exists($f=_DIR_RACINE.$src)) // l'image a ete generee dans le public et on est dans le prive\r
+                                             OR (!_DIR_RACINE AND file_exists($f=_DIR_RESTREINT.$src)) // l'image a ete generee dans le prive et on est dans le public\r
+                                            )\r
+                                         ){\r
+                                               if (!isset($images_embeded[$f])){\r
+                                                       $extension = strtolower($im[3]);\r
+                                                       $header_extension = $image_types[$extension];\r
+                                                       $cid = md5($f); // un id unique pour un meme fichier\r
+                                                       $images_embeded[$f] = $cid; // marquer l'image comme traitee, inutile d'y revenir\r
+                                                       $this->AddEmbeddedImage($f, $cid, basename($f),'base64',$header_extension);\r
+                                               }\r
+\r
+                                               $this->Body = str_replace($src_orig, "cid:".$images_embeded[$f], $this->Body);\r
+                                               $src_found[$src_orig] = $f;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+        * Compat ascendante, obsolete\r
+        */\r
+       function ConvertirStylesEnligne() {\r
+               $this->Body = facteur_convertir_styles_inline($this->Body);\r
+       }\r
+\r
+\r
+       function safe_utf8_decode($text,$mode='texte_brut') {\r
+               if (!is_utf8($text))\r
+                       return ($text);\r
+\r
+               if (function_exists('iconv') && $mode == 'texte_brut') {\r
+                       $text = str_replace('’',"'",$text);\r
+                       $text = iconv("UTF-8", "ISO-8859-1//TRANSLIT", $text);\r
+                       return str_replace('&#8217;',"'",$text);\r
+               }\r
+               else {\r
+                       if ($mode == 'texte_brut') {\r
+                               $text = str_replace('’',"'",$text);\r
+                       }\r
+                       $text = unicode2charset(utf_8_to_unicode($text),'iso-8859-1');\r
+                       return str_replace('&#8217;',"'",$text);\r
+               }\r
+       }\r
+\r
+       function ConvertirUtf8VersIso8859() {\r
+               $this->CharSet  = 'iso-8859-1';\r
+               $this->Body             = str_ireplace('charset=utf-8', 'charset=iso-8859-1', $this->Body);\r
+               $this->Body             = $this->safe_utf8_decode($this->Body,'html');\r
+               $this->AltBody  = $this->safe_utf8_decode($this->AltBody);\r
+               $this->Subject  = $this->safe_utf8_decode($this->Subject);\r
+               $this->FromName = $this->safe_utf8_decode($this->FromName);\r
+       }\r
+\r
+       function ConvertirAccents() {\r
+               // tableau à compléter au fur et à mesure\r
+               $cor = array(\r
+                                               'à' => '&agrave;',\r
+                                               'â' => '&acirc;',\r
+                                               'ä' => '&auml;',\r
+                                               'ç' => '&ccedil;',\r
+                                               'é' => '&eacute;',\r
+                                               'è' => '&egrave;',\r
+                                               'ê' => '&ecirc;',\r
+                                               'ë' => '&euml;',\r
+                                               'î' => '&icirc;',\r
+                                               'ï' => '&iuml;',\r
+                                               'ò' => '&ograve;',\r
+                                               'ô' => '&ocirc;',\r
+                                               'ö' => '&ouml;',\r
+                                               'ù' => '&ugrave;',\r
+                                               'û' => '&ucirc;',\r
+                                               'œ' => '&oelig;',\r
+                                               '€' => '&euro;'\r
+                                       );\r
+\r
+               $this->Body = strtr($this->Body, $cor);\r
+       }\r
+       public function Send() {\r
+               ob_start();\r
+               $retour = parent::Send();\r
+               $error = ob_get_contents();\r
+               ob_end_clean();\r
+               if( !empty($error) ) {\r
+                       spip_log("Erreur Facteur->Send : $error",'facteur.err');\r
+               }\r
+               return $retour;\r
+       }\r
+       public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {\r
+               ob_start();\r
+               $retour = parent::AddAttachment($path, $name, $encoding, $type);\r
+               $error = ob_get_contents();\r
+               ob_end_clean();\r
+               if( !empty($error) ) {\r
+                       spip_log("Erreur Facteur->AddAttachment : $error",'facteur.err');\r
+               }\r
+               return $retour;\r
+       }\r
+       public function AddReplyTo($address, $name = '') {\r
+               ob_start();\r
+               $retour = parent::AddReplyTo($address, $name);\r
+               $error = ob_get_contents();\r
+               ob_end_clean();\r
+               if( !empty($error) ) {\r
+                       spip_log("Erreur Facteur->AddReplyTo : $error",'facteur.err');\r
+               }\r
+               return $retour;\r
+       }\r
+       public function AddBCC($address, $name = '') {\r
+               ob_start();\r
+               $retour = parent::AddBCC($address, $name);\r
+               $error = ob_get_contents();\r
+               ob_end_clean();\r
+               if( !empty($error) ) {\r
+                       spip_log("Erreur Facteur->AddBCC : $error",'facteur.err');\r
+               }\r
+               return $retour;\r
+       }\r
+       public function AddCC($address, $name = '') {\r
+               ob_start();\r
+               $retour = parent::AddCC($address, $name);\r
+               $error = ob_get_contents();\r
+               ob_end_clean();\r
+               if( !empty($error) ) {\r
+                       spip_log("Erreur Facteur->AddCC : $error",'facteur.err');\r
+               }\r
+               return $retour;\r
+       }\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/facteur/emails/css.html b/www/plugins/facteur/emails/css.html
new file mode 100755 (executable)
index 0000000..ace3aa9
--- /dev/null
@@ -0,0 +1,63 @@
+<style type="text/css" media="screen">
+.faux_body {
+       background-color: #fff;
+       font-size: 12px;
+       font-family: verdana, sans-serif;
+}
+
+.titre {
+       text-align: center;
+       color: #000;
+       font-size: 24px;
+}
+
+h2 {
+       font-size: 18px;
+}
+
+h3 {
+       font-size: 16px;
+       clear: both;
+}
+
+a {
+       text-decoration: none;
+}
+
+a:hover {
+       text-decoration: underline;
+}
+
+a:visited {
+}
+
+.spip_documents_left {
+       float: left;
+       margin-right: 10px;
+}
+
+.spip_documents_center {
+       display: block;
+       text-align: center;
+       margin: 10px 0;
+}
+
+.spip_documents_right {
+       float: right;
+       margin-left: 10px;
+}
+
+.petit {
+       padding-top: 20px;
+       text-align: center;
+       font-size: 10px;
+}
+
+ul {
+       clear: both;
+}
+
+.invisible {
+       color: #eee;
+}
+</style>
\ No newline at end of file
diff --git a/www/plugins/facteur/emails/inc-bas.html b/www/plugins/facteur/emails/inc-bas.html
new file mode 100755 (executable)
index 0000000..b8a8c19
--- /dev/null
@@ -0,0 +1,22 @@
+</td>
+<td width="20" style="background-color: #fff;">&nbsp;</td>
+</tr>
+[<tr>
+<td colspan="3" width="580" style="background-color: #fff;"><a href="#URL_SITE_SPIP" title="[(#DESCRIPTIF_SITE_SPIP|textebrut)]"><img src="(#LOGO_NOTIFICATION_SURVOL||extraire_attribut{src})" alt="[(#NOM_SITE_SPIP|textebrut)]" border="0" width="[(#LOGO_NOTIFICATION_SURVOL||extraire_attribut{width})]" height="[(#LOGO_NOTIFICATION_SURVOL||extraire_attribut{height})]" /></a></td>
+</tr>
+]<tr>
+<td colspan="3" width="580" height="20">&nbsp;</td>
+</tr>
+</table>
+
+
+</center>
+
+
+</div><!-- fin faux_body -->
+
+
+</body>
+
+
+</html>
\ No newline at end of file
diff --git a/www/plugins/facteur/emails/inc-button.html b/www/plugins/facteur/emails/inc-button.html
new file mode 100644 (file)
index 0000000..08fc0d3
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM)
+       Bulletproof button code for email html
+       from http://emailbtn.net/
+
+       Arguments :
+       url
+       label
+       color (#ffffff par defaut)
+       bgcolor (#556270 par defaut)
+       bordercolor (#1e3650 par defaut)
+       borderradius (4px par defaut)
+       width (200px par defaut)
+       height (40px par defaut)
+       bgurl (rien par defaut)
+]
+<span style="display: inline-block;"><!--[if mso]>
+  <v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="#ENV*{url}" style="height:#ENV{height,40px};v-text-anchor:middle;width:#ENV{width,200px};"[(#ENV{borderradius,4px}|intval|oui)arcsize="[(#ENV{borderradius,4px}|intval|mult{100}|div{#ENV{height,40px}|intval}|intval)%]"] strokecolor="#ENV{bordercolor,#1e3650}" [(#ENV{bgurl,''}|?{'fill="t"',[fillcolor="(#ENV{bgcolor,#556270})"]})]>
+    [<v:fill type="tile" src="(#ENV{bgurl,''})" color="#ENV{bgcolor,#556270}" />
+    ]<w:anchorlock/>
+    <center style="color:#ENV{color,#ffffff};font-family:sans-serif;font-size:13px;font-weight:bold;">#ENV*{label}</center>
+  </v:roundrect>
+<![endif]--><![if !mso]><a href="#ENV*{url}"
+style="background-color:#ENV{bgcolor,#556270};[background-image:url\((#ENV{bgurl,''})\);]border:1px solid #ENV{bordercolor,#1e3650};[border-radius:(#ENV{borderradius,4px});]color:#ENV{color,#ffffff};display:inline-block;font-family:sans-serif;font-size:13px;font-weight:bold;line-height:#ENV{height,40px};text-align:center;text-decoration:none;width:#ENV{width,200px};-webkit-text-size-adjust:none;">#ENV*{label}</a><![endif]></span>
\ No newline at end of file
diff --git a/www/plugins/facteur/emails/inc-haut.html b/www/plugins/facteur/emails/inc-haut.html
new file mode 100755 (executable)
index 0000000..21f4ee1
--- /dev/null
@@ -0,0 +1,31 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" dir="#LANG_DIR" xml:lang="#LANG" lang="#LANG">
+
+
+<head>
+<meta http-equiv="content-type" content="text/html; charset=#CHARSET" />
+<meta name="language" content="#LANG" />
+<INCLURE {fond=emails/css}>
+</head>
+
+
+<body>
+
+
+<div class="faux_body">
+       
+
+<center>
+
+
+<table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td colspan="3" width="580" height="10">&nbsp;</td>
+</tr>
+[<tr>
+<td colspan="3" width="580" style="background-color: #fff; text-align: center;"><a class="titre" href="#URL_SITE_SPIP" title="[(#DESCRIPTIF_SITE_SPIP|textebrut)]"><img class="titre" src="(#LOGO_NOTIFICATION_NORMAL||extraire_attribut{src})" alt="[(#NOM_SITE_SPIP|textebrut)]" border="0" width="[(#LOGO_NOTIFICATION_NORMAL||extraire_attribut{width})]" height="[(#LOGO_NOTIFICATION_NORMAL||extraire_attribut{height})]" /></a></td>
+</tr>
+]<tr>
+<td width="20" style="background-color: #fff;">&nbsp;</td>
+<td width="540" style="background-color: #fff;">
diff --git a/www/plugins/facteur/emails/test_email_html.html b/www/plugins/facteur/emails/test_email_html.html
new file mode 100755 (executable)
index 0000000..481b417
--- /dev/null
@@ -0,0 +1,28 @@
+#HTTP_HEADER{Content-Type:text/html}
+#INCLURE{fond=emails/inc-haut}
+
+<h2><:facteur:corps_email_de_test:></h2>
+
+<p><:facteur:version_html:></p>
+
+<BOUCLE_art(ARTICLES){texte==<img}{0,1}>
+               [(#TEXTE|image_reduire{550,0})]
+               <hr />
+               [(#NOTES|image_reduire{550,0})]
+</BOUCLE_art>
+       <BOUCLE_art2(ARTICLES){0,1}>
+               [(#TEXTE|image_reduire{550,0})]
+               <hr />
+               [(#NOTES|image_reduire{550,0})]
+       </BOUCLE_art2>
+<//B_art>
+
+<BOUCLE_image(DOCUMENTS){extension IN jpg,png,gif}{0,1}>
+       [(#MODELE{img}|image_reduire{550,0})]
+</BOUCLE_image>
+
+<BOUCLE_pdf(DOCUMENTS){extension=pdf}{0,1}>
+       [(#MODELE{doc}|image_reduire{550,0})]
+</BOUCLE_pdf>
+
+#INCLURE{fond=emails/inc-bas}
\ No newline at end of file
diff --git a/www/plugins/facteur/emails/test_email_texte.html b/www/plugins/facteur/emails/test_email_texte.html
new file mode 100755 (executable)
index 0000000..e8953af
--- /dev/null
@@ -0,0 +1,12 @@
+<:facteur:corps_email_de_test:>
+--------------------------------
+
+<:facteur:version_texte:>
+
+<BOUCLE_art(ARTICLES){texte==<img}{0,1}>
+               [(#TEXTE|textebrut)]
+</BOUCLE_art>
+       <BOUCLE_art2(ARTICLES){0,1}>
+                       [(#TEXTE|textebrut)]
+       </BOUCLE_art2>
+<//B_art>
diff --git a/www/plugins/facteur/emails/texte.html b/www/plugins/facteur/emails/texte.html
new file mode 100644 (file)
index 0000000..cb7fccf
--- /dev/null
@@ -0,0 +1,111 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+       <title>[(#ENV*{sujet})]</title>
+       <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+       <style type="text/css">
+               [(#SET{siteColor,[#(#LOGO_SITE_SPIP|couleur_extraire|couleur_eclaircir_si_foncee{168}|sinon{BBB})]})]
+               #outlook a {padding: 0;}
+               body {width: 100% !important;}
+               body {margin: 0;padding: 0;}
+               img {border: none;font-size: inherit;font-weight: bold;height: auto;line-height: 100%;outline: none;text-decoration: none;text-transform: capitalize;}
+               #backgroundTable {height: 100% !important;margin: 0;padding: 0;width: 100% !important;}
+               body, .backgroundTable {background-color: #DDDDDD;}
+               #templateContainer {border: 1px solid #CCCCCC;max-width: 600px !important;}
+               h1,.h1,h2,.h2,h3,.h3,h4,.h4 {color: #202020;display: block;font-family: Verdana, Geneva, sans-serif;margin-bottom: 0.5em;text-align: left;}
+               #templateHeader {background-color: #FFFFFF;border-bottom: 0;}
+               #templateContainer, .bodyContent {background-color: #FFFFFF;margin-top: 40px;}
+               .bodyContent {padding:30px;border-bottom:10px solid #GET{siteColor};}
+               .bodyContent div {color: #222222;font-family: Verdana, Geneva, sans-serif;line-height: 150%;text-align: left;}
+               .bodyContent div a:link, .bodyContent div a:visited {color: #336699;font-weight: normal;text-decoration: underline;}
+               .bodyContent img {display: inline;margin-bottom: 10px;}
+               .bodyContent img.puce {display: inline;margin-bottom: 0;}
+               hr { height: 1px; margin: 1.5em 0; border: 0; background: #222222; color: #222222; }
+               .spip_code, .spip_cadre {color: #606060;font-family: Courier,"Courier New",monospace;font-size: 1em;word-wrap:break-word;max-width: 100%;overflow: auto;}
+               .coloration_code ol {list-style: none;}
+               .spip_logos {float: right;margin-left: 10px;}
+               .text {word-wrap:break-word;}
+               .header,.footer {padding: 20px 40px;margin-left: -40px;margin-right: -40px;}
+               .text > .header:first-child {margin-top: -40px;}
+               .header {background: #e9e9e9;}
+               .footer {border-top:2px solid #e9e9e9;margin-top: 40px;}
+               .header hr,.footer hr {display: none}
+               @media only screen and (max-width: 600px) {
+                       html,body {width: 100% !important;}
+                       body, .backgroundTable {background-color: #ffffff !important;}
+                       .bodyContent {padding:0 0 10px !important;border-top:0;border-bottom:0;}
+                       #templateHead {display: none}
+                       #templateContainer {width: 100% !important;border: 0 !important;margin-top: 0}
+                       #templateBody {width: 100% !important;}
+                       .padding {padding-left:0 !important;padding-right:0 !important;}
+                       .text {color: #101010 !important;}
+                       .header,.footer {padding: 10px;margin-left: -10px;margin-right: -10px;}
+                       .text > .header:first-child {margin-top: -10px;}
+               }
+               @media only screen and (max-device-width: 480px) {
+                       html,body {width: 320px !important;}
+                       body, .backgroundTable {background-color: #ffffff !important;}
+                       .bodyContent {padding: 0 0 10px !important;border-top:0;border-bottom:0;}
+                       #templateContainer {width: 320px !important;border: 0 !important;margin-top: 0;}
+                       #templateBody {width: 320px !important;}
+                       .padding {padding-left:0 !important;padding-right:0 !important;}
+                       .text {color: #101010 !important;}
+               }
+       </style>
+</head>
+<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0"
+                       style="margin: 0;padding: 0;width: 100% !important;">
+<center>
+       [<div style="display:none;display:none !important;">(#ENV{intro,''})</div>]
+       <table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%" id="backgroundTable"
+                                style="margin: 0;padding: 0;height: 100% !important;width: 100% !important;">
+               <tr>
+                       <td align="center" valign="top">
+                               <!-- // End Template Preheader \\ -->
+                               <table border="0" cellpadding="0" cellspacing="0" width="600" id="templateContainer"
+                                                        style="border: 1px solid #CCCCCC;background-color: #FFFFFF;max-width: 600px !important;">
+                                       <tr id="templateHead">
+                                               <td class="headContent" style="padding:10px 40px;background: #GET{siteColor};"><strong style="color:#fff;text-transform:uppercase">#NOM_SITE_SPIP</strong></td>
+                                       </tr>
+                                       <tr>
+                                               <td align="center" valign="top">
+                                                       <!-- // Begin Template Body \\ -->
+                                                       <table border="0" cellpadding="0" cellspacing="0" width="600" id="templateBody">
+                                                               <tr>
+                                                                       <td valign="top" class="bodyContent" style="background-color: #FFFFFF;padding:30px;">
+
+                                                                               <!-- // Begin Module: Standard Content \\ -->
+                                                                               <table border="0" cellpadding="10" cellspacing="0" width="100%">
+                                                                                       <tr>
+                                                                                               <td valign="top">
+                                                                                                       <div class='text' style="color:#222222;font-family: Verdana, Geneva, sans-serif;font-size:100%;line-height:150%;text-align:left;word-wrap:break-word;">
+                                                                                                               [(#ENV*{html,#ENV*{texte}|replace{'<','&lt;'}|facteur_nl2br_si_pas_autobr|propre|replace{'<br />\s*<br />(\s*<br />)+?','<br /> <br />'}|concat{'<br /> <br />'}})]
+                                                                                                       </div>
+                                                                                               </td>
+                                                                                       </tr>
+                                                                                       <tr>
+                                                                                               <td align="left" valign="top"
+                                                                                                               style="color:#A39F9A !important;font-family: Verdana, Geneva, sans-serif; !important;font-size:90% !important;font-weight:normal !important;font-style:normal !important;text-decoration:none !important;vertical-align:top !important;text-align:left !important;">
+                                                                                                       <br/>
+                                                                                                       <br/>
+                                                                                                       &mdash; Envoyé par <a href="#URL_SITE_SPIP/">#NOM_SITE_SPIP</a>
+                                                                                                       <br/>
+                                                                                               </td>
+                                                                                       </tr>
+                                                                               </table>
+                                                                               <!-- // End Module: Standard Content \\ -->
+                                                                       </td>
+                                                               </tr>
+                                                       </table>
+                                                       <!-- // End Template Body \\ -->
+                                               </td>
+                                       </tr>
+                               </table>
+                               <br>
+                       </td>
+               </tr>
+       </table>
+</center>
+</body>
+</html>
diff --git a/www/plugins/facteur/erreurs et exceptions.txt b/www/plugins/facteur/erreurs et exceptions.txt
new file mode 100644 (file)
index 0000000..192c8a2
--- /dev/null
@@ -0,0 +1,42 @@
+Avril 2012\r
+Yffic\r
+\r
+Petit point sur la gestion des erreurs et les exceptions de phpMailer 5. "Parce que c'est pénible de ne pas savoir pourquoi ça ne marche pas"\r
+\r
+Constat :\r
+- Les problèmes de connexion smtp ne sont pas affichées dans l'interface privée de SPIP après un test d'envoi via la page de config de Facteur. On a juste le message "Erreur: consultez le fichier log pour plus de détails" dans un cadre rouge.\r
+\r
+- Dans formulaires/configurer_facteur.php, facteur_envoyer_mail_test() renvoie true/false. Donc on n'a pas accès aux messages d'erreurs de phpMailer dans l'espace privé.\r
+\r
+- La gestion des exceptions via la classe phpmailerException n'est pas activée par défaut dans phpMailer (Cf le constructeur). Elle sert surtout à faire remonter les messages d'erreur.\r
+\r
+- Après avoir activé la gestion des exceptions et le mode debug de la classe smtp (qui ne fait que des echo), on peut remarquer que les messages d'erreurs affichés par les exceptions dans phpMailer ne reprennent pas les vraies causes d'erreurs relevées dans la classe smtp. Si par exemple, on n'active pas ssl dans php, le debug "echo" affiche "SMTP -> ERROR: Failed to connect to server: Unable to find the socket transport "ssl" - did you forget to enable it when you configured PHP?", mais l'exception se contente d'un "SMTP Error: Could not connect to SMTP host" dans le fichier log. C'est quand même dommage de ne pas avoir accès au premier message d'erreur.\r
+\r
+- Voir aussi :\r
+http://code.google.com/a/apache-extras.org/p/phpmailer/issues/detail?id=50\r
+http://code.google.com/a/apache-extras.org/p/phpmailer/issues/detail?id=5\r
+\r
+En attendant une éventuelle amélioration de phpMailer, on peut :\r
+\r
+- Upgrader phpMailer 5.2.1. J'ai testé, ca ne change rien au niveau de la gestion des messages d'erreur, mais ça corrige d'autres trucs. \r
+05/04/12 : Un cas foireux avec la version 5.2.1 : Si comme hôte on met un serveur ssl (ssl0.ovh.net), mais qu'on ne coche pas ssl au dessous, lors d'un test d'envoi, la roue Ajax tourne en rond indéfiniment... Pas de retour, aucune trace meme avec de simples echo... Je pense que ca tourne en rond au niveau de la fonction feof de get_lines. Cf les Notes de http://php.net/manual/fr/function.feof.php... Il n'est pas donc pas si urgent d'upgrader...\r
+\r
+- Redéfinir dans la classe Facteur, les fonctions Send, AddAttachment, AddReplyTo, AddBCC, AddCC, de la classe PhpMailer de cette façon :\r
+public function Send() {\r
+       ob_start();\r
+       parent::Send();\r
+       $error = ob_get_contents();\r
+       ob_end_clean();\r
+       if( !empty($error) ) {\r
+               spip_log("Erreur Facteur->Send : $error",'facteur.err');\r
+       }\r
+}\r
+Avec une constante pour activer ce mode et rajouter au début du constructeur de Facteur :\r
+if (defined('_FACTEUR_DEBUG_SMTP')) {\r
+       $this->SMTPDebug = _FACTEUR_DEBUG_SMTP ;\r
+}\r
+Ajouter la ligne qui suit dans mes_options.php permet donc de retrouver les erreurs dans le fichier facteur.err.log. \r
+define('_FACTEUR_DEBUG_SMTP','5'); // Le niveau peut varier de 1 à 5, 5 affichant tout le dialogue lors de la connexion smtp avec le serveur\r
+\r
+\r
+\r
diff --git a/www/plugins/facteur/facteur_administrations.php b/www/plugins/facteur/facteur_administrations.php
new file mode 100755 (executable)
index 0000000..1b0467a
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+/*
+ * Plugin Facteur 2
+ * (c) 2009-2011 Collectif SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function facteur_upgrade($nom_meta_base_version, $version_cible){
+
+       $maj = array();
+
+       $maj['create'] = array(
+               array('ecrire_meta','facteur_smtp', 'non'),
+               array('ecrire_meta','facteur_smtp_auth', 'non'),
+               array('ecrire_meta','facteur_smtp_secure', 'non'),
+               array('ecrire_meta','facteur_smtp_sender', ''),
+               array('ecrire_meta','facteur_filtre_images', 1),
+               array('ecrire_meta','facteur_filtre_css', 0),
+               array('ecrire_meta','facteur_filtre_iso_8859', 0),
+               array('ecrire_meta','facteur_adresse_envoi', 'non'),
+               array('facteur_vieil_upgrade'),
+       );
+
+       include_spip('base/upgrade');
+       maj_plugin($nom_meta_base_version, $version_cible, $maj);
+}
+
+function facteur_vieil_upgrade(){
+       // migration depuis tres ancienne version, a la main
+       if (isset($GLOBALS['meta']['spip_notifications_version'])) {
+               ecrire_meta('facteur_smtp', $GLOBALS['meta']['spip_notifications_smtp']);
+               ecrire_meta('facteur_smtp_auth', $GLOBALS['meta']['spip_notifications_smtp_auth']);
+               ecrire_meta('facteur_smtp_secure', $GLOBALS['meta']['spip_notifications_smtp_secure']);
+               ecrire_meta('facteur_smtp_sender', $GLOBALS['meta']['spip_notifications_smtp_sender']);
+               ecrire_meta('facteur_filtre_images', $GLOBALS['meta']['spip_notifications_filtre_images']);
+               ecrire_meta('facteur_filtre_css', $GLOBALS['meta']['spip_notifications_filtre_css']);
+               ecrire_meta('facteur_filtre_iso_8859', $GLOBALS['meta']['spip_notifications_filtre_iso_8859']);
+               ecrire_meta('facteur_adresse_envoi', $GLOBALS['meta']['spip_notifications_adresse_envoi']);
+               ecrire_meta('facteur_adresse_envoi_nom', $GLOBALS['meta']['spip_notifications_adresse_envoi_nom']);
+               ecrire_meta('facteur_adresse_envoi_email', $GLOBALS['meta']['spip_notifications_adresse_envoi_email']);
+               // supprimer l'ancien nommage
+               effacer_meta('spip_notifications_smtp');
+               effacer_meta('spip_notifications_smtp_auth');
+               effacer_meta('spip_notifications_smtp_secure');
+               effacer_meta('spip_notifications_smtp_sender');
+               effacer_meta('spip_notifications_filtre_images');
+               effacer_meta('spip_notifications_filtre_css');
+               effacer_meta('spip_notifications_filtre_iso_8859');
+               effacer_meta('spip_notifications_adresse_envoi');
+               effacer_meta('spip_notifications_adresse_envoi_nom');
+               effacer_meta('spip_notifications_adresse_envoi_email');
+               effacer_meta('spip_notifications_version');
+               // KEZAKO ?
+               include_spip('base/abstract_sql');
+               sql_drop_table('spip_notifications', true);
+       }
+}
+
+
+function facteur_vider_tables($nom_meta_base_version) {
+       // cfg la dessus, ca serait mieux !
+       effacer_meta('facteur_version');
+       effacer_meta('facteur_smtp');
+       effacer_meta('facteur_smtp_auth');
+       effacer_meta('facteur_smtp_secure');
+       effacer_meta('facteur_smtp_sender');
+       effacer_meta('facteur_filtre_images');
+       effacer_meta('facteur_filtre_css');
+       effacer_meta('facteur_filtre_iso_8859');
+       effacer_meta('facteur_adresse_envoi');
+       effacer_meta('facteur_adresse_envoi_nom');
+       effacer_meta('facteur_adresse_envoi_email');
+       effacer_meta('facteur_cc');
+       effacer_meta('facteur_bcc');
+       effacer_meta($nom_meta_base_version);
+}
+
+
+
+?>
diff --git a/www/plugins/facteur/facteur_fonctions.php b/www/plugins/facteur/facteur_fonctions.php
new file mode 100755 (executable)
index 0000000..3abf19a
--- /dev/null
@@ -0,0 +1,289 @@
+<?php
+/*
+ * Plugin Facteur 2
+ * (c) 2009-2011 Collectif SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Transformer un mail texte ou HTML simplifie en mail HTML complet avec le wrapper emails/texte.html
+ * Si le mail est un mail texte :
+ *   la premiere ligne est le sujet
+ *   le reste est le corps du mail
+ *
+ * Si le mail est un mail HTML simplifie :
+ *   le sujet est entre <title></title>
+ *   le corps est entre <body></body>
+ *   une eventuelle intro peut etre fournie entre <intro></intro>
+ *
+ * @param string $texte_ou_html
+ * @return string
+ */
+function facteur_email_wrap_to_html($texte_ou_html){
+       $texte_ou_html = trim($texte_ou_html);
+       // attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
+       if (!strlen(trim($texte_ou_html)))
+               return $texte_ou_html;
+
+       $contexte = array("sujet"=>"","texte"=>"","intro"=>"");
+
+       // tester si le mail est en html (simplifie)
+       if (substr($texte_ou_html,0,1)=="<"
+         AND substr($texte_ou_html,-1,1)==">"
+         AND stripos($texte_ou_html,"</body>")!==false){
+
+               // dans ce cas on ruse un peu : extraire le sujet du title
+               $sujet = "";
+               if (preg_match(",<title>(.*)</title>,Uims",$texte_ou_html,$m)){
+                       $contexte['sujet'] = $m[1];
+                       $texte_ou_html = preg_replace(",<title>(.*)</title>,Uims","",$texte_ou_html,1);
+                       $texte_ou_html = trim($texte_ou_html);
+               }
+               if (preg_match(",<intro>(.*)</intro>,Uims",$texte_ou_html,$m)){
+                       $contexte['intro'] = $m[1];
+                       $texte_ou_html = preg_replace(",<intro>(.*)</intro>,Uims","",$texte_ou_html,1);
+                       $texte_ou_html = trim($texte_ou_html);
+               }
+               $contexte['html'] = preg_replace(",</?body>,ims","",$texte_ou_html);
+       }
+       else {
+               // la premiere ligne est toujours le sujet
+               $texte_ou_html = explode("\n",$texte_ou_html);
+               $contexte['sujet'] = trim(array_shift($texte_ou_html));
+               $contexte['texte'] = trim(implode("\n",$texte_ou_html));
+       }
+
+       // attention : si pas de contenu on renvoi du vide aussi (mail vide = mail vide)
+       if (!strlen(trim(implode("",$contexte))))
+               return "";
+
+       return recuperer_fond("emails/texte",$contexte);
+}
+
+       /*
+
+       Written by Eric Dols - edols@auditavenue.com
+
+       You may freely use or modify this, provided
+       you leave credits to the original coder.
+       Feedback about (un)successfull uses, bugs and improvements done
+       are much appreciated, but don't expect actual support.
+
+       PURPOSE OF THIS FUNCTION
+               It is designed to process html emails relying
+               on a css stylesheet placed in the <head> for layout in
+               order to enhance compatibility with email clients,
+               including webmail services.
+               Provided you use minimal css, you can keep styling separate
+               from the content in your email template, and let this function
+               "inject" those styles inline in your email html tags on-the-fly,
+               just before sending.
+               Technically, it grabs the style declarations found in the
+               <head> section and inserts each declaration inline,
+               inside the corresponding html tags in the email message.
+
+               Supports both HTML and XHTML markup seamlessly. Thus
+               tolerant to email message writers using non-xhtml tag,
+               even when template is xhtml compliant (e.g. they would
+               add <img ...> instead of a xhtml compliant <img ... />).
+
+       NEW 10 dec. 2003:
+               - code revised, including a few regexp bugs fixed.
+               - multiple class for a tag are now allowed <p class="firstclass secondclass">
+               - all unsupported css styles are now moved to the body section (not just a:hover etc...)
+
+       USE
+               Add this function to a function library include, like "inline.inc"
+               and include it near the beginning of your php page:
+               require ("inline.inc");
+
+               load the html source of message into a variable
+               like $html_source and process it using:
+               $html_source = sheet2inline($html_source)
+
+
+       STYLE DEFINITIONS SUPPORTED
+               TAG { ... }
+               TAG1, TAG2, ... { ... }
+               TAG.class { ... }
+               .class { ...)
+               TAG:pseudo { ... }
+
+
+               CSS definitions may be freely formatted (spaces, tabs, linefeeds...),
+               they are converted to oneliners before inserting them inline in the html tags.
+
+               .class definitions are processed AFTER tag definitions,
+               thus appended inline after any existing tag styling to
+               preserve the normal css priority behavior.
+
+               Existing style="..." attributes in tags are NOT stripped. However they MUST
+               be with double quotes. If not, an addtional style="..." attribute will be added
+
+
+       KNOWN LIMITATIONS
+               - style info should be placed in <head> section. I believe
+                       it shouldnt be too hard to modify to point to an external
+                       stylesheet instead.
+               - no support (yet?):
+                       * chains like P UL LI { .... } or P UL LI.class { .... }
+                       * #divname p { ... } and <tag id="...">
+                       * a:hover, a:visited {...} multiple class:pseudo
+                       They require a significantly more complicated processing likely
+                       based on stylesheet and document trees parsing.
+                       Many email clients don't handle more than what is supported
+                       by this script anyway.
+               - pseudo-classes like a:hover {...} can't be inserted inline
+                       in the html tags: they are moved to a <style> declaration in
+                       the <body> instead. This is a limitation from html, not this script.
+               - It is still up to you to check if target email clients render
+                       your css styled templates correctly, especially webmail services
+                       like Hotmail, in which the email becomes a sub-part of an html page,
+                       with styles already in place.
+       */
+function facteur_convertir_styles_inline($body){
+       // variables to be accessed in the callback sub-function too
+       global $styledefinition, $styletag, $styleclass;
+
+       // Let's first load the stylesheet information in a $styles array using a regexp
+       preg_match_all ( "/^[ \t]*([.]?)([\w, #]+)([.:])?(\S*)\s+{([^}]+)}/mi", $body , $styles);
+       /*
+               $styles[1] = . or ''  => .class or tag (empty)
+               $styles[2] = name of class or tag(s)
+               $styles[3] = : . or '' => followed by pseudo-element, class separator or nothing (empty)
+               $styles[4] = name of pseudo-element after a tag, if any
+               $styles[5] = the style definition itself, i.e. what's between the { }
+       */
+
+       // Now loop through the styles found and act accordingly;
+
+       // process TAG {...} & TAG1, TAG2,... {...} definitions only first by order of appearance
+       foreach ($styles[1] as $i => $type) {
+               if ($type=="" && $styles[3][$i]=="") {
+                       $styledefinition = trim($styles[5][$i]);
+                       $styletag = preg_replace("/ *, */", "|", trim($styles[2][$i])); //echo $styletag."<br />";
+                       $styleclass = "";
+                       // process TAG {...} and TAG1, TAG2 {...} but not TAG1 TAG2 {...} or #divname styles
+                       if (!preg_match("/ /", $styletag) && !preg_match("/#/", $styletag)) {
+                               $pattern = "!<(".$styletag.")([^>]*(?= /)|[^>]*)( /)?>!mi";
+                               $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
+                               $styles[6][$i]=1; // mark as injected inline
+                       }
+               }
+       }
+
+       // append additional .CLASS {...} and TAG.CLASS {...} styling by order of appearance
+       // important to do so after TAG {...} definitions, so that class attributes override TAG styles when needed
+       foreach ($styles[1] as $i => $type) {
+               if ($type!="." && $styles[3][$i]=="." ) {       // class definition for a specific tag
+                       $styledefinition = trim($styles[5][$i]);
+                       $styletag = trim($styles[2][$i]);
+                       $styleclass = trim($styles[4][$i]);
+                       $pattern = "!<(".$styletag.")([^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*(?= /)|[^>]* class\=['\"][^'\"]*".$styleclass."[^'\"]*['\"][^>]*)( />)?>!mi";
+                       $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
+                       $styles[6][$i]=1; // mark as injected inline
+
+               }
+               elseif ($type=="." && $styles[3][$i]=="" ) {    // general class definition for any tag
+                       $styledefinition = trim($styles[5][$i]);
+                       $styletag = "";
+                       $styleclass = trim($styles[2][$i]);
+                       $pattern = "!<(\w+)([^>]* class\=['\"]".$styleclass."['\"][^>]*(?= /)|[^>]* class\=['\"]".$styleclass."['\"][^>]*)( />)?>!mi";
+                       $body = preg_replace_callback ($pattern, 'facteur_addstyle' , $body);
+                       $styles[6][$i]=1; // mark as injected inline
+               }
+       }
+
+
+       /* move all style declarations that weren't injected from <head> to a <body> <style> section,
+                including but not limited to:
+                - pseudo-classes like a:hover {...} as they can't be set inline
+                - declaration chains like UL LI {...}
+                - #divname {...}. These are not supported by email clients like Mac/Entourage anyway, it seems. */
+       foreach ($styles[1] as $i => $type) {
+               if ($styles[6][$i]=="") {
+                       // add a <style type="text/css"> section after <body> if there's isn't one yet
+                       if (preg_match ("!<body[^>]*>\s*<style!mi", $body)==0) {
+                               $body = preg_replace ("/(<body[^>]*>)/i", "\n\$1\n".'<style type="text/css">'."\n<!--\n-->\n</style>\n", $body);
+                       }
+                       // append a copy of the pseudo-element declaration to that body style section
+                       $styledefinition = trim($styles[5][$i]);
+                       $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition ); // convert style definition to a one-liner (optional)
+                       $declaration = $styles[1][$i].trim($styles[2][$i]).$styles[3][$i].trim($styles[4][$i])." { ".$styledefinition." }";
+                       $body = preg_replace ("!(<body[^>]*>\s*<style[^>]*>\s*<\!\-\-[^>]*)"."(\s*\-\->\s*</style>)!si", "\$1".$declaration."\n\$2", $body);
+                       $styles[6][$i]= 2; // mark as moved to <style> section in <body>
+               }
+       }
+
+       // remove stylesheet declaration(s) from <head> section (comment following line out if not wanted)
+       //$body = preg_replace ("!(<head>.*)<style type.*</style>(.*</head>)!si", "\$1\$2" , $body);
+
+       // check what styles have been injected
+#                      print_r($styles);
+
+       return $body;
+}
+
+/**
+ * facteur_addstyle
+ * @author Eric Dols
+ *
+ * @param $matches
+ * @return string
+ */
+function facteur_addstyle($matches) {
+
+       // $matches[1]=tag, $matches[2]=tag attributes (if any), $matches[3]=xhtml closing (if any)
+
+       // variables values set in calling function
+       global $styledefinition, $styletag, $styleclass;
+
+       // convert the style definition to a one-liner
+       $styledefinition = preg_replace ("!\s+!mi", " ", $styledefinition );
+       // convert all double-quotes to single-quotes
+       $styledefinition = preg_replace ('/"/','\'', $styledefinition );
+
+       if (preg_match ("/style\=/i", $matches[2])) {
+                       // add styles to existing style attribute if any already in the tag
+                       $pattern = "!(.* style\=)[\"]([^\"]*)[\"](.*)!mi";
+                       $replacement = "\$1".'"'."\$2 ".$styledefinition.'"'."\$3";
+                       $attributes = preg_replace ($pattern, $replacement , $matches[2]);
+       } else {
+                       // otherwise add new style attribute to tag (none was present)
+                       $attributes = $matches[2].' style="'.$styledefinition.'"';
+       }
+
+       if ($styleclass!="") {
+               // if we were injecting a class style, remove the now useless class attribute from the html tag
+
+               // Single class in tag case (class="classname"): remove class attribute altogether
+               $pattern = "!(.*) class\=['\"]".$styleclass."['\"](.*)!mi";
+               $replacement = "\$1\$2";
+               $attributes = preg_replace ( $pattern, $replacement, $attributes);
+
+               // Multiple classes in tag case (class="classname anotherclass..."): remove class name from class attribute.
+               // classes are injected inline and removed by order of appearance in <head> stylesheet
+               // exact same behavior as where last declared class attributes in <style> take over (IE6 tested only)
+               $pattern = "!(.* class\=['\"][^\"]*)(".$styleclass." | ".$styleclass.")([^\"]*['\"].*)!mi";
+               $replacement = "\$1\$3";
+               $attributes = preg_replace ( $pattern, $replacement, $attributes);
+
+       }
+
+       return "<".$matches[1].$attributes.$matches[3].">";
+}
+
+/**
+ * Un filtre pour transformer les retour ligne texte en br si besoin (si pas autobr actif)
+ *
+ * @param string $texte
+ * @return string
+ */
+function facteur_nl2br_si_pas_autobr($texte){
+       return (_AUTOBR?$texte:nl2br($texte));
+}
+
+?>
diff --git a/www/plugins/facteur/facteur_ieconfig_metas.php b/www/plugins/facteur/facteur_ieconfig_metas.php
new file mode 100644 (file)
index 0000000..5f0e1bf
--- /dev/null
@@ -0,0 +1,18 @@
+<?php\r
+/*\r
+ * Plugin Facteur 2\r
+ * (c) 2009-2011 Collectif SPIP\r
+ * Distribue sous licence GPL\r
+ *\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+function facteur_ieconfig_metas($table){\r
+       $table['facteur']['titre'] = _T('facteur:configuration_facteur');\r
+       $table['facteur']['icone'] = 'facteur-16.png';\r
+       $table['facteur']['metas_brutes'] = 'facteur_adresse_envoi,facteur_adresse_envoi_nom,facteur_adresse_envoi_email,facteur_smtp,facteur_smtp_host,facteur_smtp_port,facteur_smtp_auth,facteur_smtp_username,facteur_smtp_password,facteur_smtp_secure,facteur_smtp_sender,facteur_filtre_images,facteur_filtre_css,facteur_filtre_iso_8859';\r
+       return $table;\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/formulaires/configurer_facteur.html b/www/plugins/facteur/formulaires/configurer_facteur.html
new file mode 100644 (file)
index 0000000..6f7122b
--- /dev/null
@@ -0,0 +1,197 @@
+<div class="formulaire_spip formulaire_configurer formulaire_#FORM">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+       [(#ENV{tester,''}|oui)
+       <iframe style='width:95%;height:500px;margin:10px;' src='#URL_PAGE{emails/test_email_html,var_mode=calcul}'></iframe>
+       ]
+       <form method="post" action="#ENV{action}"><div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <fieldset>
+                                       <legend><:facteur:configuration_adresse_envoi:></legend>
+                                       <ul>
+                                               <li class="editer editer_facteur_adresse_envoi [ (#ENV**{erreurs}|table_valeur{facteur_adresse_envoi}|oui)erreur]">
+                                                       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_adresse_envoi})</span>]
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_adresse_envoi" class="radio" value="non" id="facteur_adresse_envoi_non"[(#ENV{facteur_adresse_envoi,'non'}|=={non}|oui)checked="checked"]/>
+                                                               <label for="facteur_adresse_envoi_non"><:facteur:utiliser_reglages_site:></label>
+                                                       </div>
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_adresse_envoi" class="radio" value="oui" id="facteur_adresse_envoi_oui"[(#ENV{facteur_adresse_envoi,'non'}|=={oui}|oui)checked="checked"]/>
+                                                               <label for="facteur_adresse_envoi_oui"><:facteur:personnaliser:></label>
+                                                       </div>
+                                               </li>
+                                               <li class="editer editer_facteur_adresse_envoi_perso editer_facteur_adresse_envoi_nom [ (#ENV**{erreurs}|table_valeur{facteur_adresse_envoi_nom}|oui)erreur]"[(#ENV{facteur_adresse_envoi,'non'}|=={non}|oui)style='display:none;']>
+                                                       <label for="facteur_adresse_envoi_nom"><:facteur:facteur_adresse_envoi_nom:></label>[
+                                                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_adresse_envoi_nom})</span>]
+                                                       <input type="text" name="facteur_adresse_envoi_nom" class="text" value="#ENV**{facteur_adresse_envoi_nom}" id="facteur_adresse_envoi_nom" />
+                                               </li>
+                                               <li class="editer editer_facteur_adresse_envoi_perso editer_facteur_adresse_envoi_email [ (#ENV**{erreurs}|table_valeur{facteur_adresse_envoi_email}|oui)erreur]"[(#ENV{facteur_adresse_envoi,'non'}|=={non}|oui)style='display:none;']>
+                                                       <label for="facteur_adresse_envoi_email"><:facteur:facteur_adresse_envoi_email:></label>[
+                                                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_adresse_envoi_email})</span>]
+                                                       <input type="text" name="facteur_adresse_envoi_email" class="text" value="#ENV**{facteur_adresse_envoi_email}" id="facteur_adresse_envoi_email" />
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+                       <li class="fieldset">
+                               <fieldset>
+                                       <legend><:facteur:configuration_mailer:></legend>
+                                       <ul>
+                                               <li class="editer editer_facteur_smtp [ (#ENV**{erreurs}|table_valeur{facteur_smtp}|oui)erreur]">
+                                                       <label><:facteur:configuration_smtp:></label>
+                                                       <p class="explication"><:facteur:configuration_smtp_descriptif:></p>
+                                                       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp})</span>]
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_smtp" class="radio" value="non" id="facteur_smtp_non"[(#ENV{facteur_smtp,'non'}|=={non}|oui)checked="checked"]/>
+                                                               <label for="facteur_smtp_non"><:facteur:utiliser_mail:></label>
+                                                       </div>
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_smtp" class="radio" value="oui" id="facteur_smtp_oui"[(#ENV{facteur_smtp,'non'}|=={oui}|oui)checked="checked"]/>
+                                                               <label for="facteur_smtp_oui"><:facteur:utiliser_smtp:></label>
+                                                       </div>
+                                               </li>
+                                               <li class="editer editer_facteur_smtp_param editer_facteur_smtp_host [ (#ENV**{erreurs}|table_valeur{facteur_smtp_host}|oui)erreur]"[(#ENV{facteur_smtp,'non'}|=={non}|oui)style='display:none;']>
+                                                       <label for="facteur_smtp_host"><:facteur:facteur_smtp_host:></label>[
+                                                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_host})</span>]
+                                                       <input type="text" name="facteur_smtp_host" class="text" value="#ENV**{facteur_smtp_host}" id="facteur_smtp_host" />
+                                               </li>
+                                               <li class="editer editer_facteur_smtp_param editer_facteur_smtp_port [ (#ENV**{erreurs}|table_valeur{facteur_smtp_port}|oui)erreur]"[(#ENV{facteur_smtp,'non'}|=={non}|oui)style='display:none;']>
+                                                       <label for="facteur_smtp_port"><:facteur:facteur_smtp_port:></label>[
+                                                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_port})</span>]
+                                                       <input type="text" name="facteur_smtp_port" class="text" value="#ENV**{facteur_smtp_port}" id="facteur_smtp_port" />
+                                               </li>
+                                               <li class="editer editer_facteur_smtp_param editer_facteur_smtp_auth [ (#ENV**{erreurs}|table_valeur{facteur_smtp_auth}|oui)erreur]"[(#ENV{facteur_smtp,'non'}|=={non}|oui)style='display:none;']>
+                                                       <label><:facteur:facteur_smtp_auth:></label>
+                                                       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_auth})</span>]
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_smtp_auth" class="radio" value="non" id="facteur_smtp_auth_non"[(#ENV{facteur_smtp_auth,'non'}|=={non}|oui)checked="checked"]/>
+                                                               <label for="facteur_smtp_auth_non"><:facteur:facteur_smtp_auth_non:></label>
+                                                       </div>
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_smtp_auth" class="radio" value="oui" id="facteur_smtp_auth_oui"[(#ENV{facteur_smtp_auth,'non'}|=={oui}|oui)checked="checked"]/>
+                                                               <label for="facteur_smtp_auth_oui"><:facteur:facteur_smtp_auth_oui:></label>
+                                                       </div>
+                                                       <ul id="smtp-auth"[(#ENV{facteur_smtp_auth,'non'}|=={non}|oui)style='display:none;']>
+                                                               <li class="editer_facteur_smtp_username [ (#ENV**{erreurs}|table_valeur{facteur_smtp_username}|oui)erreur]">
+                                                                       <label for="facteur_smtp_username"><:facteur:facteur_smtp_username:></label>[
+                                                                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_username})</span>]
+                                                                       <input type="text" name="facteur_smtp_username" class="text" value="#ENV**{facteur_smtp_username}" id="facteur_smtp_username" />
+                                                               </li>
+                                                               <li class="editer_facteur_smtp_password [ (#ENV**{erreurs}|table_valeur{facteur_smtp_password}|oui)erreur]">
+                                                                       <label for="facteur_smtp_password"><:facteur:facteur_smtp_password:></label>[
+                                                                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_password})</span>]
+                                                                       <input type="password" name="facteur_smtp_password" class="text" value="#ENV**{facteur_smtp_password}" id="facteur_smtp_password" />
+                                                               </li>
+                                                       </ul>
+                                               </li>
+                                               [(#ENV{_enable_smtp_secure}|oui)
+                                               <li class="editer editer_facteur_smtp_param editer_facteur_smtp_secure [ (#ENV**{erreurs}|table_valeur{facteur_smtp_secure}|oui)erreur]"[(#ENV{facteur_smtp,'non'}|=={non}|oui)style='display:none;']>
+                                                       <label><:facteur:facteur_smtp_secure:></label>
+                                                       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_secure})</span>]
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_smtp_secure" class="radio" value="non" id="facteur_smtp_secure_non"[(#ENV{facteur_smtp_secure,'non'}|=={non}|oui)checked="checked"]/>
+                                                               <label for="facteur_smtp_secure_non"><:facteur:facteur_smtp_secure_non:></label>
+                                                       </div>
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_smtp_secure" class="radio" value="ssl" id="facteur_smtp_secure_ssl"[(#ENV{facteur_smtp_secure,'non'}|=={ssl}|oui)checked="checked"]/>
+                                                               <label for="facteur_smtp_secure_ssl"><:facteur:facteur_smtp_secure_ssl:></label>
+                                                       </div>
+                                                       <div class="choix">
+                                                               <input type="radio" name="facteur_smtp_secure" class="radio" value="tls" id="facteur_smtp_secure_tls"[(#ENV{facteur_smtp_secure,'non'}|=={tls}|oui)checked="checked"]/>
+                                                               <label for="facteur_smtp_secure_tls"><:facteur:facteur_smtp_secure_tls:></label>
+                                                       </div>
+                                               </li>]
+                                               <li class="editer editer_facteur_smtp_sender [ (#ENV**{erreurs}|table_valeur{facteur_smtp_sender}|oui)erreur]">
+                                                       <label for="facteur_smtp_sender"><:facteur:facteur_smtp_sender:></label>[
+                                                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_sender})</span>]
+                                                       <p class="explication"><:facteur:facteur_smtp_sender_descriptif:></p>
+                                                       <input type="text" name="facteur_smtp_sender" class="text" value="#ENV**{facteur_smtp_sender}" id="facteur_smtp_sender" />
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+                       <li class="fieldset">
+                               <fieldset>
+                                       <legend><:facteur:facteur_filtres:></legend>
+                                       <ul>
+                                               <li class="editer editer_facteur_filtres[ (#ENV**{erreurs}|table_valeur{facteur_filtres}|oui)erreur]">
+                                                       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_smtp_secure})</span>]
+                                                       <p class="explication"><:facteur:facteur_filtres_descriptif:></p>
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="facteur_filtre_images" class="checkbox" value="1" id="facteur_filtre_images"[(#ENV{facteur_filtre_images,''}|=={1}|oui)checked="checked"]/>
+                                                               <label for="facteur_filtre_images"><:facteur:facteur_filtre_images:></label>
+                                                       </div>
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="facteur_filtre_iso_8859" class="checkbox" value="1" id="facteur_filtre_iso_8859"[(#ENV{facteur_filtre_iso_8859,''}|=={1}|oui)checked="checked"]/>
+                                                               <label for="facteur_filtre_iso_8859"><:facteur:facteur_filtre_iso_8859:></label>
+                                                       </div>
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+                       <li class="fieldset">
+                               <fieldset>
+                                       <legend><:facteur:facteur_copies:></legend>
+                                       <ul>
+                                               <li class="editer editer_facteur_copies editer_facteur_desc">
+                                                       <p class="explication"><:facteur:facteur_copies_descriptif:></p>
+                                               </li>
+                                               <li class="editer editer_facteur_copies editer_facteur_cc [ (#ENV**{erreurs}|table_valeur{facteur_cc}|oui)erreur]">
+                                                       <label for="facteur_cc"><:facteur:facteur_cc:></label>
+                                                       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_cc})</span>]
+                                                       <input type="text" name="facteur_cc" class="text" value="#ENV**{facteur_cc}" id="facteur_cc" />
+                                               </li>
+                                               <li class="editer editer_facteur_copies editer_facteur_bcc [ (#ENV**{erreurs}|table_valeur{facteur_bcc}|oui)erreur]">
+                                                       <label for="facteur_bcc"><:facteur:facteur_bcc:></label>
+                                                       [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{facteur_bcc})</span>]
+                                                       <input type="text" name="facteur_bcc" class="text" value="#ENV**{facteur_bcc}" id="facteur_bcc" />
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" name="valider" class="submit" value="<:bouton_valider:>" />
+               </p>
+               <ul>
+                       <li class="fieldset">
+                               <fieldset>
+                                       <h3 class="legend"><:facteur:tester_la_configuration:></h3>
+                                       <ul>
+                                               <li>
+                                               <p class="explication"><:facteur:note_test_configuration:></p>  
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" name="tester" class="submit" value="<:facteur:tester:>" />
+               </p>
+       </div></form>
+</div>
+<script type="text/javascript">
+jQuery(function(){
+       jQuery('input[name=facteur_adresse_envoi]').change(function(){
+                       if (jQuery(this).attr('value')=='oui')
+                               jQuery('.editer_facteur_adresse_envoi_perso').show('fast');
+                       else
+                               jQuery('.editer_facteur_adresse_envoi_perso').hide('fast');
+       });
+       jQuery('input[name=facteur_smtp]').change(function(){
+                       if (jQuery(this).attr('value')=='oui')
+                               jQuery('.editer_facteur_smtp_param').show('fast');
+                       else
+                               jQuery('.editer_facteur_smtp_param').hide('fast');
+       });
+       jQuery('input[name=facteur_smtp_auth]').change(function(){
+                       if (jQuery(this).attr('value')=='oui')
+                               jQuery('#smtp-auth').show('fast');
+                       else
+                               jQuery('#smtp-auth').hide('fast');
+       });
+})
+</script>
diff --git a/www/plugins/facteur/formulaires/configurer_facteur.php b/www/plugins/facteur/formulaires/configurer_facteur.php
new file mode 100644 (file)
index 0000000..0aa321b
--- /dev/null
@@ -0,0 +1,171 @@
+<?php\r
+/*\r
+ * Plugin Facteur 2\r
+ * (c) 2009-2011 Collectif SPIP\r
+ * Distribue sous licence GPL\r
+ *\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+function formulaires_configurer_facteur_charger_dist(){\r
+       $valeurs = array(\r
+               'facteur_adresse_envoi' => $GLOBALS['meta']['facteur_adresse_envoi'],\r
+               'facteur_adresse_envoi_nom' => $GLOBALS['meta']['facteur_adresse_envoi_nom'],\r
+               'facteur_adresse_envoi_email' => $GLOBALS['meta']['facteur_adresse_envoi_email'],\r
+               'facteur_smtp' => $GLOBALS['meta']['facteur_smtp'],\r
+               'facteur_smtp_host' => $GLOBALS['meta']['facteur_smtp_host'],\r
+               'facteur_smtp_port' => $GLOBALS['meta']['facteur_smtp_port']?$GLOBALS['meta']['facteur_smtp_port']:'25',\r
+               'facteur_smtp_auth' => $GLOBALS['meta']['facteur_smtp_auth'],\r
+               'facteur_smtp_username' => $GLOBALS['meta']['facteur_smtp_username'],\r
+               'facteur_smtp_password' => $GLOBALS['meta']['facteur_smtp_password'],\r
+               'facteur_smtp_secure' => $GLOBALS['meta']['facteur_smtp_secure'],\r
+               'facteur_smtp_sender' => $GLOBALS['meta']['facteur_smtp_sender'],\r
+               'facteur_filtre_images' => $GLOBALS['meta']['facteur_filtre_images'],\r
+               'facteur_filtre_iso_8859' => $GLOBALS['meta']['facteur_filtre_iso_8859'],\r
+               '_enable_smtp_secure' => (intval(phpversion()) == 5)?' ':'',\r
+               'facteur_cc' => $GLOBALS['meta']['facteur_cc'],\r
+               'facteur_bcc' => $GLOBALS['meta']['facteur_bcc'],\r
+       'tester' => '',\r
+       );\r
+\r
+       return $valeurs;\r
+}\r
+\r
+function formulaires_configurer_facteur_verifier_dist(){\r
+       $erreurs = array();\r
+       if ($email = _request('facteur_adresse_envoi_email')\r
+         AND !email_valide($email)) {\r
+               $erreurs['facteur_adresse_envoi_email'] = _T('form_email_non_valide');\r
+               set_request('facteur_adresse_envoi','oui');\r
+       }\r
+       if (_request('facteur_smtp')=='oui'){\r
+               if (!($h=_request('facteur_smtp_host')))\r
+                       $erreurs['facteur_smtp_host'] = _T('info_obligatoire');\r
+               else {\r
+                       $regexp_ip_valide = '#^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$#'; \r
+                       // Source : http://www.d-sites.com/2008/10/09/regex-ipv4-et-ipv6/\r
+                       if (!preg_match($regexp_ip_valide,$h)){ // ce n'est pas une IP\r
+                               if(!preg_match(';^([^.\s/?:]+[.]){0,2}[^.\s/?:]+$;',$h)\r
+                                 OR gethostbyname($h)==$h)\r
+                                       $erreurs['facteur_smtp_host'] = _T('facteur:erreur_invalid_host');\r
+                       }\r
+                       else {\r
+                               if (gethostbyaddr($h)==$h)\r
+                                       $erreurs['facteur_smtp_host'] = _T('facteur:erreur_invalid_host');                              \r
+                       }\r
+               }\r
+               if (!($p=_request('facteur_smtp_port')))\r
+                       $erreurs['facteur_smtp_port'] = _T('info_obligatoire');\r
+               elseif(!preg_match(';^[0-9]+$;',$p) OR !intval($p))\r
+                       $erreurs['facteur_smtp_port'] = _T('facteur:erreur_invalid_port');\r
+\r
+               if (!_request('facteur_smtp_auth'))\r
+                       $erreurs['facteur_smtp_auth'] = _T('info_obligatoire');\r
+\r
+               if (_request('facteur_smtp_auth')=='oui'){\r
+                       if (!_request('facteur_smtp_username'))\r
+                               $erreurs['facteur_smtp_username'] = _T('info_obligatoire');\r
+                       if (!_request('facteur_smtp_password'))\r
+                               $erreurs['facteur_smtp_password'] = _T('info_obligatoire');\r
+               }\r
+       }\r
+       if ($emailcc = _request('facteur_cc')\r
+         AND !email_valide($emailcc)) {\r
+               $erreurs['facteur_cc'] = _T('form_email_non_valide');\r
+       }\r
+       if ($emailbcc = _request('facteur_bcc')\r
+         AND !email_valide($emailbcc)) {\r
+               $erreurs['facteur_bcc'] = _T('form_email_non_valide');\r
+       }\r
+       \r
+       if(count($erreurs)>0){\r
+               $erreurs['message_erreur'] = _T('facteur:erreur_generale');\r
+       }\r
+       return $erreurs;\r
+}\r
+\r
+function formulaires_configurer_facteur_traiter_dist(){\r
+       include_spip('inc/meta');\r
+\r
+       $facteur_adresse_envoi = _request('facteur_adresse_envoi');\r
+       ecrire_meta('facteur_adresse_envoi', ($facteur_adresse_envoi=='oui')?'oui':'non');\r
+\r
+       $facteur_adresse_envoi_nom = _request('facteur_adresse_envoi_nom');\r
+       ecrire_meta('facteur_adresse_envoi_nom', $facteur_adresse_envoi_nom?$facteur_adresse_envoi_nom:'');\r
+\r
+       $facteur_adresse_envoi_email = _request('facteur_adresse_envoi_email');\r
+       ecrire_meta('facteur_adresse_envoi_email', $facteur_adresse_envoi_email?$facteur_adresse_envoi_email:'');\r
+\r
+       $facteur_smtp = _request('facteur_smtp');\r
+       ecrire_meta('facteur_smtp', ($facteur_smtp=='oui')?'oui':'non');\r
+\r
+       $facteur_smtp_host = _request('facteur_smtp_host');\r
+       ecrire_meta('facteur_smtp_host', $facteur_smtp_host?$facteur_smtp_host:'');\r
+\r
+       $facteur_smtp_port = _request('facteur_smtp_port');\r
+       ecrire_meta('facteur_smtp_port', strlen($facteur_smtp_port)?intval($facteur_smtp_port):'');\r
+\r
+       $facteur_smtp_auth = _request('facteur_smtp_auth');\r
+       ecrire_meta('facteur_smtp_auth', ($facteur_smtp_auth=='oui')?'oui':'non');\r
+\r
+       $facteur_smtp_username = _request('facteur_smtp_username');\r
+       ecrire_meta('facteur_smtp_username', $facteur_smtp_username);\r
+\r
+       $facteur_smtp_password = _request('facteur_smtp_password');\r
+       ecrire_meta('facteur_smtp_password', $facteur_smtp_password);\r
+\r
+       if (intval(phpversion()) == 5) {\r
+               $facteur_smtp_secure = _request('facteur_smtp_secure');\r
+               ecrire_meta('facteur_smtp_secure', in_array($facteur_smtp_secure,array('non','ssl','tls'))?$facteur_smtp_secure:'non');\r
+       }\r
+\r
+       $facteur_smtp_sender = _request('facteur_smtp_sender');\r
+       ecrire_meta('facteur_smtp_sender', $facteur_smtp_sender);\r
+\r
+       ecrire_meta('facteur_filtre_images', intval(_request('facteur_filtre_images')));\r
+       ecrire_meta('facteur_filtre_iso_8859', intval(_request('facteur_filtre_iso_8859')));\r
+\r
+       $facteur_cc = _request('facteur_cc');\r
+       ecrire_meta('facteur_cc', $facteur_cc?$facteur_cc:'');\r
+\r
+       $facteur_bcc = _request('facteur_bcc');\r
+       ecrire_meta('facteur_bcc', $facteur_bcc?$facteur_bcc:'');\r
+       \r
+       \r
+       $res = array('message_ok'=>_T('facteur:config_info_enregistree'));\r
+\r
+       // faut-il envoyer un message de test ?\r
+       if (_request('tester')){\r
+\r
+               if ($GLOBALS['meta']['facteur_adresse_envoi'] == 'oui'\r
+                 AND $GLOBALS['meta']['facteur_adresse_envoi_email'])\r
+                       $destinataire = $GLOBALS['meta']['facteur_adresse_envoi_email'];\r
+               else\r
+                       $destinataire = $GLOBALS['meta']['email_webmaster'];\r
+\r
+               if ((facteur_envoyer_mail_test($destinataire,_T('facteur:corps_email_de_test')))===true){\r
+                       // OK\r
+                       $res = array('message_ok'=>_T('facteur:email_test_envoye'));\r
+               }\r
+               else {\r
+                       // erreur\r
+                       $res = array('message_erreur'=>_T('facteur:erreur')._T('facteur:erreur_dans_log'));\r
+               }\r
+       }\r
+       \r
+       return $res;\r
+}\r
+\r
+function facteur_envoyer_mail_test($destinataire,$titre){\r
+       include_spip('classes/facteur');\r
+       $message_html   = recuperer_fond('emails/test_email_html', array());\r
+       $message_texte  = recuperer_fond('emails/test_email_texte', array());\r
+\r
+       // passer par envoyer_mail pour bien passer par les pipeline et avoir tous les logs\r
+       $envoyer_mail = charger_fonction('envoyer_mail','inc');\r
+       $retour = $envoyer_mail($destinataire, $titre, array('html'=>$message_html,'texte'=>$message_texte));\r
+\r
+       return $retour?true:false;\r
+}\r
+?>\r
diff --git a/www/plugins/facteur/inc/envoyer_mail.php b/www/plugins/facteur/inc/envoyer_mail.php
new file mode 100644 (file)
index 0000000..ef29058
--- /dev/null
@@ -0,0 +1,194 @@
+<?php\r
+/*\r
+ * Plugin Facteur 2\r
+ * (c) 2009-2011 Collectif SPIP\r
+ * Distribue sous licence GPL\r
+ *\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+include_spip('classes/facteur');\r
+// inclure le fichier natif de SPIP, pour les fonctions annexes\r
+include_once _DIR_RESTREINT."inc/envoyer_mail.php";\r
+\r
+/**\r
+ * @param string $destinataire\r
+ * @param string $sujet\r
+ * @param string|array $corps\r
+ *   au format string, c'est un corps d'email au format texte, comme supporte nativement par le core\r
+ *   au format array, c'est un corps etendu qui peut contenir\r
+ *     string texte : le corps d'email au format texte\r
+ *     string html : le corps d'email au format html\r
+ *     string from : email de l'envoyeur (prioritaire sur argument $from de premier niveau, deprecie)\r
+ *     string nom_envoyeur : un nom d'envoyeur pour completer l'email from\r
+ *     string cc : destinataires en copie conforme\r
+ *     string bcc : destinataires en copie conforme cachee\r
+ *     string|array repondre_a : une ou plusieurs adresses à qui répondre\r
+ *     string adresse_erreur : addresse de retour en cas d'erreur d'envoi\r
+ *     array pieces_jointes : listes de pieces a embarquer dans l'email, chacune au format array :\r
+ *       string chemin : chemin file system pour trouver le fichier a embarquer\r
+ *       string nom : nom du document tel qu'apparaissant dans l'email\r
+ *       string encodage : encodage a utiliser, parmi 'base64', '7bit', '8bit', 'binary', 'quoted-printable'\r
+ *       string mime : mime type du document\r
+ *     array headers : tableau d'en-tetes personalises, une entree par ligne d'en-tete\r
+ * @param string $from (deprecie, utiliser l'entree from de $corps)\r
+ * @param string $headers (deprecie, utiliser l'entree headers de $corps)\r
+ * @return bool\r
+ */\r
+function inc_envoyer_mail($destinataire, $sujet, $corps, $from = "", $headers = "") {\r
+       $message_html   = '';\r
+       $message_texte  = '';\r
+\r
+       // si $corps est un tableau -> fonctionnalites etendues\r
+       // avec entrees possible : html, texte, pieces_jointes, nom_envoyeur, ...\r
+       if (is_array($corps)) {\r
+               $message_html   = $corps['html'];\r
+               $message_texte  = nettoyer_caracteres_mail($corps['texte']);\r
+               $pieces_jointes = $corps['pieces_jointes'];\r
+               $nom_envoyeur = $corps['nom_envoyeur'];\r
+               $from = (isset($corps['from'])?$corps['from']:$from);\r
+               $cc = $corps['cc'];\r
+               $bcc = $corps['bcc'];\r
+               $repondre_a = $corps['repondre_a'];\r
+               $adresse_erreur = $corps['adresse_erreur'];\r
+               $headers = (isset($corps['headers'])?$corps['headers']:$headers);\r
+               if (is_string($headers))\r
+                       $headers = array_map('trim',explode("\n",$headers));\r
+       }\r
+       // si $corps est une chaine -> compat avec la fonction native SPIP\r
+       // gerer le cas ou le corps est du html avec un Content-Type: text/html dans les headers\r
+       else {\r
+               if (preg_match(',Content-Type:\s*text/html,ims',$headers)){\r
+                       $message_html   = $corps;\r
+               }\r
+               else {\r
+                       $message_texte  = nettoyer_caracteres_mail($corps);\r
+               }\r
+               $headers = array_map('trim',explode("\n",$headers));\r
+       }\r
+       $sujet = nettoyer_titre_email($sujet);\r
+\r
+       // si le mail est en texte brut, on l'encapsule dans un modele surchargeable\r
+       // pour garder le texte brut, il suffit de faire un modele qui renvoie uniquement #ENV*{texte}\r
+       if ($message_texte AND ! $message_html){\r
+               $message_html = recuperer_fond("emails/texte",array('texte'=>$message_texte,'sujet'=>$sujet));\r
+       }\r
+\r
+       // mode TEST : forcer l'email\r
+       if (defined('_TEST_EMAIL_DEST')) {\r
+               if (!_TEST_EMAIL_DEST)\r
+                       return false;\r
+               else\r
+                       $destinataire = _TEST_EMAIL_DEST;\r
+       }\r
+\r
+       // plusieurs destinataires peuvent etre fournis separes par des virgules\r
+       // c'est un format standard dans l'envoi de mail\r
+       // les passer au format array pour phpMailer\r
+       // mais ne pas casser si on a deja un array en entree\r
+       if (is_array($destinataire))\r
+               $destinataire = implode(", ",$destinataire);\r
+       $destinataire = array_map('trim',explode(",",$destinataire));\r
+       \r
+       // On crée l'objet Facteur (PHPMailer) pour le manipuler ensuite\r
+       $facteur = new Facteur($destinataire, $sujet, $message_html, $message_texte);\r
+       \r
+       // On ajoute le courriel de l'envoyeur s'il est fournit par la fonction\r
+       if (empty($from) AND empty($facteur->From)) {\r
+               $from = $GLOBALS['meta']["email_envoi"];\r
+               if (empty($from) OR !email_valide($from)) {\r
+                       spip_log("Meta email_envoi invalide. Le mail sera probablement vu comme spam.");\r
+                       $from = $destinataire;\r
+               }\r
+       }\r
+\r
+       // "Marie Toto <Marie@toto.com>"\r
+       if (preg_match(",^([^<>\"]*)<([^<>\"]+)>$,i",$from,$m)){\r
+               $nom_envoyeur = trim($m[1]);\r
+               $from = trim($m[2]);\r
+       }\r
+       if (!empty($from)){\r
+               $facteur->From = $from;\r
+               // la valeur par défaut de la config n'est probablement pas valable pour ce mail,\r
+               // on l'écrase pour cet envoi\r
+               $facteur->FromName = $from;\r
+       }\r
+\r
+       // On ajoute le nom de l'envoyeur s'il fait partie des options\r
+       if ($nom_envoyeur)\r
+               $facteur->FromName = $nom_envoyeur;\r
+\r
+       // Si plusieurs emails dans le from, pas de Name !\r
+       if (strpos($facteur->From,",")!==false){\r
+               $facteur->FromName = "";\r
+       }\r
+\r
+       // S'il y a des copies à envoyer\r
+       if ($cc){\r
+               if (is_array($cc))\r
+                       foreach ($cc as $courriel)\r
+                               $facteur->AddCC($courriel);\r
+               else\r
+                       $facteur->AddCC($cc);\r
+       }\r
+       \r
+       // S'il y a des copies cachées à envoyer\r
+       if ($bcc){\r
+               if (is_array($bcc))\r
+                       foreach ($bcc as $courriel)\r
+                               $facteur->AddBCC($courriel);\r
+               else\r
+                       $facteur->AddBCC($bcc);\r
+       }\r
+       \r
+       // S'il y a des copies cachées à envoyer\r
+       if ($repondre_a){\r
+               if (is_array($repondre_a))\r
+                       foreach ($repondre_a as $courriel)\r
+                               $facteur->AddReplyTo($courriel);\r
+               else\r
+                       $facteur->AddReplyTo($repondre_a);\r
+       }\r
+       \r
+       // S'il y a des pièces jointes on les ajoute proprement\r
+       if (count($pieces_jointes)) {\r
+               foreach ($pieces_jointes as $piece) {\r
+                       $facteur->AddAttachment(\r
+                               $piece['chemin'],\r
+                               isset($piece['nom']) ? $piece['nom']:'',\r
+                               (isset($piece['encodage']) AND in_array($piece['encodage'],array('base64', '7bit', '8bit', 'binary', 'quoted-printable'))) ? $piece['encodage']:'base64',\r
+                               isset($piece['mime']) ? $piece['mime']:Facteur::_mime_types(pathinfo($piece['chemin'], PATHINFO_EXTENSION))\r
+                       );\r
+               }\r
+       }\r
+\r
+       // Si une adresse email a été spécifiée pour les retours en erreur, on l'ajoute\r
+       if (!empty($adresse_erreur))\r
+               $facteur->Sender = $adresse_erreur;\r
+\r
+       // si entetes personalises : les ajouter\r
+       // bug : semble ecraser les autres headers. A debug si on veut le rendre fonctionnel\r
+       //if (!empty($headers)) {\r
+       //      foreach($headers as $h)\r
+       //              $facteur->AddCustomHeader($h);\r
+       //}\r
+       \r
+       // On passe dans un pipeline pour modifier tout le facteur avant l'envoi\r
+       $facteur = pipeline('facteur_pre_envoi', $facteur);\r
+       \r
+       // On génère les headers\r
+       $head = $facteur->CreateHeader();\r
+\r
+       // Et c'est parti on envoie enfin\r
+       spip_log("mail via facteur\n$head"."Destinataire:".print_r($destinataire,true),'mail');\r
+       spip_log("mail\n$head"."Destinataire:".print_r($destinataire,true),'facteur');\r
+       $retour = $facteur->Send();\r
+       \r
+       if (!$retour)\r
+               spip_log("Erreur Envoi mail via Facteur : ".print_r($facteur->ErrorInfo,true),'facteur');\r
+\r
+       return $retour ;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/facteur/inc/facteur_classes.php b/www/plugins/facteur/inc/facteur_classes.php
new file mode 100644 (file)
index 0000000..60244e0
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+/*
+ * Plugin Facteur 2
+ * (c) 2009-2011 Collectif SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/*
+ * Compatibilite avec plugins faisant un appel direct a ce fichier
+ */
+include_spip('classes/facteur');
+
+
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/lang/facteur.xml b/www/plugins/facteur/lang/facteur.xml
new file mode 100644 (file)
index 0000000..dd30a59
--- /dev/null
@@ -0,0 +1,13 @@
+<traduction module="facteur" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/facteur/trunk/lang/" reference="fr">
+       <langue code="de" />
+       <langue code="en" url="http://trad.spip.net/tradlang_module/facteur?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/facteur?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/facteur?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/facteur/lang/facteur_de.php b/www/plugins/facteur/lang/facteur_de.php
new file mode 100644 (file)
index 0000000..47bd055
--- /dev/null
@@ -0,0 +1,79 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/facteur?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'Z' => 'ZZzZZzzz',
+
+       // C
+       'config_info_enregistree' => 'Die Konfiguration des Briedträgers wurde gespeichert',
+       'configuration_adresse_envoi' => 'Absendeadresse einstellen',
+       'configuration_facteur' => 'Briefträger',
+       'configuration_mailer' => 'Konfiguration des Mailers',
+       'configuration_smtp' => 'Auswahl der Versandmethode',
+       'configuration_smtp_descriptif' => 'Im Zweifel hier die mail() Funktion von PHP eintragen.',
+       'corps_email_de_test' => 'Das ist ein Versandtest mit Sondärzeichen: Bär Größe Maß accentué',
+
+       // E
+       'email_test_envoye' => 'Die Testmail wurde fehlerfrei versand. Falls sie nicht richtig ankommt,
+                      bearbeiten sie ihre Serverkonfiguration oder kontaktieren sie den Administrator.',
+       'erreur' => 'Fehler',
+       'erreur_dans_log' => ' : consultez le fichier log pour plus de détails', # NEW
+       'erreur_generale' => 'Mehrere Konfigurationsfehler. Bitte Inhalt des Formulars korrigieren.',
+       'erreur_invalid_host' => 'Servername inkorrekt',
+       'erreur_invalid_port' => 'Portnummer inkorrekt',
+
+       // F
+       'facteur_adresse_envoi_email' => 'E-Mail :',
+       'facteur_adresse_envoi_nom' => 'Name:',
+       'facteur_bcc' => 'Copie Cachée (BCC) :', # NEW
+       'facteur_cc' => 'Copie (CC) :', # NEW
+       'facteur_copies' => 'Copies :', # NEW
+       'facteur_copies_descriptif' => 'Un email sera envoyé en copie aux adresses définies. Une seule adresse en copie et/ou une seule adresse en copie cachée.', # NEW
+       'facteur_filtre_accents' => 'Sonderzeichen in HTML-Entitäten umwandeln (z.B. für Hotmail).',
+       'facteur_filtre_css' => 'Stile zwischen <head> und </head> zu "inline" Stilen umwandeln, sinnvoll für Webmail die interne Stile externen vorzieht.',
+       'facteur_filtre_images' => 'Verlinkte Bilder in E-Mail einbetten',
+       'facteur_filtre_iso_8859' => 'Nach ISO-8859-1 umwandeln',
+       'facteur_filtres' => 'Filter',
+       'facteur_filtres_descriptif' => 'Beim Versand können mehrere Filter eingesetzt werden.',
+       'facteur_smtp_auth' => 'Autorisierung erforderlich:',
+       'facteur_smtp_auth_non' => 'nein',
+       'facteur_smtp_auth_oui' => 'ja',
+       'facteur_smtp_host' => 'Server:',
+       'facteur_smtp_password' => 'Passwort:',
+       'facteur_smtp_port' => 'Port:',
+       'facteur_smtp_secure' => 'Verschlüsselte Verbindung:',
+       'facteur_smtp_secure_non' => 'nein',
+       'facteur_smtp_secure_ssl' => 'SSL',
+       'facteur_smtp_secure_tls' => 'TLS',
+       'facteur_smtp_sender' => 'Fehlercodes (optional)',
+       'facteur_smtp_sender_descriptif' => 'Legt im Kopf der Mail die Empfängeradresse für Fehlermeldungen fest (bzw. den Return-Path), bestimmt ebenfalls die Absenderadresse bei Versand per SMTP.',
+       'facteur_smtp_username' => 'Benutzername:',
+
+       // N
+       'note_test_configuration' => 'Eine Mail wird an die Absendeadresse geschickt (oder an den Webmaster).',
+
+       // P
+       'personnaliser' => 'Individuelle Einstellungen',
+
+       // T
+       'tester' => 'Testen',
+       'tester_la_configuration' => 'Konfiguration testen',
+
+       // U
+       'utiliser_mail' => 'Funktion mail() von PHP verwenden',
+       'utiliser_reglages_site' => 'Einstellungen von SPIP verwenden: als Name wird die Bezeichnung der SPIP-Website verwendet und als Adresse die des Webmasters.',
+       'utiliser_smtp' => 'SMTP verwenden',
+
+       // V
+       'valider' => ' OK ',
+       'version_html' => 'HTML-Version.',
+       'version_texte' => 'Textversion.'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/facteur_en.php b/www/plugins/facteur/lang/facteur_en.php
new file mode 100755 (executable)
index 0000000..2358b1f
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/facteur?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'Z' => 'ZZzZZzzz',
+
+       // C
+       'config_info_enregistree' => 'Postman\'s configuration is now saved',
+       'configuration_adresse_envoi' => 'Sender\'s address configuration',
+       'configuration_facteur' => 'Postman',
+       'configuration_mailer' => 'Mailer\'s configuration',
+       'configuration_smtp' => 'Choose your mailer',
+       'configuration_smtp_descriptif' => 'If you\'re not sure about the settings, leave them set to "PHP mail".',
+       'corps_email_de_test' => 'This is a test email',
+
+       // E
+       'email_test_envoye' => 'The test email was successfully sent. If you do not receive it correctly, check the configuration of your server or contact a server administrator.',
+       'erreur' => 'Error',
+       'erreur_dans_log' => ': check the log file for more details',
+       'erreur_generale' => 'There are one or more configuration errors. Please check the contents of the form.',
+       'erreur_invalid_host' => 'This host name is not valid',
+       'erreur_invalid_port' => 'This port number is not valid',
+
+       // F
+       'facteur_adresse_envoi_email' => 'Email:',
+       'facteur_adresse_envoi_nom' => 'Name:',
+       'facteur_bcc' => 'Blind Carbon Copy (BCC):',
+       'facteur_cc' => 'Carbon Copy (CC):',
+       'facteur_copies' => 'Copies:',
+       'facteur_copies_descriptif' => 'An email will be sent to specified adresses. One Carbon Copy and/or one Blind Carbon Copy.',
+       'facteur_filtre_accents' => 'Transform accents into their html entities (useful for Hotmail).',
+       'facteur_filtre_css' => 'Transform styles present between &lt;head&gt; and &lt;/head&gt; into inline styles, useful for webmails because inline styles overwrite external styles.',
+       'facteur_filtre_images' => 'Embed images referenced in emails',
+       'facteur_filtre_iso_8859' => 'Convert to ISO-8859-1',
+       'facteur_filtres' => 'Filters',
+       'facteur_filtres_descriptif' => 'Some filters can be applied before sending an email.',
+       'facteur_smtp_auth' => 'Requires authentication:',
+       'facteur_smtp_auth_non' => 'no',
+       'facteur_smtp_auth_oui' => 'yes',
+       'facteur_smtp_host' => 'Host:',
+       'facteur_smtp_password' => 'Password:',
+       'facteur_smtp_port' => 'Port:',
+       'facteur_smtp_secure' => 'Secure:',
+       'facteur_smtp_secure_non' => 'no',
+       'facteur_smtp_secure_ssl' => 'SSL',
+       'facteur_smtp_secure_tls' => 'TLS',
+       'facteur_smtp_sender' => 'Return-Path (optional)',
+       'facteur_smtp_sender_descriptif' => 'Define the Return-Path in the mail header, useful for error feedback, also in SMTP mode it defines the sender\'s email.',
+       'facteur_smtp_username' => 'Username:',
+
+       // N
+       'note_test_configuration' => 'A test email will be sent to the "sender".',
+
+       // P
+       'personnaliser' => 'Customize',
+
+       // T
+       'tester' => 'Test',
+       'tester_la_configuration' => 'Test the config',
+
+       // U
+       'utiliser_mail' => 'Use mail function from PHP',
+       'utiliser_reglages_site' => 'Use the site\'s settings: the email address is the webmaster\'s one and the name of the website is the name of the sender',
+       'utiliser_smtp' => 'Use SMTP',
+
+       // V
+       'valider' => 'Submit',
+       'version_html' => 'HTML version.',
+       'version_texte' => 'Text version.'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/facteur_es.php b/www/plugins/facteur/lang/facteur_es.php
new file mode 100644 (file)
index 0000000..4f7f936
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/facteur?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'Z' => 'ZZzZZzzz',
+
+       // C
+       'config_info_enregistree' => 'La configuración del factor se ha registrado correctamente',
+       'configuration_adresse_envoi' => 'Configuración de la dirección de envío',
+       'configuration_facteur' => 'Factor',
+       'configuration_mailer' => 'Configuración del "mailer"',
+       'configuration_smtp' => 'Elección del método de envío del correo electrónico',
+       'configuration_smtp_descriptif' => 'Si no está seguro, elija la función de correo electrónico de PHP.',
+       'corps_email_de_test' => 'Éste es un mensaje de prueba acentuado',
+
+       // E
+       'email_test_envoye' => 'El correo electrónico de prueba se ha enviado correctamente. Si lo recibe, verifique la configuración de su servidor o contacte con un administrador del servicio. ',
+       'erreur' => 'Error',
+       'erreur_dans_log' => ': consulte el archivo de registro para obtener más detalles',
+       'erreur_generale' => 'Hay uno o más errores de configuración. Por favor, compruebe el contenido del formulario. ',
+       'erreur_invalid_host' => 'Este nombre de host es incorrecto',
+       'erreur_invalid_port' => 'Este número de puerto es incorrecto',
+
+       // F
+       'facteur_adresse_envoi_email' => 'Correo electrónico:',
+       'facteur_adresse_envoi_nom' => 'Nombre:',
+       'facteur_bcc' => 'Copia Oculta (CCO):',
+       'facteur_cc' => 'Copia (CC) :',
+       'facteur_copies' => 'Copias:',
+       'facteur_copies_descriptif' => 'Un correo electrónico será enviado en copia a las direcciones definidas. Una sola dirección en copia y/o una sola dirección en copia oculta.',
+       'facteur_filtre_accents' => 'Transformar los acentos en su versión html (especialmente útil para Hotmail).',
+       'facteur_filtre_css' => 'Transformar los estilos contenidos entre <head> y </head> en estilos en línea, útil para los webmails porque los estilos lineales tienen prioridad sobre los estilos externos. ',
+       'facteur_filtre_images' => 'Incorporar las imágenes de referencia en los correos electrónicos',
+       'facteur_filtre_iso_8859' => 'Convertir en ISO-8859-1',
+       'facteur_filtres' => 'Filtros',
+       'facteur_filtres_descriptif' => 'Los filtros pueden aplicarse en los correos electrónicos en el momento del envío.',
+       'facteur_smtp_auth' => 'Requiere autentificación:',
+       'facteur_smtp_auth_non' => 'no',
+       'facteur_smtp_auth_oui' => 'sí',
+       'facteur_smtp_host' => 'Host:',
+       'facteur_smtp_password' => 'Contraseña:',
+       'facteur_smtp_port' => 'Puerto:',
+       'facteur_smtp_secure' => 'Conexión segura:',
+       'facteur_smtp_secure_non' => 'no',
+       'facteur_smtp_secure_ssl' => 'SSL',
+       'facteur_smtp_secure_tls' => 'TLS',
+       'facteur_smtp_sender' => 'Rebote de errores (opcional)',
+       'facteur_smtp_sender_descriptif' => 'Indica en el encabezado del correo electrónico la dirección de correo electrónico de rebote de errores (o "Return-Path"), y en caso de un envío a través del método SMTP indica, también, la dirección del remitente.',
+       'facteur_smtp_username' => 'Nombre de usuario:',
+
+       // N
+       'note_test_configuration' => 'Un correo electrónico se enviará a la dirección de envío definida (o aquélla del webmaster).',
+
+       // P
+       'personnaliser' => 'Personalizar esta configuración',
+
+       // T
+       'tester' => 'Testar',
+       'tester_la_configuration' => 'Testar la configuración',
+
+       // U
+       'utiliser_mail' => 'Utilizar la función de correo electrónico de PHP',
+       'utiliser_reglages_site' => 'Utilizar la configuración del sitio SPIP: el nombre mostrado será el nombre del sitio SPIP y la dirección de correo electrónico será la del webmaster',
+       'utiliser_smtp' => 'Utilizar SMTP',
+
+       // V
+       'valider' => 'Validar',
+       'version_html' => 'Versión HTML.',
+       'version_texte' => 'Versión texto.'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/facteur_fr.php b/www/plugins/facteur/lang/facteur_fr.php
new file mode 100755 (executable)
index 0000000..c085653
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/facteur/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'Z' => 'ZZzZZzzz',
+
+       // C
+       'config_info_enregistree' => 'La configuration du facteur a bien été enregistrée',
+       'configuration_adresse_envoi' => 'Configuration de l\'adresse d\'envoi',
+       'configuration_facteur' => 'Facteur',
+       'configuration_mailer' => 'Configuration du mailer',
+       'configuration_smtp' => 'Choix de la méthode d\'envoi de mail',
+       'configuration_smtp_descriptif' => 'Si vous n\'êtes pas sûrs, choisissez la fonction mail de PHP.',
+       'corps_email_de_test' => 'Ceci est un email de test accentué',
+
+       // E
+       'email_test_envoye' => 'L\'email de test a correctement été envoyé. Si vous ne le recevez pas correctement, vérifiez la configuration de votre serveur ou contactez un administrateur du serveur.',
+       'erreur' => 'Erreur',
+       'erreur_dans_log' => ' : consultez le fichier log pour plus de détails',
+       'erreur_generale' => 'Il y a une ou plusieurs erreurs de configuration. Veuillez vérifier le contenu du formulaire.',
+       'erreur_invalid_host' => 'Ce nom d\'hôte n\'est pas correct',
+       'erreur_invalid_port' => 'Ce numéro de port n\'est pas correct',
+
+       // F
+       'facteur_adresse_envoi_email' => 'Email :',
+       'facteur_adresse_envoi_nom' => 'Nom :',
+       'facteur_bcc' => 'Copie Cachée (BCC) :',
+       'facteur_cc' => 'Copie (CC) :',
+       'facteur_copies' => 'Copies :',
+       'facteur_copies_descriptif' => 'Un email sera envoyé en copie aux adresses définies. Une seule adresse en copie et/ou une seule adresse en copie cachée.',
+       'facteur_filtre_accents' => 'Transformer les accents en leur entités html (utile pour Hotmail notamment).',
+       'facteur_filtre_css' => 'Transformer les styles contenus entre <head> et </head> en des styles "en ligne", utile pour les webmails car les styles en ligne ont la priorité sur les styles externes.',
+       'facteur_filtre_images' => 'Embarquer les images référencées dans les emails',
+       'facteur_filtre_iso_8859' => 'Convertir en ISO-8859-1',
+       'facteur_filtres' => 'Filtres',
+       'facteur_filtres_descriptif' => 'Des filtres peuvent être appliqués aux emails au moment de l\'envoi.',
+       'facteur_smtp_auth' => 'Requiert une authentification :',
+       'facteur_smtp_auth_non' => 'non',
+       'facteur_smtp_auth_oui' => 'oui',
+       'facteur_smtp_host' => 'Hôte :',
+       'facteur_smtp_password' => 'Mot de passe :',
+       'facteur_smtp_port' => 'Port :',
+       'facteur_smtp_secure' => 'Connexion sécurisée :',
+       'facteur_smtp_secure_non' => 'non',
+       'facteur_smtp_secure_ssl' => 'SSL',
+       'facteur_smtp_secure_tls' => 'TLS',
+       'facteur_smtp_sender' => 'Retour des erreurs (optionnel)',
+       'facteur_smtp_sender_descriptif' => 'Définit dans l\'entête du mail l\'adresse email de retour des erreurs (ou Return-Path), et lors d\'un envoi via la méthode SMTP cela définit aussi l\'adresse de l\'envoyeur.',
+       'facteur_smtp_username' => 'Nom d\'utilisateur :',
+
+       // N
+       'note_test_configuration' => 'Un email sera envoyé à l\'adresse d\'envoi définie (ou celle du webmaster).',
+
+       // P
+       'personnaliser' => 'Personnaliser ces réglages',
+
+       // T
+       'tester' => 'Tester',
+       'tester_la_configuration' => 'Tester la configuration',
+
+       // U
+       'utiliser_mail' => 'Utiliser la fonction mail de PHP',
+       'utiliser_reglages_site' => 'Utiliser les réglages du site SPIP : le nom affiché sera le nom du site SPIP et l\'adresse email sera celle du webmaster',
+       'utiliser_smtp' => 'Utiliser SMTP',
+
+       // V
+       'valider' => 'Valider',
+       'version_html' => 'Version HTML.',
+       'version_texte' => 'Version texte.'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/facteur_sk.php b/www/plugins/facteur/lang/facteur_sk.php
new file mode 100644 (file)
index 0000000..b292859
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/facteur?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'Z' => 'ZZzZZzzz',
+
+       // C
+       'config_info_enregistree' => 'Nastavenia Poštára sa uložili správne',
+       'configuration_adresse_envoi' => 'Nastavenie adresy odosielateľa',
+       'configuration_facteur' => 'Poštár',
+       'configuration_mailer' => 'Nastavenia Poštára',
+       'configuration_smtp' => 'Výber spôsobu odoslania e-mailu',
+       'configuration_smtp_descriptif' => 'Ak si nie ste istý, zvoľte si funkciu mail jazyka PHP.',
+       'corps_email_de_test' => 'Toto je testovací e-mail s diakritikou',
+
+       // E
+       'email_test_envoye' => 'Testovací e-mail bol úspešne odoslaný. Ak ho nedostanete, skontrolujte nastavenia svojho servera alebo sa obráťte na administrátora servera.',
+       'erreur' => 'Chyba',
+       'erreur_dans_log' => ' : viac podrobností nájdete v súbore log',
+       'erreur_generale' => 'V nastaveniach je jedna alebo viac chýb. Prosím, skontrolujte obsah formulára.',
+       'erreur_invalid_host' => 'Názov servera nie je správny',
+       'erreur_invalid_port' => 'Toto číslo portu nie je správne',
+
+       // F
+       'facteur_adresse_envoi_email' => 'E-mail:',
+       'facteur_adresse_envoi_nom' => '(Obchodné) meno:',
+       'facteur_bcc' => 'Skrytá kópia (BCC):',
+       'facteur_cc' => 'Kópia (CC):',
+       'facteur_copies' => 'Kópie:',
+       'facteur_copies_descriptif' => 'Kópia e-mailu sa pošle na zadané adresy. Na jednu adresu bude odoslaná bežná kópia a/lebo skrytá kópia.',
+       'facteur_filtre_accents' => 'Diakritiku meniť na entity html (užitočné najmä pre Hotmail).',
+       'facteur_filtre_css' => 'Zmeniť štýly medzi <head> a </head> na "in-line" štýly, užitočné pre webmaily, lebo in-line štýly majú prednosť pred externými.',
+       'facteur_filtre_images' => 'Do e-mailov pridávať obrázky, na ktoré sa v nich odkazuje',
+       'facteur_filtre_iso_8859' => 'Zmeniť na ISO-8859-1',
+       'facteur_filtres' => 'Filtre',
+       'facteur_filtres_descriptif' => 'Pri posielaní sa na e-maily môžu použiť filtre.',
+       'facteur_smtp_auth' => 'Vyžaduje sa prihlásenie:',
+       'facteur_smtp_auth_non' => 'nie',
+       'facteur_smtp_auth_oui' => 'áno',
+       'facteur_smtp_host' => 'Host:',
+       'facteur_smtp_password' => 'Heslo:',
+       'facteur_smtp_port' => 'Port:',
+       'facteur_smtp_secure' => 'Zabezpečené pripojenie:',
+       'facteur_smtp_secure_non' => 'nie',
+       'facteur_smtp_secure_ssl' => 'SSL',
+       'facteur_smtp_secure_tls' => 'TLS',
+       'facteur_smtp_sender' => 'Vypísanie chýb (nepovinné)',
+       'facteur_smtp_sender_descriptif' => 'Zadané v hlavičke návratnej e-mailovej adresy pri chybe (alebo Return-Path) a pri jej odoslaní metódou SMTP je aj adresou odosielateľa.',
+       'facteur_smtp_username' => 'Používateľské meno:',
+
+       // N
+       'note_test_configuration' => 'E-mail bude odoslaný na uvedenú adresu (alebo webmasterovi).',
+
+       // P
+       'personnaliser' => 'Prispôsobiť si tieto nastavenia',
+
+       // T
+       'tester' => 'Otestovať',
+       'tester_la_configuration' => 'Otestovať nastavenia',
+
+       // U
+       'utiliser_mail' => 'Používať funkciu mail z PHP',
+       'utiliser_reglages_site' => 'Použiť nastavenia stránky v SPIPe: zobrazovaný názov je názov stránky a e-mailová adresa je e-mail webmastera',
+       'utiliser_smtp' => 'Používať SMTP',
+
+       // V
+       'valider' => 'Potvrdiť',
+       'version_html' => 'HTML verzia.',
+       'version_texte' => 'Textová verzia.'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/paquet-facteur.xml b/www/plugins/facteur/lang/paquet-facteur.xml
new file mode 100644 (file)
index 0000000..17c6723
--- /dev/null
@@ -0,0 +1,10 @@
+<traduction module="paquet-facteur" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/facteur/trunk/lang/" reference="fr">
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-facteur?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-facteur?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/facteur/lang/paquet-facteur_en.php b/www/plugins/facteur/lang/paquet-facteur_en.php
new file mode 100644 (file)
index 0000000..b354c28
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-facteur?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // F
+       'facteur_description' => 'Postman delivers emails in HTML, text or mixed format; via SMTP or not',
+       'facteur_nom' => 'Postman',
+       'facteur_slogan' => 'He delivers emails'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/paquet-facteur_es.php b/www/plugins/facteur/lang/paquet-facteur_es.php
new file mode 100644 (file)
index 0000000..ffa1ba1
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-facteur?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // F
+       'facteur_description' => '"Cartero" se ocupa de la distribución de correos electrónicos en formato HTML, texto o mixto; vía SMTP o no',
+       'facteur_nom' => 'Cartero',
+       'facteur_slogan' => 'Distribuye sus correos electrónicos'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/paquet-facteur_fr.php b/www/plugins/facteur/lang/paquet-facteur_fr.php
new file mode 100644 (file)
index 0000000..332b6a3
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/facteur/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // F
+       'facteur_description' => 'Facteur s\'occupe de la distribution des courriels au format HTML, texte ou mixte ; via SMTP ou non',
+       'facteur_nom' => 'Facteur',
+       'facteur_slogan' => 'Il distribue vos courriels'
+);
+
+?>
diff --git a/www/plugins/facteur/lang/paquet-facteur_sk.php b/www/plugins/facteur/lang/paquet-facteur_sk.php
new file mode 100644 (file)
index 0000000..de98cc7
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-facteur?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // F
+       'facteur_description' => 'Poštár slúži na doručovanie e-mailov vo formáte HTML, v textovej alebo v zmiešanej podobe či už cez SMTP, alebo nie',
+       'facteur_nom' => 'Poštár',
+       'facteur_slogan' => 'Posiela vašu poštu'
+);
+
+?>
diff --git a/www/plugins/facteur/paquet.xml b/www/plugins/facteur/paquet.xml
new file mode 100644 (file)
index 0000000..bf76ce6
--- /dev/null
@@ -0,0 +1,21 @@
+<paquet\r
+       prefix="facteur"\r
+       categorie="communication"\r
+       version="2.4.5"\r
+       etat="stable"\r
+       compatibilite="[3.0.0;3.0.*]"\r
+       logo="prive/themes/spip/images/facteur-32.png"\r
+       schema="1.1"\r
+       documentation="http://www.spip-contrib.net/Facteur"\r
+>      \r
+       \r
+       <nom>Facteur</nom>\r
+       <!-- Il distribue votre courrier -->\r
+       \r
+       <auteur>Collectif SPIP</auteur>\r
+       \r
+       <pipeline nom="facteur_pre_envoi" action="" />\r
+       <pipeline nom="ieconfig_metas" inclure="facteur_ieconfig_metas.php" />\r
+       \r
+       <menu nom="configurer_facteur" titre="facteur:configuration_facteur" parent="menu_configuration" icone="images/facteur-16.png" />\r
+</paquet>\r
diff --git a/www/plugins/facteur/phpmailer-php5/LICENSE b/www/plugins/facteur/phpmailer-php5/LICENSE
new file mode 100755 (executable)
index 0000000..03851a3
--- /dev/null
@@ -0,0 +1,504 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE\r
+                      Version 2.1, February 1999\r
+\r
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.\r
+     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ Everyone is permitted to copy and distribute verbatim copies\r
+ of this license document, but changing it is not allowed.\r
+\r
+[This is the first released version of the Lesser GPL.  It also counts\r
+ as the successor of the GNU Library Public License, version 2, hence\r
+ the version number 2.1.]\r
+\r
+                           Preamble\r
+\r
+  The licenses for most software are designed to take away your\r
+freedom to share and change it.  By contrast, the GNU General Public\r
+Licenses are intended to guarantee your freedom to share and change\r
+free software--to make sure the software is free for all its users.\r
+\r
+  This license, the Lesser General Public License, applies to some\r
+specially designated software packages--typically libraries--of the\r
+Free Software Foundation and other authors who decide to use it.  You\r
+can use it too, but we suggest you first think carefully about whether\r
+this license or the ordinary General Public License is the better\r
+strategy to use in any particular case, based on the explanations below.\r
+\r
+  When we speak of free software, we are referring to freedom of use,\r
+not price.  Our General Public Licenses are designed to make sure that\r
+you have the freedom to distribute copies of free software (and charge\r
+for this service if you wish); that you receive source code or can get\r
+it if you want it; that you can change the software and use pieces of\r
+it in new free programs; and that you are informed that you can do\r
+these things.\r
+\r
+  To protect your rights, we need to make restrictions that forbid\r
+distributors to deny you these rights or to ask you to surrender these\r
+rights.  These restrictions translate to certain responsibilities for\r
+you if you distribute copies of the library or if you modify it.\r
+\r
+  For example, if you distribute copies of the library, whether gratis\r
+or for a fee, you must give the recipients all the rights that we gave\r
+you.  You must make sure that they, too, receive or can get the source\r
+code.  If you link other code with the library, you must provide\r
+complete object files to the recipients, so that they can relink them\r
+with the library after making changes to the library and recompiling\r
+it.  And you must show them these terms so they know their rights.\r
+\r
+  We protect your rights with a two-step method: (1) we copyright the\r
+library, and (2) we offer you this license, which gives you legal\r
+permission to copy, distribute and/or modify the library.\r
+\r
+  To protect each distributor, we want to make it very clear that\r
+there is no warranty for the free library.  Also, if the library is\r
+modified by someone else and passed on, the recipients should know\r
+that what they have is not the original version, so that the original\r
+author's reputation will not be affected by problems that might be\r
+introduced by others.\r
+\r
+  Finally, software patents pose a constant threat to the existence of\r
+any free program.  We wish to make sure that a company cannot\r
+effectively restrict the users of a free program by obtaining a\r
+restrictive license from a patent holder.  Therefore, we insist that\r
+any patent license obtained for a version of the library must be\r
+consistent with the full freedom of use specified in this license.\r
+\r
+  Most GNU software, including some libraries, is covered by the\r
+ordinary GNU General Public License.  This license, the GNU Lesser\r
+General Public License, applies to certain designated libraries, and\r
+is quite different from the ordinary General Public License.  We use\r
+this license for certain libraries in order to permit linking those\r
+libraries into non-free programs.\r
+\r
+  When a program is linked with a library, whether statically or using\r
+a shared library, the combination of the two is legally speaking a\r
+combined work, a derivative of the original library.  The ordinary\r
+General Public License therefore permits such linking only if the\r
+entire combination fits its criteria of freedom.  The Lesser General\r
+Public License permits more lax criteria for linking other code with\r
+the library.\r
+\r
+  We call this license the "Lesser" General Public License because it\r
+does Less to protect the user's freedom than the ordinary General\r
+Public License.  It also provides other free software developers Less\r
+of an advantage over competing non-free programs.  These disadvantages\r
+are the reason we use the ordinary General Public License for many\r
+libraries.  However, the Lesser license provides advantages in certain\r
+special circumstances.\r
+\r
+  For example, on rare occasions, there may be a special need to\r
+encourage the widest possible use of a certain library, so that it becomes\r
+a de-facto standard.  To achieve this, non-free programs must be\r
+allowed to use the library.  A more frequent case is that a free\r
+library does the same job as widely used non-free libraries.  In this\r
+case, there is little to gain by limiting the free library to free\r
+software only, so we use the Lesser General Public License.\r
+\r
+  In other cases, permission to use a particular library in non-free\r
+programs enables a greater number of people to use a large body of\r
+free software.  For example, permission to use the GNU C Library in\r
+non-free programs enables many more people to use the whole GNU\r
+operating system, as well as its variant, the GNU/Linux operating\r
+system.\r
+\r
+  Although the Lesser General Public License is Less protective of the\r
+users' freedom, it does ensure that the user of a program that is\r
+linked with the Library has the freedom and the wherewithal to run\r
+that program using a modified version of the Library.\r
+\r
+  The precise terms and conditions for copying, distribution and\r
+modification follow.  Pay close attention to the difference between a\r
+"work based on the library" and a "work that uses the library".  The\r
+former contains code derived from the library, whereas the latter must\r
+be combined with the library in order to run.\r
+\r
+                 GNU LESSER GENERAL PUBLIC LICENSE\r
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\r
+\r
+  0. This License Agreement applies to any software library or other\r
+program which contains a notice placed by the copyright holder or\r
+other authorized party saying it may be distributed under the terms of\r
+this Lesser General Public License (also called "this License").\r
+Each licensee is addressed as "you".\r
+\r
+  A "library" means a collection of software functions and/or data\r
+prepared so as to be conveniently linked with application programs\r
+(which use some of those functions and data) to form executables.\r
+\r
+  The "Library", below, refers to any such software library or work\r
+which has been distributed under these terms.  A "work based on the\r
+Library" means either the Library or any derivative work under\r
+copyright law: that is to say, a work containing the Library or a\r
+portion of it, either verbatim or with modifications and/or translated\r
+straightforwardly into another language.  (Hereinafter, translation is\r
+included without limitation in the term "modification".)\r
+\r
+  "Source code" for a work means the preferred form of the work for\r
+making modifications to it.  For a library, complete source code means\r
+all the source code for all modules it contains, plus any associated\r
+interface definition files, plus the scripts used to control compilation\r
+and installation of the library.\r
+\r
+  Activities other than copying, distribution and modification are not\r
+covered by this License; they are outside its scope.  The act of\r
+running a program using the Library is not restricted, and output from\r
+such a program is covered only if its contents constitute a work based\r
+on the Library (independent of the use of the Library in a tool for\r
+writing it).  Whether that is true depends on what the Library does\r
+and what the program that uses the Library does.\r
+  \r
+  1. You may copy and distribute verbatim copies of the Library's\r
+complete source code as you receive it, in any medium, provided that\r
+you conspicuously and appropriately publish on each copy an\r
+appropriate copyright notice and disclaimer of warranty; keep intact\r
+all the notices that refer to this License and to the absence of any\r
+warranty; and distribute a copy of this License along with the\r
+Library.\r
+\r
+  You may charge a fee for the physical act of transferring a copy,\r
+and you may at your option offer warranty protection in exchange for a\r
+fee.\r
+\r
+  2. You may modify your copy or copies of the Library or any portion\r
+of it, thus forming a work based on the Library, and copy and\r
+distribute such modifications or work under the terms of Section 1\r
+above, provided that you also meet all of these conditions:\r
+\r
+    a) The modified work must itself be a software library.\r
+\r
+    b) You must cause the files modified to carry prominent notices\r
+    stating that you changed the files and the date of any change.\r
+\r
+    c) You must cause the whole of the work to be licensed at no\r
+    charge to all third parties under the terms of this License.\r
+\r
+    d) If a facility in the modified Library refers to a function or a\r
+    table of data to be supplied by an application program that uses\r
+    the facility, other than as an argument passed when the facility\r
+    is invoked, then you must make a good faith effort to ensure that,\r
+    in the event an application does not supply such function or\r
+    table, the facility still operates, and performs whatever part of\r
+    its purpose remains meaningful.\r
+\r
+    (For example, a function in a library to compute square roots has\r
+    a purpose that is entirely well-defined independent of the\r
+    application.  Therefore, Subsection 2d requires that any\r
+    application-supplied function or table used by this function must\r
+    be optional: if the application does not supply it, the square\r
+    root function must still compute square roots.)\r
+\r
+These requirements apply to the modified work as a whole.  If\r
+identifiable sections of that work are not derived from the Library,\r
+and can be reasonably considered independent and separate works in\r
+themselves, then this License, and its terms, do not apply to those\r
+sections when you distribute them as separate works.  But when you\r
+distribute the same sections as part of a whole which is a work based\r
+on the Library, the distribution of the whole must be on the terms of\r
+this License, whose permissions for other licensees extend to the\r
+entire whole, and thus to each and every part regardless of who wrote\r
+it.\r
+\r
+Thus, it is not the intent of this section to claim rights or contest\r
+your rights to work written entirely by you; rather, the intent is to\r
+exercise the right to control the distribution of derivative or\r
+collective works based on the Library.\r
+\r
+In addition, mere aggregation of another work not based on the Library\r
+with the Library (or with a work based on the Library) on a volume of\r
+a storage or distribution medium does not bring the other work under\r
+the scope of this License.\r
+\r
+  3. You may opt to apply the terms of the ordinary GNU General Public\r
+License instead of this License to a given copy of the Library.  To do\r
+this, you must alter all the notices that refer to this License, so\r
+that they refer to the ordinary GNU General Public License, version 2,\r
+instead of to this License.  (If a newer version than version 2 of the\r
+ordinary GNU General Public License has appeared, then you can specify\r
+that version instead if you wish.)  Do not make any other change in\r
+these notices.\r
+\r
+  Once this change is made in a given copy, it is irreversible for\r
+that copy, so the ordinary GNU General Public License applies to all\r
+subsequent copies and derivative works made from that copy.\r
+\r
+  This option is useful when you wish to copy part of the code of\r
+the Library into a program that is not a library.\r
+\r
+  4. You may copy and distribute the Library (or a portion or\r
+derivative of it, under Section 2) in object code or executable form\r
+under the terms of Sections 1 and 2 above provided that you accompany\r
+it with the complete corresponding machine-readable source code, which\r
+must be distributed under the terms of Sections 1 and 2 above on a\r
+medium customarily used for software interchange.\r
+\r
+  If distribution of object code is made by offering access to copy\r
+from a designated place, then offering equivalent access to copy the\r
+source code from the same place satisfies the requirement to\r
+distribute the source code, even though third parties are not\r
+compelled to copy the source along with the object code.\r
+\r
+  5. A program that contains no derivative of any portion of the\r
+Library, but is designed to work with the Library by being compiled or\r
+linked with it, is called a "work that uses the Library".  Such a\r
+work, in isolation, is not a derivative work of the Library, and\r
+therefore falls outside the scope of this License.\r
+\r
+  However, linking a "work that uses the Library" with the Library\r
+creates an executable that is a derivative of the Library (because it\r
+contains portions of the Library), rather than a "work that uses the\r
+library".  The executable is therefore covered by this License.\r
+Section 6 states terms for distribution of such executables.\r
+\r
+  When a "work that uses the Library" uses material from a header file\r
+that is part of the Library, the object code for the work may be a\r
+derivative work of the Library even though the source code is not.\r
+Whether this is true is especially significant if the work can be\r
+linked without the Library, or if the work is itself a library.  The\r
+threshold for this to be true is not precisely defined by law.\r
+\r
+  If such an object file uses only numerical parameters, data\r
+structure layouts and accessors, and small macros and small inline\r
+functions (ten lines or less in length), then the use of the object\r
+file is unrestricted, regardless of whether it is legally a derivative\r
+work.  (Executables containing this object code plus portions of the\r
+Library will still fall under Section 6.)\r
+\r
+  Otherwise, if the work is a derivative of the Library, you may\r
+distribute the object code for the work under the terms of Section 6.\r
+Any executables containing that work also fall under Section 6,\r
+whether or not they are linked directly with the Library itself.\r
+\r
+  6. As an exception to the Sections above, you may also combine or\r
+link a "work that uses the Library" with the Library to produce a\r
+work containing portions of the Library, and distribute that work\r
+under terms of your choice, provided that the terms permit\r
+modification of the work for the customer's own use and reverse\r
+engineering for debugging such modifications.\r
+\r
+  You must give prominent notice with each copy of the work that the\r
+Library is used in it and that the Library and its use are covered by\r
+this License.  You must supply a copy of this License.  If the work\r
+during execution displays copyright notices, you must include the\r
+copyright notice for the Library among them, as well as a reference\r
+directing the user to the copy of this License.  Also, you must do one\r
+of these things:\r
+\r
+    a) Accompany the work with the complete corresponding\r
+    machine-readable source code for the Library including whatever\r
+    changes were used in the work (which must be distributed under\r
+    Sections 1 and 2 above); and, if the work is an executable linked\r
+    with the Library, with the complete machine-readable "work that\r
+    uses the Library", as object code and/or source code, so that the\r
+    user can modify the Library and then relink to produce a modified\r
+    executable containing the modified Library.  (It is understood\r
+    that the user who changes the contents of definitions files in the\r
+    Library will not necessarily be able to recompile the application\r
+    to use the modified definitions.)\r
+\r
+    b) Use a suitable shared library mechanism for linking with the\r
+    Library.  A suitable mechanism is one that (1) uses at run time a\r
+    copy of the library already present on the user's computer system,\r
+    rather than copying library functions into the executable, and (2)\r
+    will operate properly with a modified version of the library, if\r
+    the user installs one, as long as the modified version is\r
+    interface-compatible with the version that the work was made with.\r
+\r
+    c) Accompany the work with a written offer, valid for at\r
+    least three years, to give the same user the materials\r
+    specified in Subsection 6a, above, for a charge no more\r
+    than the cost of performing this distribution.\r
+\r
+    d) If distribution of the work is made by offering access to copy\r
+    from a designated place, offer equivalent access to copy the above\r
+    specified materials from the same place.\r
+\r
+    e) Verify that the user has already received a copy of these\r
+    materials or that you have already sent this user a copy.\r
+\r
+  For an executable, the required form of the "work that uses the\r
+Library" must include any data and utility programs needed for\r
+reproducing the executable from it.  However, as a special exception,\r
+the materials to be distributed need not include anything that is\r
+normally distributed (in either source or binary form) with the major\r
+components (compiler, kernel, and so on) of the operating system on\r
+which the executable runs, unless that component itself accompanies\r
+the executable.\r
+\r
+  It may happen that this requirement contradicts the license\r
+restrictions of other proprietary libraries that do not normally\r
+accompany the operating system.  Such a contradiction means you cannot\r
+use both them and the Library together in an executable that you\r
+distribute.\r
+\r
+  7. You may place library facilities that are a work based on the\r
+Library side-by-side in a single library together with other library\r
+facilities not covered by this License, and distribute such a combined\r
+library, provided that the separate distribution of the work based on\r
+the Library and of the other library facilities is otherwise\r
+permitted, and provided that you do these two things:\r
+\r
+    a) Accompany the combined library with a copy of the same work\r
+    based on the Library, uncombined with any other library\r
+    facilities.  This must be distributed under the terms of the\r
+    Sections above.\r
+\r
+    b) Give prominent notice with the combined library of the fact\r
+    that part of it is a work based on the Library, and explaining\r
+    where to find the accompanying uncombined form of the same work.\r
+\r
+  8. You may not copy, modify, sublicense, link with, or distribute\r
+the Library except as expressly provided under this License.  Any\r
+attempt otherwise to copy, modify, sublicense, link with, or\r
+distribute the Library is void, and will automatically terminate your\r
+rights under this License.  However, parties who have received copies,\r
+or rights, from you under this License will not have their licenses\r
+terminated so long as such parties remain in full compliance.\r
+\r
+  9. You are not required to accept this License, since you have not\r
+signed it.  However, nothing else grants you permission to modify or\r
+distribute the Library or its derivative works.  These actions are\r
+prohibited by law if you do not accept this License.  Therefore, by\r
+modifying or distributing the Library (or any work based on the\r
+Library), you indicate your acceptance of this License to do so, and\r
+all its terms and conditions for copying, distributing or modifying\r
+the Library or works based on it.\r
+\r
+  10. Each time you redistribute the Library (or any work based on the\r
+Library), the recipient automatically receives a license from the\r
+original licensor to copy, distribute, link with or modify the Library\r
+subject to these terms and conditions.  You may not impose any further\r
+restrictions on the recipients' exercise of the rights granted herein.\r
+You are not responsible for enforcing compliance by third parties with\r
+this License.\r
+\r
+  11. If, as a consequence of a court judgment or allegation of patent\r
+infringement or for any other reason (not limited to patent issues),\r
+conditions are imposed on you (whether by court order, agreement or\r
+otherwise) that contradict the conditions of this License, they do not\r
+excuse you from the conditions of this License.  If you cannot\r
+distribute so as to satisfy simultaneously your obligations under this\r
+License and any other pertinent obligations, then as a consequence you\r
+may not distribute the Library at all.  For example, if a patent\r
+license would not permit royalty-free redistribution of the Library by\r
+all those who receive copies directly or indirectly through you, then\r
+the only way you could satisfy both it and this License would be to\r
+refrain entirely from distribution of the Library.\r
+\r
+If any portion of this section is held invalid or unenforceable under any\r
+particular circumstance, the balance of the section is intended to apply,\r
+and the section as a whole is intended to apply in other circumstances.\r
+\r
+It is not the purpose of this section to induce you to infringe any\r
+patents or other property right claims or to contest validity of any\r
+such claims; this section has the sole purpose of protecting the\r
+integrity of the free software distribution system which is\r
+implemented by public license practices.  Many people have made\r
+generous contributions to the wide range of software distributed\r
+through that system in reliance on consistent application of that\r
+system; it is up to the author/donor to decide if he or she is willing\r
+to distribute software through any other system and a licensee cannot\r
+impose that choice.\r
+\r
+This section is intended to make thoroughly clear what is believed to\r
+be a consequence of the rest of this License.\r
+\r
+  12. If the distribution and/or use of the Library is restricted in\r
+certain countries either by patents or by copyrighted interfaces, the\r
+original copyright holder who places the Library under this License may add\r
+an explicit geographical distribution limitation excluding those countries,\r
+so that distribution is permitted only in or among countries not thus\r
+excluded.  In such case, this License incorporates the limitation as if\r
+written in the body of this License.\r
+\r
+  13. The Free Software Foundation may publish revised and/or new\r
+versions of the Lesser General Public License from time to time.\r
+Such new versions will be similar in spirit to the present version,\r
+but may differ in detail to address new problems or concerns.\r
+\r
+Each version is given a distinguishing version number.  If the Library\r
+specifies a version number of this License which applies to it and\r
+"any later version", you have the option of following the terms and\r
+conditions either of that version or of any later version published by\r
+the Free Software Foundation.  If the Library does not specify a\r
+license version number, you may choose any version ever published by\r
+the Free Software Foundation.\r
+\r
+  14. If you wish to incorporate parts of the Library into other free\r
+programs whose distribution conditions are incompatible with these,\r
+write to the author to ask for permission.  For software which is\r
+copyrighted by the Free Software Foundation, write to the Free\r
+Software Foundation; we sometimes make exceptions for this.  Our\r
+decision will be guided by the two goals of preserving the free status\r
+of all derivatives of our free software and of promoting the sharing\r
+and reuse of software generally.\r
+\r
+                           NO WARRANTY\r
+\r
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\r
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\r
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\r
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY\r
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\r
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\r
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\r
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\r
+\r
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\r
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\r
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\r
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\r
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\r
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\r
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\r
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\r
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\r
+DAMAGES.\r
+\r
+                    END OF TERMS AND CONDITIONS\r
+\r
+           How to Apply These Terms to Your New Libraries\r
+\r
+  If you develop a new library, and you want it to be of the greatest\r
+possible use to the public, we recommend making it free software that\r
+everyone can redistribute and change.  You can do so by permitting\r
+redistribution under these terms (or, alternatively, under the terms of the\r
+ordinary General Public License).\r
+\r
+  To apply these terms, attach the following notices to the library.  It is\r
+safest to attach them to the start of each source file to most effectively\r
+convey the exclusion of warranty; and each file should have at least the\r
+"copyright" line and a pointer to where the full notice is found.\r
+\r
+    <one line to give the library's name and a brief idea of what it does.>\r
+    Copyright (C) <year>  <name of author>\r
+\r
+    This library is free software; you can redistribute it and/or\r
+    modify it under the terms of the GNU Lesser General Public\r
+    License as published by the Free Software Foundation; either\r
+    version 2.1 of the License, or (at your option) any later version.\r
+\r
+    This library is distributed in the hope that it will be useful,\r
+    but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+    Lesser General Public License for more details.\r
+\r
+    You should have received a copy of the GNU Lesser General Public\r
+    License along with this library; if not, write to the Free Software\r
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+\r
+Also add information on how to contact you by electronic and paper mail.\r
+\r
+You should also get your employer (if you work as a programmer) or your\r
+school, if any, to sign a "copyright disclaimer" for the library, if\r
+necessary.  Here is a sample; alter the names:\r
+\r
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the\r
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\r
+\r
+  <signature of Ty Coon>, 1 April 1990\r
+  Ty Coon, President of Vice\r
+\r
+That's all there is to it!\r
+\r
+\r
diff --git a/www/plugins/facteur/phpmailer-php5/README b/www/plugins/facteur/phpmailer-php5/README
new file mode 100755 (executable)
index 0000000..3670fb6
--- /dev/null
@@ -0,0 +1,178 @@
+/*******************************************************************\r
+* The http://phpmailer.codeworxtech.com/ website now carries a few *\r
+* advertisements through the Google Adsense network. Please visit  *\r
+* the advertiser sites and help us offset some of our costs.       *\r
+* Thanks ....                                                      *\r
+********************************************************************/\r
+\r
+PHPMailer\r
+Full Featured Email Transfer Class for PHP\r
+==========================================\r
+\r
+Version 2.1 (June 04 2008)\r
+\r
+With this release, we are announcing that the development of PHPMailer for PHP5\r
+will be our focus from this date on. We have implemented all the enhancements\r
+and fixes from the latest release of PHPMailer for PHP4.\r
+\r
+Far more important, though, is that this release of PHPMailer (v2.1) is\r
+fully tested with E_STRICT error checking enabled.\r
+\r
+** NOTE: WE HAVE A NEW LANGUAGE VARIABLE FOR DIGITALLY SIGNED S/MIME EMAILS.\r
+   IF YOU CAN HELP WITH LANGUAGES OTHER THAN ENGLISH AND SPANISH, IT WOULD BE\r
+   APPRECIATED.\r
+\r
+We have now added S/MIME functionality (ability to digitally sign emails).\r
+BIG THANKS TO "sergiocambra" for posting this patch back in November 2007.\r
+The "Signed Emails" functionality adds the Sign method to pass the private key\r
+filename and the password to read it, and then email will be sent with\r
+content-type multipart/signed and with the digital signature attached.\r
+\r
+A quick note on E_STRICT:\r
+\r
+- In about half the test environments the development version was subjected\r
+       to, an error was thrown for the date() functions (used at line 1565 and 1569).\r
+       This is NOT a PHPMailer error, it is the result of an incorrectly configured\r
+       PHP5 installation. The fix is to modify your 'php.ini' file and include the\r
+       date.timezone = America/New York\r
+       directive, (for your own server timezone)\r
+- If you do get this error, and are unable to access your php.ini file, there is\r
+       a workaround. In your PHP script, add\r
+       date_default_timezone_set('America/Toronto');\r
+\r
+       * do NOT try to use\r
+       $myVar = date_default_timezone_get();\r
+       as a test, it will throw an error.\r
+\r
+We have also included more example files to show the use of "sendmail", "mail()",\r
+"smtp", and "gmail".\r
+\r
+We are also looking for more programmers to join the volunteer development team.\r
+If you have an interest in this, please let us know.\r
+\r
+Enjoy!\r
+\r
+\r
+Version 2.1.0beta1 & beta2\r
+\r
+please note, this is BETA software\r
+** DO NOT USE THIS IN PRODUCTION OR LIVE PROJECTS\r
+INTENDED STRICTLY FOR TESTING\r
+\r
+** NOTE:\r
+\r
+As of November 2007, PHPMailer has a new project team headed by industry\r
+veteran Andy Prevost (codeworxtech). The first release in more than two\r
+years will focus on fixes, adding ease-of-use enhancements, provide\r
+basic compatibility with PHP4 and PHP5 using PHP5 backwards compatibility\r
+features. A new release is planned before year-end 2007 that will provide\r
+full compatiblity with PHP4 and PHP5, as well as more bug fixes.\r
+\r
+We are looking for project developers to assist in restoring PHPMailer to\r
+its leadership position. Our goals are to simplify use of PHPMailer, provide\r
+good documentation and examples, and retain backward compatibility to level\r
+1.7.3 standards.\r
+\r
+If you are interested in helping out, visit http://sourceforge.net/phpmailer\r
+and indicate your interest.\r
+\r
+**\r
+\r
+http://phpmailer.sourceforge.net/\r
+\r
+This software is licenced under the LGPL.  Please read LICENSE for information on the\r
+software availability and distribution.\r
+\r
+Class Features:\r
+- Send emails with multiple TOs, CCs, BCCs and REPLY-TOs\r
+- Redundant SMTP servers\r
+- Multipart/alternative emails for mail clients that do not read HTML email\r
+- Support for 8bit, base64, binary, and quoted-printable encoding\r
+- Uses the same methods as the very popular AspEmail active server (COM) component\r
+- SMTP authentication\r
+- Native language support\r
+- Word wrap, and more!\r
+\r
+Why you might need it:\r
+\r
+Many PHP developers utilize email in their code.  The only PHP function\r
+that supports this is the mail() function.  However, it does not expose\r
+any of the popular features that many email clients use nowadays like\r
+HTML-based emails and attachments. There are two proprietary\r
+development tools out there that have all the functionality built into\r
+easy to use classes: AspEmail(tm) and AspMail.  Both of these\r
+programs are COM components only available on Windows.  They are also a\r
+little pricey for smaller projects.\r
+\r
+Since I do Linux development I\92ve missed these tools for my PHP coding.\r
+So I built a version myself that implements the same methods (object\r
+calls) that the Windows-based components do. It is open source and the\r
+LGPL license allows you to place the class in your proprietary PHP\r
+projects.\r
+\r
+\r
+Installation:\r
+\r
+Copy class.phpmailer.php into your php.ini include_path. If you are\r
+using the SMTP mailer then place class.smtp.php in your path as well.\r
+In the language directory you will find several files like\r
+phpmailer.lang-en.php.  If you look right before the .php extension\r
+that there are two letters.  These represent the language type of the\r
+translation file.  For instance "en" is the English file and "br" is\r
+the Portuguese file.  Chose the file that best fits with your language\r
+and place it in the PHP include path.  If your language is English\r
+then you have nothing more to do.  If it is a different language then\r
+you must point PHPMailer to the correct translation.  To do this, call\r
+the PHPMailer SetLanguage method like so:\r
+\r
+// To load the Portuguese version\r
+$mail->SetLanguage("br", "/optional/path/to/language/directory/");\r
+\r
+That's it.  You should now be ready to use PHPMailer!\r
+\r
+\r
+A Simple Example:\r
+\r
+<?php\r
+require("class.phpmailer.php");\r
+\r
+$mail = new PHPMailer();\r
+\r
+$mail->IsSMTP();                                      // set mailer to use SMTP\r
+$mail->Host = "smtp1.example.com;smtp2.example.com";  // specify main and backup server\r
+$mail->SMTPAuth = true;     // turn on SMTP authentication\r
+$mail->Username = "jswan";  // SMTP username\r
+$mail->Password = "secret"; // SMTP password\r
+\r
+$mail->From = "from@example.com";\r
+$mail->FromName = "Mailer";\r
+$mail->AddAddress("josh@example.net", "Josh Adams");\r
+$mail->AddAddress("ellen@example.com");                  // name is optional\r
+$mail->AddReplyTo("info@example.com", "Information");\r
+\r
+$mail->WordWrap = 50;                                 // set word wrap to 50 characters\r
+$mail->AddAttachment("/var/tmp/file.tar.gz");         // add attachments\r
+$mail->AddAttachment("/tmp/image.jpg", "new.jpg");    // optional name\r
+$mail->IsHTML(true);                                  // set email format to HTML\r
+\r
+$mail->Subject = "Here is the subject";\r
+$mail->Body    = "This is the HTML message body <b>in bold!</b>";\r
+$mail->AltBody = "This is the body in plain text for non-HTML mail clients";\r
+\r
+if(!$mail->Send())\r
+{\r
+   echo "Message could not be sent. <p>";\r
+   echo "Mailer Error: " . $mail->ErrorInfo;\r
+   exit;\r
+}\r
+\r
+echo "Message has been sent";\r
+?>\r
+\r
+CHANGELOG\r
+\r
+See ChangeLog.txt\r
+\r
+Download: http://sourceforge.net/project/showfiles.php?group_id=26031\r
+\r
+Andy Prevost\r
diff --git a/www/plugins/facteur/phpmailer-php5/class.phpmailer.php b/www/plugins/facteur/phpmailer-php5/class.phpmailer.php
new file mode 100755 (executable)
index 0000000..9cdd0f3
--- /dev/null
@@ -0,0 +1,2320 @@
+<?php
+/*~ class.phpmailer.php
+.---------------------------------------------------------------------------.
+|  Software: PHPMailer - PHP email class                                    |
+|   Version: 5.1                                                            |
+|   Contact: via sourceforge.net support pages (also www.worxware.com)      |
+|      Info: http://phpmailer.sourceforge.net                               |
+|   Support: http://sourceforge.net/projects/phpmailer/                     |
+| ------------------------------------------------------------------------- |
+|     Admin: Andy Prevost (project admininistrator)                         |
+|   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
+|          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
+|   Founder: Brent R. Matzelle (original founder)                           |
+| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
+| Copyright (c) 2001-2003, Brent R. Matzelle                                |
+| ------------------------------------------------------------------------- |
+|   License: Distributed under the Lesser General Public License (LGPL)     |
+|            http://www.gnu.org/copyleft/lesser.html                        |
+| This program is distributed in the hope that it will be useful - WITHOUT  |
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
+| FITNESS FOR A PARTICULAR PURPOSE.                                         |
+| ------------------------------------------------------------------------- |
+| We offer a number of paid services (www.worxware.com):                    |
+| - Web Hosting on highly optimized fast and secure servers                 |
+| - Technology Consulting                                                   |
+| - Oursourcing (highly qualified programmers and graphic designers)        |
+'---------------------------------------------------------------------------'
+*/
+
+/**
+ * PHPMailer - PHP email transport class
+ * NOTE: Requires PHP version 5 or later
+ * @package PHPMailer
+ * @author Andy Prevost
+ * @author Marcus Bointon
+ * @copyright 2004 - 2009 Andy Prevost
+ * @version $Id: class.phpmailer.php 447 2009-05-25 01:36:38Z codeworxtech $
+ * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
+ */
+
+if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
+
+class PHPMailer {
+
+  /////////////////////////////////////////////////
+  // PROPERTIES, PUBLIC
+  /////////////////////////////////////////////////
+
+  /**
+   * Email priority (1 = High, 3 = Normal, 5 = low).
+   * @var int
+   */
+  public $Priority          = 3;
+
+  /**
+   * Sets the CharSet of the message.
+   * @var string
+   */
+  public $CharSet           = 'iso-8859-1';
+
+  /**
+   * Sets the Content-type of the message.
+   * @var string
+   */
+  public $ContentType       = 'text/plain';
+
+  /**
+   * Sets the Encoding of the message. Options for this are
+   *  "8bit", "7bit", "binary", "base64", and "quoted-printable".
+   * @var string
+   */
+  public $Encoding          = '8bit';
+
+  /**
+   * Holds the most recent mailer error message.
+   * @var string
+   */
+  public $ErrorInfo         = '';
+
+  /**
+   * Sets the From email address for the message.
+   * @var string
+   */
+  public $From              = 'root@localhost';
+
+  /**
+   * Sets the From name of the message.
+   * @var string
+   */
+  public $FromName          = 'Root User';
+
+  /**
+   * Sets the Sender email (Return-Path) of the message.  If not empty,
+   * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
+   * @var string
+   */
+  public $Sender            = '';
+
+  /**
+   * Sets the Subject of the message.
+   * @var string
+   */
+  public $Subject           = '';
+
+  /**
+   * Sets the Body of the message.  This can be either an HTML or text body.
+   * If HTML then run IsHTML(true).
+   * @var string
+   */
+  public $Body              = '';
+
+  /**
+   * Sets the text-only body of the message.  This automatically sets the
+   * email to multipart/alternative.  This body can be read by mail
+   * clients that do not have HTML email capability such as mutt. Clients
+   * that can read HTML will view the normal Body.
+   * @var string
+   */
+  public $AltBody           = '';
+
+  /**
+   * Sets word wrapping on the body of the message to a given number of
+   * characters.
+   * @var int
+   */
+  public $WordWrap          = 0;
+
+  /**
+   * Method to send mail: ("mail", "sendmail", or "smtp").
+   * @var string
+   */
+  public $Mailer            = 'mail';
+
+  /**
+   * Sets the path of the sendmail program.
+   * @var string
+   */
+  public $Sendmail          = '/usr/sbin/sendmail';
+
+  /**
+   * Path to PHPMailer plugins.  Useful if the SMTP class
+   * is in a different directory than the PHP include path.
+   * @var string
+   */
+  public $PluginDir         = '';
+
+  /**
+   * Sets the email address that a reading confirmation will be sent.
+   * @var string
+   */
+  public $ConfirmReadingTo  = '';
+
+  /**
+   * Sets the hostname to use in Message-Id and Received headers
+   * and as default HELO string. If empty, the value returned
+   * by SERVER_NAME is used or 'localhost.localdomain'.
+   * @var string
+   */
+  public $Hostname          = '';
+
+  /**
+   * Sets the message ID to be used in the Message-Id header.
+   * If empty, a unique id will be generated.
+   * @var string
+   */
+  public $MessageID         = '';
+
+  /////////////////////////////////////////////////
+  // PROPERTIES FOR SMTP
+  /////////////////////////////////////////////////
+
+  /**
+   * Sets the SMTP hosts.  All hosts must be separated by a
+   * semicolon.  You can also specify a different port
+   * for each host by using this format: [hostname:port]
+   * (e.g. "smtp1.example.com:25;smtp2.example.com").
+   * Hosts will be tried in order.
+   * @var string
+   */
+  public $Host          = 'localhost';
+
+  /**
+   * Sets the default SMTP server port.
+   * @var int
+   */
+  public $Port          = 25;
+
+  /**
+   * Sets the SMTP HELO of the message (Default is $Hostname).
+   * @var string
+   */
+  public $Helo          = '';
+
+  /**
+   * Sets connection prefix.
+   * Options are "", "ssl" or "tls"
+   * @var string
+   */
+  public $SMTPSecure    = '';
+
+  /**
+   * Sets SMTP authentication. Utilizes the Username and Password variables.
+   * @var bool
+   */
+  public $SMTPAuth      = false;
+
+  /**
+   * Sets SMTP username.
+   * @var string
+   */
+  public $Username      = '';
+
+  /**
+   * Sets SMTP password.
+   * @var string
+   */
+  public $Password      = '';
+
+  /**
+   * Sets the SMTP server timeout in seconds.
+   * This function will not work with the win32 version.
+   * @var int
+   */
+  public $Timeout       = 10;
+
+  /**
+   * Sets SMTP class debugging on or off.
+   * @var bool
+   */
+  public $SMTPDebug     = false;
+
+  /**
+   * Prevents the SMTP connection from being closed after each mail
+   * sending.  If this is set to true then to close the connection
+   * requires an explicit call to SmtpClose().
+   * @var bool
+   */
+  public $SMTPKeepAlive = false;
+
+  /**
+   * Provides the ability to have the TO field process individual
+   * emails, instead of sending to entire TO addresses
+   * @var bool
+   */
+  public $SingleTo      = false;
+
+   /**
+   * If SingleTo is true, this provides the array to hold the email addresses
+   * @var bool
+   */
+  public $SingleToArray = array();
+
+ /**
+   * Provides the ability to change the line ending
+   * @var string
+   */
+  public $LE              = "\n";
+
+  /**
+   * Used with DKIM DNS Resource Record
+   * @var string
+   */
+  public $DKIM_selector   = 'phpmailer';
+
+  /**
+   * Used with DKIM DNS Resource Record
+   * optional, in format of email address 'you@yourdomain.com'
+   * @var string
+   */
+  public $DKIM_identity   = '';
+
+  /**
+   * Used with DKIM DNS Resource Record
+   * optional, in format of email address 'you@yourdomain.com'
+   * @var string
+   */
+  public $DKIM_domain     = '';
+
+  /**
+   * Used with DKIM DNS Resource Record
+   * optional, in format of email address 'you@yourdomain.com'
+   * @var string
+   */
+  public $DKIM_private    = '';
+
+  /**
+   * Callback Action function name
+   * the function that handles the result of the send email action. Parameters:
+   *   bool    $result        result of the send action
+   *   string  $to            email address of the recipient
+   *   string  $cc            cc email addresses
+   *   string  $bcc           bcc email addresses
+   *   string  $subject       the subject
+   *   string  $body          the email body
+   * @var string
+   */
+  public $action_function = ''; //'callbackAction';
+
+  /**
+   * Sets the PHPMailer Version number
+   * @var string
+   */
+  public $Version         = '5.1';
+
+  /////////////////////////////////////////////////
+  // PROPERTIES, PRIVATE AND PROTECTED
+  /////////////////////////////////////////////////
+
+  private   $smtp           = NULL;
+  private   $to             = array();
+  private   $cc             = array();
+  private   $bcc            = array();
+  private   $ReplyTo        = array();
+  private   $all_recipients = array();
+  private   $attachment     = array();
+  private   $CustomHeader   = array();
+  private   $message_type   = '';
+  private   $boundary       = array();
+  protected $language       = array();
+  private   $error_count    = 0;
+  private   $sign_cert_file = "";
+  private   $sign_key_file  = "";
+  private   $sign_key_pass  = "";
+  private   $exceptions     = false;
+
+  /////////////////////////////////////////////////
+  // CONSTANTS
+  /////////////////////////////////////////////////
+
+  const STOP_MESSAGE  = 0; // message only, continue processing
+  const STOP_CONTINUE = 1; // message?, likely ok to continue processing
+  const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
+
+  /////////////////////////////////////////////////
+  // METHODS, VARIABLES
+  /////////////////////////////////////////////////
+
+  /**
+   * Constructor
+   * @param boolean $exceptions Should we throw external exceptions?
+   */
+  public function __construct($exceptions = false) {
+    $this->exceptions = ($exceptions == true);
+  }
+
+  /**
+   * Sets message type to HTML.
+   * @param bool $ishtml
+   * @return void
+   */
+  public function IsHTML($ishtml = true) {
+    if ($ishtml) {
+      $this->ContentType = 'text/html';
+    } else {
+      $this->ContentType = 'text/plain';
+    }
+  }
+
+  /**
+   * Sets Mailer to send message using SMTP.
+   * @return void
+   */
+  public function IsSMTP() {
+    $this->Mailer = 'smtp';
+  }
+
+  /**
+   * Sets Mailer to send message using PHP mail() function.
+   * @return void
+   */
+  public function IsMail() {
+    $this->Mailer = 'mail';
+  }
+
+  /**
+   * Sets Mailer to send message using the $Sendmail program.
+   * @return void
+   */
+  public function IsSendmail() {
+    if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
+      $this->Sendmail = '/var/qmail/bin/sendmail';
+    }
+    $this->Mailer = 'sendmail';
+  }
+
+  /**
+   * Sets Mailer to send message using the qmail MTA.
+   * @return void
+   */
+  public function IsQmail() {
+    if (stristr(ini_get('sendmail_path'), 'qmail')) {
+      $this->Sendmail = '/var/qmail/bin/sendmail';
+    }
+    $this->Mailer = 'sendmail';
+  }
+
+  /////////////////////////////////////////////////
+  // METHODS, RECIPIENTS
+  /////////////////////////////////////////////////
+
+  /**
+   * Adds a "To" address.
+   * @param string $address
+   * @param string $name
+   * @return boolean true on success, false if address already used
+   */
+  public function AddAddress($address, $name = '') {
+    return $this->AddAnAddress('to', $address, $name);
+  }
+
+  /**
+   * Adds a "Cc" address.
+   * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
+   * @param string $address
+   * @param string $name
+   * @return boolean true on success, false if address already used
+   */
+  public function AddCC($address, $name = '') {
+    return $this->AddAnAddress('cc', $address, $name);
+  }
+
+  /**
+   * Adds a "Bcc" address.
+   * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
+   * @param string $address
+   * @param string $name
+   * @return boolean true on success, false if address already used
+   */
+  public function AddBCC($address, $name = '') {
+    return $this->AddAnAddress('bcc', $address, $name);
+  }
+
+  /**
+   * Adds a "Reply-to" address.
+   * @param string $address
+   * @param string $name
+   * @return boolean
+   */
+  public function AddReplyTo($address, $name = '') {
+    return $this->AddAnAddress('ReplyTo', $address, $name);
+  }
+
+  /**
+   * Adds an address to one of the recipient arrays
+   * Addresses that have been added already return false, but do not throw exceptions
+   * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
+   * @param string $address The email address to send to
+   * @param string $name
+   * @return boolean true on success, false if address already used or invalid in some way
+   * @access private
+   */
+  private function AddAnAddress($kind, $address, $name = '') {
+    if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
+      echo 'Invalid recipient array: ' . kind;
+      return false;
+    }
+    $address = trim($address);
+    $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+    if (!self::ValidateAddress($address)) {
+      $this->SetError($this->Lang('invalid_address').': '. $address);
+      if ($this->exceptions) {
+        throw new phpmailerException($this->Lang('invalid_address').': '.$address);
+      }
+      echo $this->Lang('invalid_address').': '.$address;
+      return false;
+    }
+    if ($kind != 'ReplyTo') {
+      if (!isset($this->all_recipients[strtolower($address)])) {
+        array_push($this->$kind, array($address, $name));
+        $this->all_recipients[strtolower($address)] = true;
+        return true;
+      }
+    } else {
+      if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
+        $this->ReplyTo[strtolower($address)] = array($address, $name);
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Set the From and FromName properties
+ * @param string $address
+ * @param string $name
+ * @return boolean
+ */
+  public function SetFrom($address, $name = '',$auto=1) {
+    $address = trim($address);
+    $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
+    if (!self::ValidateAddress($address)) {
+      $this->SetError($this->Lang('invalid_address').': '. $address);
+      if ($this->exceptions) {
+        throw new phpmailerException($this->Lang('invalid_address').': '.$address);
+      }
+      echo $this->Lang('invalid_address').': '.$address;
+      return false;
+    }
+    $this->From = $address;
+    $this->FromName = $name;
+    if ($auto) {
+      if (empty($this->ReplyTo)) {
+        $this->AddAnAddress('ReplyTo', $address, $name);
+      }
+      if (empty($this->Sender)) {
+        $this->Sender = $address;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Check that a string looks roughly like an email address should
+   * Static so it can be used without instantiation
+   * Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator
+   * Conforms approximately to RFC2822
+   * @link http://www.hexillion.com/samples/#Regex Original pattern found here
+   * @param string $address The email address to check
+   * @return boolean
+   * @static
+   * @access public
+   */
+  public static function ValidateAddress($address) {
+    if (function_exists('filter_var')) { //Introduced in PHP 5.2
+      if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
+        return false;
+      } else {
+        return true;
+      }
+    } else {
+      return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
+    }
+  }
+
+  /////////////////////////////////////////////////
+  // METHODS, MAIL SENDING
+  /////////////////////////////////////////////////
+
+  /**
+   * Creates message and assigns Mailer. If the message is
+   * not sent successfully then it returns false.  Use the ErrorInfo
+   * variable to view description of the error.
+   * @return bool
+   */
+  public function Send() {
+    try {
+      if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
+        throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
+      }
+
+      // Set whether the message is multipart/alternative
+      if(!empty($this->AltBody)) {
+        $this->ContentType = 'multipart/alternative';
+      }
+
+      $this->error_count = 0; // reset errors
+      $this->SetMessageType();
+      $header = $this->CreateHeader();
+      $body = $this->CreateBody();
+
+      if (empty($this->Body)) {
+        throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
+      }
+
+      // digitally sign with DKIM if enabled
+      if ($this->DKIM_domain && $this->DKIM_private) {
+        $header_dkim = $this->DKIM_Add($header,$this->Subject,$body);
+        $header = str_replace("\r\n","\n",$header_dkim) . $header;
+      }
+
+      // Choose the mailer and send through it
+      switch($this->Mailer) {
+        case 'sendmail':
+          return $this->SendmailSend($header, $body);
+        case 'smtp':
+          return $this->SmtpSend($header, $body);
+        default:
+          return $this->MailSend($header, $body);
+      }
+
+    } catch (phpmailerException $e) {
+      $this->SetError($e->getMessage());
+      if ($this->exceptions) {
+        throw $e;
+      }
+      echo $e->getMessage()."\n";
+      return false;
+    }
+  }
+
+  /**
+   * Sends mail using the $Sendmail program.
+   * @param string $header The message headers
+   * @param string $body The message body
+   * @access protected
+   * @return bool
+   */
+  protected function SendmailSend($header, $body) {
+    if ($this->Sender != '') {
+      $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
+    } else {
+      $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
+    }
+    if ($this->SingleTo === true) {
+      foreach ($this->SingleToArray as $key => $val) {
+        if(!@$mail = popen($sendmail, 'w')) {
+          throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+        }
+        fputs($mail, "To: " . $val . "\n");
+        fputs($mail, $header);
+        fputs($mail, $body);
+        $result = pclose($mail);
+        // implement call back function if it exists
+        $isSent = ($result == 0) ? 1 : 0;
+        $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
+        if($result != 0) {
+          throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+        }
+      }
+    } else {
+      if(!@$mail = popen($sendmail, 'w')) {
+        throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+      }
+      fputs($mail, $header);
+      fputs($mail, $body);
+      $result = pclose($mail);
+      // implement call back function if it exists
+      $isSent = ($result == 0) ? 1 : 0;
+      $this->doCallback($isSent,$this->to,$this->cc,$this->bcc,$this->Subject,$body);
+      if($result != 0) {
+        throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Sends mail using the PHP mail() function.
+   * @param string $header The message headers
+   * @param string $body The message body
+   * @access protected
+   * @return bool
+   */
+  protected function MailSend($header, $body) {
+    $toArr = array();
+    foreach($this->to as $t) {
+      $toArr[] = $this->AddrFormat($t);
+    }
+    $to = implode(', ', $toArr);
+
+    $params = sprintf("-oi -f %s", $this->Sender);
+    if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
+      $old_from = ini_get('sendmail_from');
+      ini_set('sendmail_from', $this->Sender);
+      if ($this->SingleTo === true && count($toArr) > 1) {
+        foreach ($toArr as $key => $val) {
+          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+          // implement call back function if it exists
+          $isSent = ($rt == 1) ? 1 : 0;
+          $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
+        }
+      } else {
+        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+        // implement call back function if it exists
+        $isSent = ($rt == 1) ? 1 : 0;
+        $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
+      }
+    } else {
+      if ($this->SingleTo === true && count($toArr) > 1) {
+        foreach ($toArr as $key => $val) {
+          $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
+          // implement call back function if it exists
+          $isSent = ($rt == 1) ? 1 : 0;
+          $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
+        }
+      } else {
+        $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
+        // implement call back function if it exists
+        $isSent = ($rt == 1) ? 1 : 0;
+        $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
+      }
+    }
+    if (isset($old_from)) {
+      ini_set('sendmail_from', $old_from);
+    }
+    if(!$rt) {
+      throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
+    }
+    return true;
+  }
+
+  /**
+   * Sends mail via SMTP using PhpSMTP
+   * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
+   * @param string $header The message headers
+   * @param string $body The message body
+   * @uses SMTP
+   * @access protected
+   * @return bool
+   */
+  protected function SmtpSend($header, $body) {
+    require_once $this->PluginDir . 'class.smtp.php';
+    $bad_rcpt = array();
+
+    if(!$this->SmtpConnect()) {
+      throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
+    }
+    $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
+    if(!$this->smtp->Mail($smtp_from)) {
+      throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
+    }
+
+    // Attempt to send attach all recipients
+    foreach($this->to as $to) {
+      if (!$this->smtp->Recipient($to[0])) {
+        $bad_rcpt[] = $to[0];
+        // implement call back function if it exists
+        $isSent = 0;
+        $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
+      } else {
+        // implement call back function if it exists
+        $isSent = 1;
+        $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
+      }
+    }
+    foreach($this->cc as $cc) {
+      if (!$this->smtp->Recipient($cc[0])) {
+        $bad_rcpt[] = $cc[0];
+        // implement call back function if it exists
+        $isSent = 0;
+        $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
+      } else {
+        // implement call back function if it exists
+        $isSent = 1;
+        $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
+      }
+    }
+    foreach($this->bcc as $bcc) {
+      if (!$this->smtp->Recipient($bcc[0])) {
+        $bad_rcpt[] = $bcc[0];
+        // implement call back function if it exists
+        $isSent = 0;
+        $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
+      } else {
+        // implement call back function if it exists
+        $isSent = 1;
+        $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
+      }
+    }
+
+
+    if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
+      $badaddresses = implode(', ', $bad_rcpt);
+      throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
+    }
+    if(!$this->smtp->Data($header . $body)) {
+      throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
+    }
+    if($this->SMTPKeepAlive == true) {
+      $this->smtp->Reset();
+    }
+    return true;
+  }
+
+  /**
+   * Initiates a connection to an SMTP server.
+   * Returns false if the operation failed.
+   * @uses SMTP
+   * @access public
+   * @return bool
+   */
+  public function SmtpConnect() {
+    if(is_null($this->smtp)) {
+      $this->smtp = new SMTP();
+    }
+
+    $this->smtp->do_debug = $this->SMTPDebug;
+    $hosts = explode(';', $this->Host);
+    $index = 0;
+    $connection = $this->smtp->Connected();
+
+    // Retry while there is no connection
+    try {
+      while($index < count($hosts) && !$connection) {
+        $hostinfo = array();
+        if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
+          $host = $hostinfo[1];
+          $port = $hostinfo[2];
+        } else {
+          $host = $hosts[$index];
+          $port = $this->Port;
+        }
+
+        $tls = ($this->SMTPSecure == 'tls');
+        $ssl = ($this->SMTPSecure == 'ssl');
+
+        if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
+
+          $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
+          $this->smtp->Hello($hello);
+
+          if ($tls) {
+            if (!$this->smtp->StartTLS()) {
+              throw new phpmailerException($this->Lang('tls'));
+            }
+
+            //We must resend HELO after tls negotiation
+            $this->smtp->Hello($hello);
+          }
+
+          $connection = true;
+          if ($this->SMTPAuth) {
+            if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
+              throw new phpmailerException($this->Lang('authenticate'));
+            }
+          }
+        }
+        $index++;
+        if (!$connection) {
+          throw new phpmailerException($this->Lang('connect_host'));
+        }
+      }
+    } catch (phpmailerException $e) {
+      $this->smtp->Reset();
+      throw $e;
+    }
+    return true;
+  }
+
+  /**
+   * Closes the active SMTP session if one exists.
+   * @return void
+   */
+  public function SmtpClose() {
+    if(!is_null($this->smtp)) {
+      if($this->smtp->Connected()) {
+        $this->smtp->Quit();
+        $this->smtp->Close();
+      }
+    }
+  }
+
+  /**
+  * Sets the language for all class error messages.
+  * Returns false if it cannot load the language file.  The default language is English.
+  * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
+  * @param string $lang_path Path to the language file directory
+  * @access public
+  */
+  function SetLanguage($langcode = 'en', $lang_path = 'language/') {
+    //Define full set of translatable strings
+    $PHPMAILER_LANG = array(
+      'provide_address' => 'You must provide at least one recipient email address.',
+      'mailer_not_supported' => ' mailer is not supported.',
+      'execute' => 'Could not execute: ',
+      'instantiate' => 'Could not instantiate mail function.',
+      'authenticate' => 'SMTP Error: Could not authenticate.',
+      'from_failed' => 'The following From address failed: ',
+      'recipients_failed' => 'SMTP Error: The following recipients failed: ',
+      'data_not_accepted' => 'SMTP Error: Data not accepted.',
+      'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
+      'file_access' => 'Could not access file: ',
+      'file_open' => 'File Error: Could not open file: ',
+      'encoding' => 'Unknown encoding: ',
+      'signing' => 'Signing Error: ',
+      'smtp_error' => 'SMTP server error: ',
+      'empty_message' => 'Message body empty',
+      'invalid_address' => 'Invalid address',
+      'variable_set' => 'Cannot set or reset variable: '
+    );
+    //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
+    $l = true;
+    if ($langcode != 'en') { //There is no English translation file
+      $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
+    }
+    $this->language = $PHPMAILER_LANG;
+    return ($l == true); //Returns false if language not found
+  }
+
+  /**
+  * Return the current array of language strings
+  * @return array
+  */
+  public function GetTranslations() {
+    return $this->language;
+  }
+
+  /////////////////////////////////////////////////
+  // METHODS, MESSAGE CREATION
+  /////////////////////////////////////////////////
+
+  /**
+   * Creates recipient headers.
+   * @access public
+   * @return string
+   */
+  public function AddrAppend($type, $addr) {
+    $addr_str = $type . ': ';
+    $addresses = array();
+    foreach ($addr as $a) {
+      $addresses[] = $this->AddrFormat($a);
+    }
+    $addr_str .= implode(', ', $addresses);
+    $addr_str .= $this->LE;
+
+    return $addr_str;
+  }
+
+  /**
+   * Formats an address correctly.
+   * @access public
+   * @return string
+   */
+  public function AddrFormat($addr) {
+    if (empty($addr[1])) {
+      return $this->SecureHeader($addr[0]);
+    } else {
+      return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
+    }
+  }
+
+  /**
+   * Wraps message for use with mailers that do not
+   * automatically perform wrapping and for quoted-printable.
+   * Original written by philippe.
+   * @param string $message The message to wrap
+   * @param integer $length The line length to wrap to
+   * @param boolean $qp_mode Whether to run in Quoted-Printable mode
+   * @access public
+   * @return string
+   */
+  public function WrapText($message, $length, $qp_mode = false) {
+    $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
+    // If utf-8 encoding is used, we will need to make sure we don't
+    // split multibyte characters when we wrap
+    $is_utf8 = (strtolower($this->CharSet) == "utf-8");
+
+    $message = $this->FixEOL($message);
+    if (substr($message, -1) == $this->LE) {
+      $message = substr($message, 0, -1);
+    }
+
+    $line = explode($this->LE, $message);
+    $message = '';
+    for ($i=0 ;$i < count($line); $i++) {
+      $line_part = explode(' ', $line[$i]);
+      $buf = '';
+      for ($e = 0; $e<count($line_part); $e++) {
+        $word = $line_part[$e];
+        if ($qp_mode and (strlen($word) > $length)) {
+          $space_left = $length - strlen($buf) - 1;
+          if ($e != 0) {
+            if ($space_left > 20) {
+              $len = $space_left;
+              if ($is_utf8) {
+                $len = $this->UTF8CharBoundary($word, $len);
+              } elseif (substr($word, $len - 1, 1) == "=") {
+                $len--;
+              } elseif (substr($word, $len - 2, 1) == "=") {
+                $len -= 2;
+              }
+              $part = substr($word, 0, $len);
+              $word = substr($word, $len);
+              $buf .= ' ' . $part;
+              $message .= $buf . sprintf("=%s", $this->LE);
+            } else {
+              $message .= $buf . $soft_break;
+            }
+            $buf = '';
+          }
+          while (strlen($word) > 0) {
+            $len = $length;
+            if ($is_utf8) {
+              $len = $this->UTF8CharBoundary($word, $len);
+            } elseif (substr($word, $len - 1, 1) == "=") {
+              $len--;
+            } elseif (substr($word, $len - 2, 1) == "=") {
+              $len -= 2;
+            }
+            $part = substr($word, 0, $len);
+            $word = substr($word, $len);
+
+            if (strlen($word) > 0) {
+              $message .= $part . sprintf("=%s", $this->LE);
+            } else {
+              $buf = $part;
+            }
+          }
+        } else {
+          $buf_o = $buf;
+          $buf .= ($e == 0) ? $word : (' ' . $word);
+
+          if (strlen($buf) > $length and $buf_o != '') {
+            $message .= $buf_o . $soft_break;
+            $buf = $word;
+          }
+        }
+      }
+      $message .= $buf . $this->LE;
+    }
+
+    return $message;
+  }
+
+  /**
+   * Finds last character boundary prior to maxLength in a utf-8
+   * quoted (printable) encoded string.
+   * Original written by Colin Brown.
+   * @access public
+   * @param string $encodedText utf-8 QP text
+   * @param int    $maxLength   find last character boundary prior to this length
+   * @return int
+   */
+  public function UTF8CharBoundary($encodedText, $maxLength) {
+    $foundSplitPos = false;
+    $lookBack = 3;
+    while (!$foundSplitPos) {
+      $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
+      $encodedCharPos = strpos($lastChunk, "=");
+      if ($encodedCharPos !== false) {
+        // Found start of encoded character byte within $lookBack block.
+        // Check the encoded byte value (the 2 chars after the '=')
+        $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
+        $dec = hexdec($hex);
+        if ($dec < 128) { // Single byte character.
+          // If the encoded char was found at pos 0, it will fit
+          // otherwise reduce maxLength to start of the encoded char
+          $maxLength = ($encodedCharPos == 0) ? $maxLength :
+          $maxLength - ($lookBack - $encodedCharPos);
+          $foundSplitPos = true;
+        } elseif ($dec >= 192) { // First byte of a multi byte character
+          // Reduce maxLength to split at start of character
+          $maxLength = $maxLength - ($lookBack - $encodedCharPos);
+          $foundSplitPos = true;
+        } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
+          $lookBack += 3;
+        }
+      } else {
+        // No encoded character found
+        $foundSplitPos = true;
+      }
+    }
+    return $maxLength;
+  }
+
+
+  /**
+   * Set the body wrapping.
+   * @access public
+   * @return void
+   */
+  public function SetWordWrap() {
+    if($this->WordWrap < 1) {
+      return;
+    }
+
+    switch($this->message_type) {
+      case 'alt':
+      case 'alt_attachments':
+        $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
+        break;
+      default:
+        $this->Body = $this->WrapText($this->Body, $this->WordWrap);
+        break;
+    }
+  }
+
+  /**
+   * Assembles message header.
+   * @access public
+   * @return string The assembled header
+   */
+  public function CreateHeader() {
+    $result = '';
+
+    // Set the boundaries
+    $uniq_id = md5(uniqid(time()));
+    $this->boundary[1] = 'b1_' . $uniq_id;
+    $this->boundary[2] = 'b2_' . $uniq_id;
+
+    $result .= $this->HeaderLine('Date', self::RFCDate());
+    if($this->Sender == '') {
+      $result .= $this->HeaderLine('Return-Path', trim($this->From));
+    } else {
+      $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
+    }
+
+    // To be created automatically by mail()
+    if($this->Mailer != 'mail') {
+      if ($this->SingleTo === true) {
+        foreach($this->to as $t) {
+          $this->SingleToArray[] = $this->AddrFormat($t);
+        }
+      } else {
+        if(count($this->to) > 0) {
+          $result .= $this->AddrAppend('To', $this->to);
+        } elseif (count($this->cc) == 0) {
+          $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
+        }
+      }
+    }
+
+    $from = array();
+    $from[0][0] = trim($this->From);
+    $from[0][1] = $this->FromName;
+    $result .= $this->AddrAppend('From', $from);
+
+    // sendmail and mail() extract Cc from the header before sending
+    if(count($this->cc) > 0) {
+      $result .= $this->AddrAppend('Cc', $this->cc);
+    }
+
+    // sendmail and mail() extract Bcc from the header before sending
+    if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
+      $result .= $this->AddrAppend('Bcc', $this->bcc);
+    }
+
+    if(count($this->ReplyTo) > 0) {
+      $result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
+    }
+
+    // mail() sets the subject itself
+    if($this->Mailer != 'mail') {
+      $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
+    }
+
+    if($this->MessageID != '') {
+      $result .= $this->HeaderLine('Message-ID',$this->MessageID);
+    } else {
+      $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
+    }
+    $result .= $this->HeaderLine('X-Priority', $this->Priority);
+    $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (phpmailer.sourceforge.net)');
+
+    if($this->ConfirmReadingTo != '') {
+      $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
+    }
+
+    // Add custom headers
+    for($index = 0; $index < count($this->CustomHeader); $index++) {
+      $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
+    }
+    if (!$this->sign_key_file) {
+      $result .= $this->HeaderLine('MIME-Version', '1.0');
+      $result .= $this->GetMailMIME();
+    }
+
+    return $result;
+  }
+
+  /**
+   * Returns the message MIME.
+   * @access public
+   * @return string
+   */
+  public function GetMailMIME() {
+    $result = '';
+    switch($this->message_type) {
+      case 'plain':
+        $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
+        $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
+        break;
+      case 'attachments':
+      case 'alt_attachments':
+        if($this->InlineImageExists()){
+          $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
+        } else {
+          $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
+          $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+        }
+        break;
+      case 'alt':
+        $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
+        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
+        break;
+    }
+
+    if($this->Mailer != 'mail') {
+      $result .= $this->LE.$this->LE;
+    }
+
+    return $result;
+  }
+
+  /**
+   * Assembles the message body.  Returns an empty string on failure.
+   * @access public
+   * @return string The assembled message body
+   */
+  public function CreateBody() {
+    $body = '';
+
+    if ($this->sign_key_file) {
+      $body .= $this->GetMailMIME();
+    }
+
+    $this->SetWordWrap();
+
+    switch($this->message_type) {
+      case 'alt':
+        $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
+        $body .= $this->EncodeString($this->AltBody, $this->Encoding);
+        $body .= $this->LE.$this->LE;
+        $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
+        $body .= $this->EncodeString($this->Body, $this->Encoding);
+        $body .= $this->LE.$this->LE;
+        $body .= $this->EndBoundary($this->boundary[1]);
+        break;
+      case 'plain':
+        $body .= $this->EncodeString($this->Body, $this->Encoding);
+        break;
+      case 'attachments':
+        $body .= $this->GetBoundary($this->boundary[1], '', '', '');
+        $body .= $this->EncodeString($this->Body, $this->Encoding);
+        $body .= $this->LE;
+        $body .= $this->AttachAll();
+        break;
+      case 'alt_attachments':
+        $body .= sprintf("--%s%s", $this->boundary[1], $this->LE);
+        $body .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
+        $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
+        $body .= $this->EncodeString($this->AltBody, $this->Encoding);
+        $body .= $this->LE.$this->LE;
+        $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
+        $body .= $this->EncodeString($this->Body, $this->Encoding);
+        $body .= $this->LE.$this->LE;
+        $body .= $this->EndBoundary($this->boundary[2]);
+        $body .= $this->AttachAll();
+        break;
+    }
+
+    if ($this->IsError()) {
+      $body = '';
+    } elseif ($this->sign_key_file) {
+      try {
+        $file = tempnam('', 'mail');
+        file_put_contents($file, $body); //TODO check this worked
+        $signed = tempnam("", "signed");
+        if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
+          @unlink($file);
+          @unlink($signed);
+          $body = file_get_contents($signed);
+        } else {
+          @unlink($file);
+          @unlink($signed);
+          throw new phpmailerException($this->Lang("signing").openssl_error_string());
+        }
+      } catch (phpmailerException $e) {
+        $body = '';
+        if ($this->exceptions) {
+          throw $e;
+        }
+      }
+    }
+
+    return $body;
+  }
+
+  /**
+   * Returns the start of a message boundary.
+   * @access private
+   */
+  private function GetBoundary($boundary, $charSet, $contentType, $encoding) {
+    $result = '';
+    if($charSet == '') {
+      $charSet = $this->CharSet;
+    }
+    if($contentType == '') {
+      $contentType = $this->ContentType;
+    }
+    if($encoding == '') {
+      $encoding = $this->Encoding;
+    }
+    $result .= $this->TextLine('--' . $boundary);
+    $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
+    $result .= $this->LE;
+    $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
+    $result .= $this->LE;
+
+    return $result;
+  }
+
+  /**
+   * Returns the end of a message boundary.
+   * @access private
+   */
+  private function EndBoundary($boundary) {
+    return $this->LE . '--' . $boundary . '--' . $this->LE;
+  }
+
+  /**
+   * Sets the message type.
+   * @access private
+   * @return void
+   */
+  private function SetMessageType() {
+    if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
+      $this->message_type = 'plain';
+    } else {
+      if(count($this->attachment) > 0) {
+        $this->message_type = 'attachments';
+      }
+      if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
+        $this->message_type = 'alt';
+      }
+      if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
+        $this->message_type = 'alt_attachments';
+      }
+    }
+  }
+
+  /**
+   *  Returns a formatted header line.
+   * @access public
+   * @return string
+   */
+  public function HeaderLine($name, $value) {
+    return $name . ': ' . $value . $this->LE;
+  }
+
+  /**
+   * Returns a formatted mail line.
+   * @access public
+   * @return string
+   */
+  public function TextLine($value) {
+    return $value . $this->LE;
+  }
+
+  /////////////////////////////////////////////////
+  // CLASS METHODS, ATTACHMENTS
+  /////////////////////////////////////////////////
+
+  /**
+   * Adds an attachment from a path on the filesystem.
+   * Returns false if the file could not be found
+   * or accessed.
+   * @param string $path Path to the attachment.
+   * @param string $name Overrides the attachment name.
+   * @param string $encoding File encoding (see $Encoding).
+   * @param string $type File extension (MIME) type.
+   * @return bool
+   */
+  public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
+    try {
+      if ( !@is_file($path) ) {
+        throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
+      }
+      $filename = basename($path);
+      if ( $name == '' ) {
+        $name = $filename;
+      }
+
+      $this->attachment[] = array(
+        0 => $path,
+        1 => $filename,
+        2 => $name,
+        3 => $encoding,
+        4 => $type,
+        5 => false,  // isStringAttachment
+        6 => 'attachment',
+        7 => 0
+      );
+
+    } catch (phpmailerException $e) {
+      $this->SetError($e->getMessage());
+      if ($this->exceptions) {
+        throw $e;
+      }
+      echo $e->getMessage()."\n";
+      if ( $e->getCode() == self::STOP_CRITICAL ) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+  * Return the current array of attachments
+  * @return array
+  */
+  public function GetAttachments() {
+    return $this->attachment;
+  }
+
+  /**
+   * Attaches all fs, string, and binary attachments to the message.
+   * Returns an empty string on failure.
+   * @access private
+   * @return string
+   */
+  private function AttachAll() {
+    // Return text of body
+    $mime = array();
+    $cidUniq = array();
+    $incl = array();
+
+    // Add all attachments
+    foreach ($this->attachment as $attachment) {
+      // Check for string attachment
+      $bString = $attachment[5];
+      if ($bString) {
+        $string = $attachment[0];
+      } else {
+        $path = $attachment[0];
+      }
+
+      if (in_array($attachment[0], $incl)) { continue; }
+      $filename    = $attachment[1];
+      $name        = $attachment[2];
+      $encoding    = $attachment[3];
+      $type        = $attachment[4];
+      $disposition = $attachment[6];
+      $cid         = $attachment[7];
+      $incl[]      = $attachment[0];
+      if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
+      $cidUniq[$cid] = true;
+
+      $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
+      $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
+      $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
+
+      if($disposition == 'inline') {
+        $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
+      }
+
+      $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
+
+      // Encode as string attachment
+      if($bString) {
+        $mime[] = $this->EncodeString($string, $encoding);
+        if($this->IsError()) {
+          return '';
+        }
+        $mime[] = $this->LE.$this->LE;
+      } else {
+        $mime[] = $this->EncodeFile($path, $encoding);
+        if($this->IsError()) {
+          return '';
+        }
+        $mime[] = $this->LE.$this->LE;
+      }
+    }
+
+    $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
+
+    return join('', $mime);
+  }
+
+  /**
+   * Encodes attachment in requested format.
+   * Returns an empty string on failure.
+   * @param string $path The full path to the file
+   * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
+   * @see EncodeFile()
+   * @access private
+   * @return string
+   */
+  private function EncodeFile($path, $encoding = 'base64') {
+    try {
+      if (!is_readable($path)) {
+        throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
+      }
+      if (!function_exists('get_magic_quotes')) {
+        function get_magic_quotes() {
+          return false;
+        }
+      }
+      if (PHP_VERSION < 6
+                         AND $magic_quotes = get_magic_quotes_runtime()) {
+        set_magic_quotes_runtime(0);
+      }
+      $file_buffer  = file_get_contents($path);
+      $file_buffer  = $this->EncodeString($file_buffer, $encoding);
+      if (PHP_VERSION < 6 AND $magic_quotes) { set_magic_quotes_runtime($magic_quotes); }
+      return $file_buffer;
+    } catch (Exception $e) {
+      $this->SetError($e->getMessage());
+      return '';
+    }
+  }
+
+  /**
+   * Encodes string to requested format.
+   * Returns an empty string on failure.
+   * @param string $str The text to encode
+   * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
+   * @access public
+   * @return string
+   */
+  public function EncodeString ($str, $encoding = 'base64') {
+    $encoded = '';
+    switch(strtolower($encoding)) {
+      case 'base64':
+        $encoded = chunk_split(base64_encode($str), 76, $this->LE);
+        break;
+      case '7bit':
+      case '8bit':
+        $encoded = $this->FixEOL($str);
+        //Make sure it ends with a line break
+        if (substr($encoded, -(strlen($this->LE))) != $this->LE)
+          $encoded .= $this->LE;
+        break;
+      case 'binary':
+        $encoded = $str;
+        break;
+      case 'quoted-printable':
+        $encoded = $this->EncodeQP($str);
+        break;
+      default:
+        $this->SetError($this->Lang('encoding') . $encoding);
+        break;
+    }
+    return $encoded;
+  }
+
+  /**
+   * Encode a header string to best (shortest) of Q, B, quoted or none.
+   * @access public
+   * @return string
+   */
+  public function EncodeHeader($str, $position = 'text') {
+    $x = 0;
+
+    switch (strtolower($position)) {
+      case 'phrase':
+        if (!preg_match('/[\200-\377]/', $str)) {
+          // Can't use addslashes as we don't know what value has magic_quotes_sybase
+          $encoded = addcslashes($str, "\0..\37\177\\\"");
+          if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
+            return ($encoded);
+          } else {
+            return ("\"$encoded\"");
+          }
+        }
+        $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
+        break;
+      case 'comment':
+        $x = preg_match_all('/[()"]/', $str, $matches);
+        // Fall-through
+      case 'text':
+      default:
+        $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
+        break;
+    }
+
+    if ($x == 0) {
+      return ($str);
+    }
+
+    $maxlen = 75 - 7 - strlen($this->CharSet);
+    // Try to select the encoding which should produce the shortest output
+    if (strlen($str)/3 < $x) {
+      $encoding = 'B';
+      if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
+        // Use a custom function which correctly encodes and wraps long
+        // multibyte strings without breaking lines within a character
+        $encoded = $this->Base64EncodeWrapMB($str);
+      } else {
+        $encoded = base64_encode($str);
+        $maxlen -= $maxlen % 4;
+        $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
+      }
+    } else {
+      $encoding = 'Q';
+      $encoded = $this->EncodeQ($str, $position);
+      $encoded = $this->WrapText($encoded, $maxlen, true);
+      $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
+    }
+
+    $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
+    $encoded = trim(str_replace("\n", $this->LE, $encoded));
+
+    return $encoded;
+  }
+
+  /**
+   * Checks if a string contains multibyte characters.
+   * @access public
+   * @param string $str multi-byte text to wrap encode
+   * @return bool
+   */
+  public function HasMultiBytes($str) {
+    if (function_exists('mb_strlen')) {
+      return (strlen($str) > mb_strlen($str, $this->CharSet));
+    } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
+      return false;
+    }
+  }
+
+  /**
+   * Correctly encodes and wraps long multibyte strings for mail headers
+   * without breaking lines within a character.
+   * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
+   * @access public
+   * @param string $str multi-byte text to wrap encode
+   * @return string
+   */
+  public function Base64EncodeWrapMB($str) {
+    $start = "=?".$this->CharSet."?B?";
+    $end = "?=";
+    $encoded = "";
+
+    $mb_length = mb_strlen($str, $this->CharSet);
+    // Each line must have length <= 75, including $start and $end
+    $length = 75 - strlen($start) - strlen($end);
+    // Average multi-byte ratio
+    $ratio = $mb_length / strlen($str);
+    // Base64 has a 4:3 ratio
+    $offset = $avgLength = floor($length * $ratio * .75);
+
+    for ($i = 0; $i < $mb_length; $i += $offset) {
+      $lookBack = 0;
+
+      do {
+        $offset = $avgLength - $lookBack;
+        $chunk = mb_substr($str, $i, $offset, $this->CharSet);
+        $chunk = base64_encode($chunk);
+        $lookBack++;
+      }
+      while (strlen($chunk) > $length);
+
+      $encoded .= $chunk . $this->LE;
+    }
+
+    // Chomp the last linefeed
+    $encoded = substr($encoded, 0, -strlen($this->LE));
+    return $encoded;
+  }
+
+  /**
+  * Encode string to quoted-printable.
+  * Only uses standard PHP, slow, but will always work
+  * @access public
+  * @param string $string the text to encode
+  * @param integer $line_max Number of chars allowed on a line before wrapping
+  * @return string
+  */
+  public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
+    $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
+    $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
+    $eol = "\r\n";
+    $escape = '=';
+    $output = '';
+    while( list(, $line) = each($lines) ) {
+      $linlen = strlen($line);
+      $newline = '';
+      for($i = 0; $i < $linlen; $i++) {
+        $c = substr( $line, $i, 1 );
+        $dec = ord( $c );
+        if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
+          $c = '=2E';
+        }
+        if ( $dec == 32 ) {
+          if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
+            $c = '=20';
+          } else if ( $space_conv ) {
+            $c = '=20';
+          }
+        } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
+          $h2 = floor($dec/16);
+          $h1 = floor($dec%16);
+          $c = $escape.$hex[$h2].$hex[$h1];
+        }
+        if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
+          $output .= $newline.$escape.$eol; //  soft line break; " =\r\n" is okay
+          $newline = '';
+          // check if newline first character will be point or not
+          if ( $dec == 46 ) {
+            $c = '=2E';
+          }
+        }
+        $newline .= $c;
+      } // end of for
+      $output .= $newline.$eol;
+    } // end of while
+    return $output;
+  }
+
+  /**
+  * Encode string to RFC2045 (6.7) quoted-printable format
+  * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version
+  * Also results in same content as you started with after decoding
+  * @see EncodeQPphp()
+  * @access public
+  * @param string $string the text to encode
+  * @param integer $line_max Number of chars allowed on a line before wrapping
+  * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function
+  * @return string
+  * @author Marcus Bointon
+  */
+  public function EncodeQP($string, $line_max = 76, $space_conv = false) {
+    if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
+      return quoted_printable_encode($string);
+    }
+    $filters = stream_get_filters();
+    if (!in_array('convert.*', $filters)) { //Got convert stream filter?
+      return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation
+    }
+    $fp = fopen('php://temp/', 'r+');
+    $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks
+    $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
+    $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
+    fputs($fp, $string);
+    rewind($fp);
+    $out = stream_get_contents($fp);
+    stream_filter_remove($s);
+    $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange
+    fclose($fp);
+    return $out;
+  }
+
+  /**
+   * Encode string to q encoding.
+   * @link http://tools.ietf.org/html/rfc2047
+   * @param string $str the text to encode
+   * @param string $position Where the text is going to be used, see the RFC for what that means
+   * @access public
+   * @return string
+   */
+  public function EncodeQ ($str, $position = 'text') {
+    // There should not be any EOL in the string
+    $encoded = preg_replace('/[\r\n]*/', '', $str);
+
+    switch (strtolower($position)) {
+      case 'phrase':
+        $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+        break;
+      case 'comment':
+        $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
+      case 'text':
+      default:
+        // Replace every high ascii, control =, ? and _ characters
+        //TODO using /e (equivalent to eval()) is probably not a good idea
+        $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
+              "'='.sprintf('%02X', ord('\\1'))", $encoded);
+        break;
+    }
+
+    // Replace every spaces to _ (more readable than =20)
+    $encoded = str_replace(' ', '_', $encoded);
+
+    return $encoded;
+  }
+
+  /**
+   * Adds a string or binary attachment (non-filesystem) to the list.
+   * This method can be used to attach ascii or binary data,
+   * such as a BLOB record from a database.
+   * @param string $string String attachment data.
+   * @param string $filename Name of the attachment.
+   * @param string $encoding File encoding (see $Encoding).
+   * @param string $type File extension (MIME) type.
+   * @return void
+   */
+  public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
+    // Append to $attachment array
+    $this->attachment[] = array(
+      0 => $string,
+      1 => $filename,
+      2 => basename($filename),
+      3 => $encoding,
+      4 => $type,
+      5 => true,  // isStringAttachment
+      6 => 'attachment',
+      7 => 0
+    );
+  }
+
+  /**
+   * Adds an embedded attachment.  This can include images, sounds, and
+   * just about any other document.  Make sure to set the $type to an
+   * image type.  For JPEG images use "image/jpeg" and for GIF images
+   * use "image/gif".
+   * @param string $path Path to the attachment.
+   * @param string $cid Content ID of the attachment.  Use this to identify
+   *        the Id for accessing the image in an HTML form.
+   * @param string $name Overrides the attachment name.
+   * @param string $encoding File encoding (see $Encoding).
+   * @param string $type File extension (MIME) type.
+   * @return bool
+   */
+  public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
+
+    if ( !@is_file($path) ) {
+      $this->SetError($this->Lang('file_access') . $path);
+      return false;
+    }
+
+    $filename = basename($path);
+    if ( $name == '' ) {
+      $name = $filename;
+    }
+
+    // Append to $attachment array
+    $this->attachment[] = array(
+      0 => $path,
+      1 => $filename,
+      2 => $name,
+      3 => $encoding,
+      4 => $type,
+      5 => false,  // isStringAttachment
+      6 => 'inline',
+      7 => $cid
+    );
+
+    return true;
+  }
+
+  /**
+   * Returns true if an inline attachment is present.
+   * @access public
+   * @return bool
+   */
+  public function InlineImageExists() {
+    foreach($this->attachment as $attachment) {
+      if ($attachment[6] == 'inline') {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /////////////////////////////////////////////////
+  // CLASS METHODS, MESSAGE RESET
+  /////////////////////////////////////////////////
+
+  /**
+   * Clears all recipients assigned in the TO array.  Returns void.
+   * @return void
+   */
+  public function ClearAddresses() {
+    foreach($this->to as $to) {
+      unset($this->all_recipients[strtolower($to[0])]);
+    }
+    $this->to = array();
+  }
+
+  /**
+   * Clears all recipients assigned in the CC array.  Returns void.
+   * @return void
+   */
+  public function ClearCCs() {
+    foreach($this->cc as $cc) {
+      unset($this->all_recipients[strtolower($cc[0])]);
+    }
+    $this->cc = array();
+  }
+
+  /**
+   * Clears all recipients assigned in the BCC array.  Returns void.
+   * @return void
+   */
+  public function ClearBCCs() {
+    foreach($this->bcc as $bcc) {
+      unset($this->all_recipients[strtolower($bcc[0])]);
+    }
+    $this->bcc = array();
+  }
+
+  /**
+   * Clears all recipients assigned in the ReplyTo array.  Returns void.
+   * @return void
+   */
+  public function ClearReplyTos() {
+    $this->ReplyTo = array();
+  }
+
+  /**
+   * Clears all recipients assigned in the TO, CC and BCC
+   * array.  Returns void.
+   * @return void
+   */
+  public function ClearAllRecipients() {
+    $this->to = array();
+    $this->cc = array();
+    $this->bcc = array();
+    $this->all_recipients = array();
+  }
+
+  /**
+   * Clears all previously set filesystem, string, and binary
+   * attachments.  Returns void.
+   * @return void
+   */
+  public function ClearAttachments() {
+    $this->attachment = array();
+  }
+
+  /**
+   * Clears all custom headers.  Returns void.
+   * @return void
+   */
+  public function ClearCustomHeaders() {
+    $this->CustomHeader = array();
+  }
+
+  /////////////////////////////////////////////////
+  // CLASS METHODS, MISCELLANEOUS
+  /////////////////////////////////////////////////
+
+  /**
+   * Adds the error message to the error container.
+   * @access protected
+   * @return void
+   */
+  protected function SetError($msg) {
+    $this->error_count++;
+    if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
+      $lasterror = $this->smtp->getError();
+      if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
+        $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
+      }
+    }
+    $this->ErrorInfo = $msg;
+  }
+
+  /**
+   * Returns the proper RFC 822 formatted date.
+   * @access public
+   * @return string
+   * @static
+   */
+  public static function RFCDate() {
+    $tz = date('Z');
+    $tzs = ($tz < 0) ? '-' : '+';
+    $tz = abs($tz);
+    $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
+    $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
+
+    return $result;
+  }
+
+  /**
+   * Returns the server hostname or 'localhost.localdomain' if unknown.
+   * @access private
+   * @return string
+   */
+  private function ServerHostname() {
+    if (!empty($this->Hostname)) {
+      $result = $this->Hostname;
+    } elseif (isset($_SERVER['SERVER_NAME'])) {
+      $result = $_SERVER['SERVER_NAME'];
+    } else {
+      $result = 'localhost.localdomain';
+    }
+
+    return $result;
+  }
+
+  /**
+   * Returns a message in the appropriate language.
+   * @access private
+   * @return string
+   */
+  private function Lang($key) {
+    if(count($this->language) < 1) {
+      $this->SetLanguage('en'); // set the default language
+    }
+
+    if(isset($this->language[$key])) {
+      return $this->language[$key];
+    } else {
+      return 'Language string failed to load: ' . $key;
+    }
+  }
+
+  /**
+   * Returns true if an error occurred.
+   * @access public
+   * @return bool
+   */
+  public function IsError() {
+    return ($this->error_count > 0);
+  }
+
+  /**
+   * Changes every end of line from CR or LF to CRLF.
+   * @access private
+   * @return string
+   */
+  private function FixEOL($str) {
+    $str = str_replace("\r\n", "\n", $str);
+    $str = str_replace("\r", "\n", $str);
+    $str = str_replace("\n", $this->LE, $str);
+    return $str;
+  }
+
+  /**
+   * Adds a custom header.
+   * @access public
+   * @return void
+   */
+  public function AddCustomHeader($custom_header) {
+    $this->CustomHeader[] = explode(':', $custom_header, 2);
+  }
+
+  /**
+   * Evaluates the message and returns modifications for inline images and backgrounds
+   * @access public
+   * @return $message
+   */
+  public function MsgHTML($message, $basedir = '') {
+    preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
+    if(isset($images[2])) {
+      foreach($images[2] as $i => $url) {
+        // do not change urls for absolute images (thanks to corvuscorax)
+        if (!preg_match('#^[A-z]+://#',$url)) {
+          $filename = basename($url);
+          $directory = dirname($url);
+          ($directory == '.')?$directory='':'';
+          $cid = 'cid:' . md5($filename);
+          $ext = pathinfo($filename, PATHINFO_EXTENSION);
+          $mimeType  = self::_mime_types($ext);
+          if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
+          if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; }
+          if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
+            $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
+          }
+        }
+      }
+    }
+    $this->IsHTML(true);
+    $this->Body = $message;
+    $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
+    if (!empty($textMsg) && empty($this->AltBody)) {
+      $this->AltBody = html_entity_decode($textMsg);
+    }
+    if (empty($this->AltBody)) {
+      $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
+    }
+  }
+
+  /**
+   * Gets the MIME type of the embedded or inline image
+   * @param string File extension
+   * @access public
+   * @return string MIME type of ext
+   * @static
+   */
+  public static function _mime_types($ext = '') {
+    $mimes = array(
+      'hqx'   =>  'application/mac-binhex40',
+      'cpt'   =>  'application/mac-compactpro',
+      'doc'   =>  'application/msword',
+      'bin'   =>  'application/macbinary',
+      'dms'   =>  'application/octet-stream',
+      'lha'   =>  'application/octet-stream',
+      'lzh'   =>  'application/octet-stream',
+      'exe'   =>  'application/octet-stream',
+      'class' =>  'application/octet-stream',
+      'psd'   =>  'application/octet-stream',
+      'so'    =>  'application/octet-stream',
+      'sea'   =>  'application/octet-stream',
+      'dll'   =>  'application/octet-stream',
+      'oda'   =>  'application/oda',
+      'pdf'   =>  'application/pdf',
+      'ai'    =>  'application/postscript',
+      'eps'   =>  'application/postscript',
+      'ps'    =>  'application/postscript',
+      'smi'   =>  'application/smil',
+      'smil'  =>  'application/smil',
+      'mif'   =>  'application/vnd.mif',
+      'xls'   =>  'application/vnd.ms-excel',
+      'ppt'   =>  'application/vnd.ms-powerpoint',
+      'wbxml' =>  'application/vnd.wap.wbxml',
+      'wmlc'  =>  'application/vnd.wap.wmlc',
+      'dcr'   =>  'application/x-director',
+      'dir'   =>  'application/x-director',
+      'dxr'   =>  'application/x-director',
+      'dvi'   =>  'application/x-dvi',
+      'gtar'  =>  'application/x-gtar',
+      'php'   =>  'application/x-httpd-php',
+      'php4'  =>  'application/x-httpd-php',
+      'php3'  =>  'application/x-httpd-php',
+      'phtml' =>  'application/x-httpd-php',
+      'phps'  =>  'application/x-httpd-php-source',
+      'js'    =>  'application/x-javascript',
+      'swf'   =>  'application/x-shockwave-flash',
+      'sit'   =>  'application/x-stuffit',
+      'tar'   =>  'application/x-tar',
+      'tgz'   =>  'application/x-tar',
+      'xhtml' =>  'application/xhtml+xml',
+      'xht'   =>  'application/xhtml+xml',
+      'zip'   =>  'application/zip',
+      'mid'   =>  'audio/midi',
+      'midi'  =>  'audio/midi',
+      'mpga'  =>  'audio/mpeg',
+      'mp2'   =>  'audio/mpeg',
+      'mp3'   =>  'audio/mpeg',
+      'aif'   =>  'audio/x-aiff',
+      'aiff'  =>  'audio/x-aiff',
+      'aifc'  =>  'audio/x-aiff',
+      'ram'   =>  'audio/x-pn-realaudio',
+      'rm'    =>  'audio/x-pn-realaudio',
+      'rpm'   =>  'audio/x-pn-realaudio-plugin',
+      'ra'    =>  'audio/x-realaudio',
+      'rv'    =>  'video/vnd.rn-realvideo',
+      'wav'   =>  'audio/x-wav',
+      'bmp'   =>  'image/bmp',
+      'gif'   =>  'image/gif',
+      'jpeg'  =>  'image/jpeg',
+      'jpg'   =>  'image/jpeg',
+      'jpe'   =>  'image/jpeg',
+      'png'   =>  'image/png',
+      'tiff'  =>  'image/tiff',
+      'tif'   =>  'image/tiff',
+      'css'   =>  'text/css',
+      'html'  =>  'text/html',
+      'htm'   =>  'text/html',
+      'shtml' =>  'text/html',
+      'txt'   =>  'text/plain',
+      'text'  =>  'text/plain',
+      'log'   =>  'text/plain',
+      'rtx'   =>  'text/richtext',
+      'rtf'   =>  'text/rtf',
+      'xml'   =>  'text/xml',
+      'xsl'   =>  'text/xml',
+      'mpeg'  =>  'video/mpeg',
+      'mpg'   =>  'video/mpeg',
+      'mpe'   =>  'video/mpeg',
+      'qt'    =>  'video/quicktime',
+      'mov'   =>  'video/quicktime',
+      'avi'   =>  'video/x-msvideo',
+      'movie' =>  'video/x-sgi-movie',
+      'doc'   =>  'application/msword',
+      'word'  =>  'application/msword',
+      'xl'    =>  'application/excel',
+      'eml'   =>  'message/rfc822'
+    );
+    return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
+  }
+
+  /**
+  * Set (or reset) Class Objects (variables)
+  *
+  * Usage Example:
+  * $page->set('X-Priority', '3');
+  *
+  * @access public
+  * @param string $name Parameter Name
+  * @param mixed $value Parameter Value
+  * NOTE: will not work with arrays, there are no arrays to set/reset
+  * @todo Should this not be using __set() magic function?
+  */
+  public function set($name, $value = '') {
+    try {
+      if (isset($this->$name) ) {
+        $this->$name = $value;
+      } else {
+        throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
+      }
+    } catch (Exception $e) {
+      $this->SetError($e->getMessage());
+      if ($e->getCode() == self::STOP_CRITICAL) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Strips newlines to prevent header injection.
+   * @access public
+   * @param string $str String
+   * @return string
+   */
+  public function SecureHeader($str) {
+    $str = str_replace("\r", '', $str);
+    $str = str_replace("\n", '', $str);
+    return trim($str);
+  }
+
+  /**
+   * Set the private key file and password to sign the message.
+   *
+   * @access public
+   * @param string $key_filename Parameter File Name
+   * @param string $key_pass Password for private key
+   */
+  public function Sign($cert_filename, $key_filename, $key_pass) {
+    $this->sign_cert_file = $cert_filename;
+    $this->sign_key_file = $key_filename;
+    $this->sign_key_pass = $key_pass;
+  }
+
+  /**
+   * Set the private key file and password to sign the message.
+   *
+   * @access public
+   * @param string $key_filename Parameter File Name
+   * @param string $key_pass Password for private key
+   */
+  public function DKIM_QP($txt) {
+    $tmp="";
+    $line="";
+    for ($i=0;$i<strlen($txt);$i++) {
+      $ord=ord($txt[$i]);
+      if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
+        $line.=$txt[$i];
+      } else {
+        $line.="=".sprintf("%02X",$ord);
+      }
+    }
+    return $line;
+  }
+
+  /**
+   * Generate DKIM signature
+   *
+   * @access public
+   * @param string $s Header
+   */
+  public function DKIM_Sign($s) {
+    $privKeyStr = file_get_contents($this->DKIM_private);
+    if ($this->DKIM_passphrase!='') {
+      $privKey = openssl_pkey_get_private($privKeyStr,$this->DKIM_passphrase);
+    } else {
+      $privKey = $privKeyStr;
+    }
+    if (openssl_sign($s, $signature, $privKey)) {
+      return base64_encode($signature);
+    }
+  }
+
+  /**
+   * Generate DKIM Canonicalization Header
+   *
+   * @access public
+   * @param string $s Header
+   */
+  public function DKIM_HeaderC($s) {
+    $s=preg_replace("/\r\n\s+/"," ",$s);
+    $lines=explode("\r\n",$s);
+    foreach ($lines as $key=>$line) {
+      list($heading,$value)=explode(":",$line,2);
+      $heading=strtolower($heading);
+      $value=preg_replace("/\s+/"," ",$value) ; // Compress useless spaces
+      $lines[$key]=$heading.":".trim($value) ; // Don't forget to remove WSP around the value
+    }
+    $s=implode("\r\n",$lines);
+    return $s;
+  }
+
+  /**
+   * Generate DKIM Canonicalization Body
+   *
+   * @access public
+   * @param string $body Message Body
+   */
+  public function DKIM_BodyC($body) {
+    if ($body == '') return "\r\n";
+    // stabilize line endings
+    $body=str_replace("\r\n","\n",$body);
+    $body=str_replace("\n","\r\n",$body);
+    // END stabilize line endings
+    while (substr($body,strlen($body)-4,4) == "\r\n\r\n") {
+      $body=substr($body,0,strlen($body)-2);
+    }
+    return $body;
+  }
+
+  /**
+   * Create the DKIM header, body, as new header
+   *
+   * @access public
+   * @param string $headers_line Header lines
+   * @param string $subject Subject
+   * @param string $body Body
+   */
+  public function DKIM_Add($headers_line,$subject,$body) {
+    $DKIMsignatureType    = 'rsa-sha1'; // Signature & hash algorithms
+    $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
+    $DKIMquery            = 'dns/txt'; // Query method
+    $DKIMtime             = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
+    $subject_header       = "Subject: $subject";
+    $headers              = explode("\r\n",$headers_line);
+    foreach($headers as $header) {
+      if (strpos($header,'From:') === 0) {
+        $from_header=$header;
+      } elseif (strpos($header,'To:') === 0) {
+        $to_header=$header;
+      }
+    }
+    $from     = str_replace('|','=7C',$this->DKIM_QP($from_header));
+    $to       = str_replace('|','=7C',$this->DKIM_QP($to_header));
+    $subject  = str_replace('|','=7C',$this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
+    $body     = $this->DKIM_BodyC($body);
+    $DKIMlen  = strlen($body) ; // Length of body
+    $DKIMb64  = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
+    $ident    = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
+    $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
+                "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
+                "\th=From:To:Subject;\r\n".
+                "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
+                "\tz=$from\r\n".
+                "\t|$to\r\n".
+                "\t|$subject;\r\n".
+                "\tbh=" . $DKIMb64 . ";\r\n".
+                "\tb=";
+    $toSign   = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
+    $signed   = $this->DKIM_Sign($toSign);
+    return "X-PHPMAILER-DKIM: phpmailer.worxware.com\r\n".$dkimhdrs.$signed."\r\n";
+  }
+
+  protected function doCallback($isSent,$to,$cc,$bcc,$subject,$body) {
+    if (!empty($this->action_function) && function_exists($this->action_function)) {
+      $params = array($isSent,$to,$cc,$bcc,$subject,$body);
+      call_user_func_array($this->action_function,$params);
+    }
+  }
+}
+
+class phpmailerException extends Exception {
+  public function errorMessage() {
+    $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
+    return $errorMsg;
+  }
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/class.pop3.php b/www/plugins/facteur/phpmailer-php5/class.pop3.php
new file mode 100755 (executable)
index 0000000..f9fd3b2
--- /dev/null
@@ -0,0 +1,407 @@
+<?php
+/*~ class.pop3.php
+.---------------------------------------------------------------------------.
+|  Software: PHPMailer - PHP email class                                    |
+|   Version: 5.1                                                            |
+|   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
+|      Info: http://phpmailer.sourceforge.net                               |
+|   Support: http://sourceforge.net/projects/phpmailer/                     |
+| ------------------------------------------------------------------------- |
+|     Admin: Andy Prevost (project admininistrator)                         |
+|   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
+|          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
+|   Founder: Brent R. Matzelle (original founder)                           |
+| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
+| Copyright (c) 2001-2003, Brent R. Matzelle                                |
+| ------------------------------------------------------------------------- |
+|   License: Distributed under the Lesser General Public License (LGPL)     |
+|            http://www.gnu.org/copyleft/lesser.html                        |
+| This program is distributed in the hope that it will be useful - WITHOUT  |
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
+| FITNESS FOR A PARTICULAR PURPOSE.                                         |
+| ------------------------------------------------------------------------- |
+| We offer a number of paid services (www.codeworxtech.com):                |
+| - Web Hosting on highly optimized fast and secure servers                 |
+| - Technology Consulting                                                   |
+| - Oursourcing (highly qualified programmers and graphic designers)        |
+'---------------------------------------------------------------------------'
+*/
+
+/**
+ * PHPMailer - PHP POP Before SMTP Authentication Class
+ * NOTE: Designed for use with PHP version 5 and up
+ * @package PHPMailer
+ * @author Andy Prevost
+ * @author Marcus Bointon
+ * @copyright 2004 - 2009 Andy Prevost
+ * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
+ * @version $Id: class.pop3.php 444 2009-05-05 11:22:26Z coolbru $
+ */
+
+/**
+ * POP Before SMTP Authentication Class
+ * Version 5.0.0
+ *
+ * Author: Richard Davey (rich@corephp.co.uk)
+ * Modifications: Andy Prevost
+ * License: LGPL, see PHPMailer License
+ *
+ * Specifically for PHPMailer to allow POP before SMTP authentication.
+ * Does not yet work with APOP - if you have an APOP account, contact Richard Davey
+ * and we can test changes to this script.
+ *
+ * This class is based on the structure of the SMTP class originally authored by Chris Ryan
+ *
+ * This class is rfc 1939 compliant and implements all the commands
+ * required for POP3 connection, authentication and disconnection.
+ *
+ * @package PHPMailer
+ * @author Richard Davey
+ */
+
+class POP3 {
+  /**
+   * Default POP3 port
+   * @var int
+   */
+  public $POP3_PORT = 110;
+
+  /**
+   * Default Timeout
+   * @var int
+   */
+  public $POP3_TIMEOUT = 30;
+
+  /**
+   * POP3 Carriage Return + Line Feed
+   * @var string
+   */
+  public $CRLF = "\r\n";
+
+  /**
+   * Displaying Debug warnings? (0 = now, 1+ = yes)
+   * @var int
+   */
+  public $do_debug = 2;
+
+  /**
+   * POP3 Mail Server
+   * @var string
+   */
+  public $host;
+
+  /**
+   * POP3 Port
+   * @var int
+   */
+  public $port;
+
+  /**
+   * POP3 Timeout Value
+   * @var int
+   */
+  public $tval;
+
+  /**
+   * POP3 Username
+   * @var string
+   */
+  public $username;
+
+  /**
+   * POP3 Password
+   * @var string
+   */
+  public $password;
+
+  /////////////////////////////////////////////////
+  // PROPERTIES, PRIVATE AND PROTECTED
+  /////////////////////////////////////////////////
+
+  private $pop_conn;
+  private $connected;
+  private $error;     //  Error log array
+
+  /**
+   * Constructor, sets the initial values
+   * @access public
+   * @return POP3
+   */
+  public function __construct() {
+    $this->pop_conn  = 0;
+    $this->connected = false;
+    $this->error     = null;
+  }
+
+  /**
+   * Combination of public events - connect, login, disconnect
+   * @access public
+   * @param string $host
+   * @param integer $port
+   * @param integer $tval
+   * @param string $username
+   * @param string $password
+   */
+  public function Authorise ($host, $port = false, $tval = false, $username, $password, $debug_level = 0) {
+    $this->host = $host;
+
+    //  If no port value is passed, retrieve it
+    if ($port == false) {
+      $this->port = $this->POP3_PORT;
+    } else {
+      $this->port = $port;
+    }
+
+    //  If no port value is passed, retrieve it
+    if ($tval == false) {
+      $this->tval = $this->POP3_TIMEOUT;
+    } else {
+      $this->tval = $tval;
+    }
+
+    $this->do_debug = $debug_level;
+    $this->username = $username;
+    $this->password = $password;
+
+    //  Refresh the error log
+    $this->error = null;
+
+    //  Connect
+    $result = $this->Connect($this->host, $this->port, $this->tval);
+
+    if ($result) {
+      $login_result = $this->Login($this->username, $this->password);
+
+      if ($login_result) {
+        $this->Disconnect();
+
+        return true;
+      }
+
+    }
+
+    //  We need to disconnect regardless if the login succeeded
+    $this->Disconnect();
+
+    return false;
+  }
+
+  /**
+   * Connect to the POP3 server
+   * @access public
+   * @param string $host
+   * @param integer $port
+   * @param integer $tval
+   * @return boolean
+   */
+  public function Connect ($host, $port = false, $tval = 30) {
+    //  Are we already connected?
+    if ($this->connected) {
+      return true;
+    }
+
+    /*
+    On Windows this will raise a PHP Warning error if the hostname doesn't exist.
+    Rather than supress it with @fsockopen, let's capture it cleanly instead
+    */
+
+    set_error_handler(array(&$this, 'catchWarning'));
+
+    //  Connect to the POP3 server
+    $this->pop_conn = fsockopen($host,    //  POP3 Host
+                  $port,    //  Port #
+                  $errno,   //  Error Number
+                  $errstr,  //  Error Message
+                  $tval);   //  Timeout (seconds)
+
+    //  Restore the error handler
+    restore_error_handler();
+
+    //  Does the Error Log now contain anything?
+    if ($this->error && $this->do_debug >= 1) {
+      $this->displayErrors();
+    }
+
+    //  Did we connect?
+    if ($this->pop_conn == false) {
+      //  It would appear not...
+      $this->error = array(
+        'error' => "Failed to connect to server $host on port $port",
+        'errno' => $errno,
+        'errstr' => $errstr
+      );
+
+      if ($this->do_debug >= 1) {
+        $this->displayErrors();
+      }
+
+      return false;
+    }
+
+    //  Increase the stream time-out
+
+    //  Check for PHP 4.3.0 or later
+    if (version_compare(phpversion(), '5.0.0', 'ge')) {
+      stream_set_timeout($this->pop_conn, $tval, 0);
+    } else {
+      //  Does not work on Windows
+      if (substr(PHP_OS, 0, 3) !== 'WIN') {
+        socket_set_timeout($this->pop_conn, $tval, 0);
+      }
+    }
+
+    //  Get the POP3 server response
+    $pop3_response = $this->getResponse();
+
+    //  Check for the +OK
+    if ($this->checkResponse($pop3_response)) {
+    //  The connection is established and the POP3 server is talking
+    $this->connected = true;
+      return true;
+    }
+
+  }
+
+  /**
+   * Login to the POP3 server (does not support APOP yet)
+   * @access public
+   * @param string $username
+   * @param string $password
+   * @return boolean
+   */
+  public function Login ($username = '', $password = '') {
+    if ($this->connected == false) {
+      $this->error = 'Not connected to POP3 server';
+
+      if ($this->do_debug >= 1) {
+        $this->displayErrors();
+      }
+    }
+
+    if (empty($username)) {
+      $username = $this->username;
+    }
+
+    if (empty($password)) {
+      $password = $this->password;
+    }
+
+    $pop_username = "USER $username" . $this->CRLF;
+    $pop_password = "PASS $password" . $this->CRLF;
+
+    //  Send the Username
+    $this->sendString($pop_username);
+    $pop3_response = $this->getResponse();
+
+    if ($this->checkResponse($pop3_response)) {
+      //  Send the Password
+      $this->sendString($pop_password);
+      $pop3_response = $this->getResponse();
+
+      if ($this->checkResponse($pop3_response)) {
+        return true;
+      } else {
+        return false;
+      }
+    } else {
+      return false;
+    }
+  }
+
+  /**
+   * Disconnect from the POP3 server
+   * @access public
+   */
+  public function Disconnect () {
+    $this->sendString('QUIT');
+
+    fclose($this->pop_conn);
+  }
+
+  /////////////////////////////////////////////////
+  //  Private Methods
+  /////////////////////////////////////////////////
+
+  /**
+   * Get the socket response back.
+   * $size is the maximum number of bytes to retrieve
+   * @access private
+   * @param integer $size
+   * @return string
+   */
+  private function getResponse ($size = 128) {
+    $pop3_response = fgets($this->pop_conn, $size);
+
+    return $pop3_response;
+  }
+
+  /**
+   * Send a string down the open socket connection to the POP3 server
+   * @access private
+   * @param string $string
+   * @return integer
+   */
+  private function sendString ($string) {
+    $bytes_sent = fwrite($this->pop_conn, $string, strlen($string));
+
+    return $bytes_sent;
+  }
+
+  /**
+   * Checks the POP3 server response for +OK or -ERR
+   * @access private
+   * @param string $string
+   * @return boolean
+   */
+  private function checkResponse ($string) {
+    if (substr($string, 0, 3) !== '+OK') {
+      $this->error = array(
+        'error' => "Server reported an error: $string",
+        'errno' => 0,
+        'errstr' => ''
+      );
+
+      if ($this->do_debug >= 1) {
+        $this->displayErrors();
+      }
+
+      return false;
+    } else {
+      return true;
+    }
+
+  }
+
+  /**
+   * If debug is enabled, display the error message array
+   * @access private
+   */
+  private function displayErrors () {
+    echo '<pre>';
+
+    foreach ($this->error as $single_error) {
+      print_r($single_error);
+    }
+
+    echo '</pre>';
+  }
+
+  /**
+   * Takes over from PHP for the socket warning handler
+   * @access private
+   * @param integer $errno
+   * @param string $errstr
+   * @param string $errfile
+   * @param integer $errline
+   */
+  private function catchWarning ($errno, $errstr, $errfile, $errline) {
+    $this->error[] = array(
+      'error' => "Connecting to the POP3 server raised a PHP warning: ",
+      'errno' => $errno,
+      'errstr' => $errstr
+    );
+  }
+
+  //  End of class
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/class.smtp.php b/www/plugins/facteur/phpmailer-php5/class.smtp.php
new file mode 100755 (executable)
index 0000000..c2ca1cb
--- /dev/null
@@ -0,0 +1,814 @@
+<?php\r
+/*~ class.smtp.php\r
+.---------------------------------------------------------------------------.\r
+|  Software: PHPMailer - PHP email class                                    |\r
+|   Version: 5.1                                                            |\r
+|   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |\r
+|      Info: http://phpmailer.sourceforge.net                               |\r
+|   Support: http://sourceforge.net/projects/phpmailer/                     |\r
+| ------------------------------------------------------------------------- |\r
+|     Admin: Andy Prevost (project admininistrator)                         |\r
+|   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |\r
+|          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |\r
+|   Founder: Brent R. Matzelle (original founder)                           |\r
+| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |\r
+| Copyright (c) 2001-2003, Brent R. Matzelle                                |\r
+| ------------------------------------------------------------------------- |\r
+|   License: Distributed under the Lesser General Public License (LGPL)     |\r
+|            http://www.gnu.org/copyleft/lesser.html                        |\r
+| This program is distributed in the hope that it will be useful - WITHOUT  |\r
+| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |\r
+| FITNESS FOR A PARTICULAR PURPOSE.                                         |\r
+| ------------------------------------------------------------------------- |\r
+| We offer a number of paid services (www.codeworxtech.com):                |\r
+| - Web Hosting on highly optimized fast and secure servers                 |\r
+| - Technology Consulting                                                   |\r
+| - Oursourcing (highly qualified programmers and graphic designers)        |\r
+'---------------------------------------------------------------------------'\r
+*/\r
+\r
+/**\r
+ * PHPMailer - PHP SMTP email transport class\r
+ * NOTE: Designed for use with PHP version 5 and up\r
+ * @package PHPMailer\r
+ * @author Andy Prevost\r
+ * @author Marcus Bointon\r
+ * @copyright 2004 - 2008 Andy Prevost\r
+ * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)\r
+ * @version $Id: class.smtp.php 444 2009-05-05 11:22:26Z coolbru $\r
+ */\r
+\r
+/**\r
+ * SMTP is rfc 821 compliant and implements all the rfc 821 SMTP\r
+ * commands except TURN which will always return a not implemented\r
+ * error. SMTP also provides some utility methods for sending mail\r
+ * to an SMTP server.\r
+ * original author: Chris Ryan\r
+ */\r
+\r
+class SMTP {\r
+  /**\r
+   *  SMTP server port\r
+   *  @var int\r
+   */\r
+  public $SMTP_PORT = 25;\r
+\r
+  /**\r
+   *  SMTP reply line ending\r
+   *  @var string\r
+   */\r
+  public $CRLF = "\r\n";\r
+\r
+  /**\r
+   *  Sets whether debugging is turned on\r
+   *  @var bool\r
+   */\r
+  public $do_debug;       // the level of debug to perform\r
+\r
+  /**\r
+   *  Sets VERP use on/off (default is off)\r
+   *  @var bool\r
+   */\r
+  public $do_verp = false;\r
+\r
+  /////////////////////////////////////////////////\r
+  // PROPERTIES, PRIVATE AND PROTECTED\r
+  /////////////////////////////////////////////////\r
+\r
+  private $smtp_conn; // the socket to the server\r
+  private $error;     // error if any on the last call\r
+  private $helo_rply; // the reply the server sent to us for HELO\r
+\r
+  /**\r
+   * Initialize the class so that the data is in a known state.\r
+   * @access public\r
+   * @return void\r
+   */\r
+  public function __construct() {\r
+    $this->smtp_conn = 0;\r
+    $this->error = null;\r
+    $this->helo_rply = null;\r
+\r
+    $this->do_debug = 0;\r
+  }\r
+\r
+  /////////////////////////////////////////////////\r
+  // CONNECTION FUNCTIONS\r
+  /////////////////////////////////////////////////\r
+\r
+  /**\r
+   * Connect to the server specified on the port specified.\r
+   * If the port is not specified use the default SMTP_PORT.\r
+   * If tval is specified then a connection will try and be\r
+   * established with the server for that number of seconds.\r
+   * If tval is not specified the default is 30 seconds to\r
+   * try on the connection.\r
+   *\r
+   * SMTP CODE SUCCESS: 220\r
+   * SMTP CODE FAILURE: 421\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Connect($host, $port = 0, $tval = 30) {\r
+    // set the error val to null so there is no confusion\r
+    $this->error = null;\r
+\r
+    // make sure we are __not__ connected\r
+    if($this->connected()) {\r
+      // already connected, generate error\r
+      $this->error = array("error" => "Already connected to a server");\r
+      return false;\r
+    }\r
+\r
+    if(empty($port)) {\r
+      $port = $this->SMTP_PORT;\r
+    }\r
+\r
+    // connect to the smtp server\r
+    $this->smtp_conn = @fsockopen($host,    // the host of the server\r
+                                 $port,    // the port to use\r
+                                 $errno,   // error number if any\r
+                                 $errstr,  // error message if any\r
+                                 $tval);   // give up after ? secs\r
+    // verify we connected properly\r
+    if(empty($this->smtp_conn)) {\r
+      $this->error = array("error" => "Failed to connect to server",\r
+                           "errno" => $errno,\r
+                           "errstr" => $errstr);\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    // SMTP server can take longer to respond, give longer timeout for first read\r
+    // Windows does not have support for this timeout function\r
+    if(substr(PHP_OS, 0, 3) != "WIN")\r
+     socket_set_timeout($this->smtp_conn, $tval, 0);\r
+\r
+    // get any announcement\r
+    $announce = $this->get_lines();\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';\r
+    }\r
+\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Initiate a TLS communication with the server.\r
+   *\r
+   * SMTP CODE 220 Ready to start TLS\r
+   * SMTP CODE 501 Syntax error (no parameters allowed)\r
+   * SMTP CODE 454 TLS not available due to temporary reason\r
+   * @access public\r
+   * @return bool success\r
+   */\r
+  public function StartTLS() {\r
+    $this->error = null; # to avoid confusion\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array("error" => "Called StartTLS() without being connected");\r
+      return false;\r
+    }\r
+\r
+    fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 220) {\r
+      $this->error =\r
+         array("error"     => "STARTTLS not accepted from server",\r
+               "smtp_code" => $code,\r
+               "smtp_msg"  => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    // Begin encrypted connection\r
+    if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {\r
+      return false;\r
+    }\r
+\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Performs SMTP authentication.  Must be run after running the\r
+   * Hello() method.  Returns true if successfully authenticated.\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Authenticate($username, $password) {\r
+    // Start authentication\r
+    fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($code != 334) {\r
+      $this->error =\r
+        array("error" => "AUTH not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    // Send encoded username\r
+    fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($code != 334) {\r
+      $this->error =\r
+        array("error" => "Username not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    // Send encoded password\r
+    fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($code != 235) {\r
+      $this->error =\r
+        array("error" => "Password not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Returns true if connected to a server otherwise false\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Connected() {\r
+    if(!empty($this->smtp_conn)) {\r
+      $sock_status = socket_get_status($this->smtp_conn);\r
+      if($sock_status["eof"]) {\r
+        // the socket is valid but we are not connected\r
+        if($this->do_debug >= 1) {\r
+            echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";\r
+        }\r
+        $this->Close();\r
+        return false;\r
+      }\r
+      return true; // everything looks good\r
+    }\r
+    return false;\r
+  }\r
+\r
+  /**\r
+   * Closes the socket and cleans up the state of the class.\r
+   * It is not considered good to use this function without\r
+   * first trying to use QUIT.\r
+   * @access public\r
+   * @return void\r
+   */\r
+  public function Close() {\r
+    $this->error = null; // so there is no confusion\r
+    $this->helo_rply = null;\r
+    if(!empty($this->smtp_conn)) {\r
+      // close the connection and cleanup\r
+      fclose($this->smtp_conn);\r
+      $this->smtp_conn = 0;\r
+    }\r
+  }\r
+\r
+  /////////////////////////////////////////////////\r
+  // SMTP COMMANDS\r
+  /////////////////////////////////////////////////\r
+\r
+  /**\r
+   * Issues a data command and sends the msg_data to the server\r
+   * finializing the mail transaction. $msg_data is the message\r
+   * that is to be send with the headers. Each header needs to be\r
+   * on a single line followed by a <CRLF> with the message headers\r
+   * and the message body being seperated by and additional <CRLF>.\r
+   *\r
+   * Implements rfc 821: DATA <CRLF>\r
+   *\r
+   * SMTP CODE INTERMEDIATE: 354\r
+   *     [data]\r
+   *     <CRLF>.<CRLF>\r
+   *     SMTP CODE SUCCESS: 250\r
+   *     SMTP CODE FAILURE: 552,554,451,452\r
+   * SMTP CODE FAILURE: 451,554\r
+   * SMTP CODE ERROR  : 500,501,503,421\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Data($msg_data) {\r
+    $this->error = null; // so no confusion is caused\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array(\r
+              "error" => "Called Data() without being connected");\r
+      return false;\r
+    }\r
+\r
+    fputs($this->smtp_conn,"DATA" . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 354) {\r
+      $this->error =\r
+        array("error" => "DATA command not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    /* the server is ready to accept data!\r
+     * according to rfc 821 we should not send more than 1000\r
+     * including the CRLF\r
+     * characters on a single line so we will break the data up\r
+     * into lines by \r and/or \n then if needed we will break\r
+     * each of those into smaller lines to fit within the limit.\r
+     * in addition we will be looking for lines that start with\r
+     * a period '.' and append and additional period '.' to that\r
+     * line. NOTE: this does not count towards limit.\r
+     */\r
+\r
+    // normalize the line breaks so we know the explode works\r
+    $msg_data = str_replace("\r\n","\n",$msg_data);\r
+    $msg_data = str_replace("\r","\n",$msg_data);\r
+    $lines = explode("\n",$msg_data);\r
+\r
+    /* we need to find a good way to determine is headers are\r
+     * in the msg_data or if it is a straight msg body\r
+     * currently I am assuming rfc 822 definitions of msg headers\r
+     * and if the first field of the first line (':' sperated)\r
+     * does not contain a space then it _should_ be a header\r
+     * and we can process all lines before a blank "" line as\r
+     * headers.\r
+     */\r
+\r
+    $field = substr($lines[0],0,strpos($lines[0],":"));\r
+    $in_headers = false;\r
+    if(!empty($field) && !strstr($field," ")) {\r
+      $in_headers = true;\r
+    }\r
+\r
+    $max_line_length = 998; // used below; set here for ease in change\r
+\r
+    while(list(,$line) = @each($lines)) {\r
+      $lines_out = null;\r
+      if($line == "" && $in_headers) {\r
+        $in_headers = false;\r
+      }\r
+      // ok we need to break this line up into several smaller lines\r
+      while(strlen($line) > $max_line_length) {\r
+        $pos = strrpos(substr($line,0,$max_line_length)," ");\r
+\r
+        // Patch to fix DOS attack\r
+        if(!$pos) {\r
+          $pos = $max_line_length - 1;\r
+          $lines_out[] = substr($line,0,$pos);\r
+          $line = substr($line,$pos);\r
+        } else {\r
+          $lines_out[] = substr($line,0,$pos);\r
+          $line = substr($line,$pos + 1);\r
+        }\r
+\r
+        /* if processing headers add a LWSP-char to the front of new line\r
+         * rfc 822 on long msg headers\r
+         */\r
+        if($in_headers) {\r
+          $line = "\t" . $line;\r
+        }\r
+      }\r
+      $lines_out[] = $line;\r
+\r
+      // send the lines to the server\r
+      while(list(,$line_out) = @each($lines_out)) {\r
+        if(strlen($line_out) > 0)\r
+        {\r
+          if(substr($line_out, 0, 1) == ".") {\r
+            $line_out = "." . $line_out;\r
+          }\r
+        }\r
+        fputs($this->smtp_conn,$line_out . $this->CRLF);\r
+      }\r
+    }\r
+\r
+    // message data has been sent\r
+    fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 250) {\r
+      $this->error =\r
+        array("error" => "DATA not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Sends the HELO command to the smtp server.\r
+   * This makes sure that we and the server are in\r
+   * the same known state.\r
+   *\r
+   * Implements from rfc 821: HELO <SP> <domain> <CRLF>\r
+   *\r
+   * SMTP CODE SUCCESS: 250\r
+   * SMTP CODE ERROR  : 500, 501, 504, 421\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Hello($host = '') {\r
+    $this->error = null; // so no confusion is caused\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array(\r
+            "error" => "Called Hello() without being connected");\r
+      return false;\r
+    }\r
+\r
+    // if hostname for HELO was not specified send default\r
+    if(empty($host)) {\r
+      // determine appropriate default to send to server\r
+      $host = "localhost";\r
+    }\r
+\r
+    // Send extended hello first (RFC 2821)\r
+    if(!$this->SendHello("EHLO", $host)) {\r
+      if(!$this->SendHello("HELO", $host)) {\r
+        return false;\r
+      }\r
+    }\r
+\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Sends a HELO/EHLO command.\r
+   * @access private\r
+   * @return bool\r
+   */\r
+  private function SendHello($hello, $host) {\r
+    fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 250) {\r
+      $this->error =\r
+        array("error" => $hello . " not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    $this->helo_rply = $rply;\r
+\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Starts a mail transaction from the email address specified in\r
+   * $from. Returns true if successful or false otherwise. If True\r
+   * the mail transaction is started and then one or more Recipient\r
+   * commands may be called followed by a Data command.\r
+   *\r
+   * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>\r
+   *\r
+   * SMTP CODE SUCCESS: 250\r
+   * SMTP CODE SUCCESS: 552,451,452\r
+   * SMTP CODE SUCCESS: 500,501,421\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Mail($from) {\r
+    $this->error = null; // so no confusion is caused\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array(\r
+              "error" => "Called Mail() without being connected");\r
+      return false;\r
+    }\r
+\r
+    $useVerp = ($this->do_verp ? "XVERP" : "");\r
+    fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 250) {\r
+      $this->error =\r
+        array("error" => "MAIL not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Sends the quit command to the server and then closes the socket\r
+   * if there is no error or the $close_on_error argument is true.\r
+   *\r
+   * Implements from rfc 821: QUIT <CRLF>\r
+   *\r
+   * SMTP CODE SUCCESS: 221\r
+   * SMTP CODE ERROR  : 500\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Quit($close_on_error = true) {\r
+    $this->error = null; // so there is no confusion\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array(\r
+              "error" => "Called Quit() without being connected");\r
+      return false;\r
+    }\r
+\r
+    // send the quit command to the server\r
+    fputs($this->smtp_conn,"quit" . $this->CRLF);\r
+\r
+    // get any good-bye messages\r
+    $byemsg = $this->get_lines();\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';\r
+    }\r
+\r
+    $rval = true;\r
+    $e = null;\r
+\r
+    $code = substr($byemsg,0,3);\r
+    if($code != 221) {\r
+      // use e as a tmp var cause Close will overwrite $this->error\r
+      $e = array("error" => "SMTP server rejected quit command",\r
+                 "smtp_code" => $code,\r
+                 "smtp_rply" => substr($byemsg,4));\r
+      $rval = false;\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';\r
+      }\r
+    }\r
+\r
+    if(empty($e) || $close_on_error) {\r
+      $this->Close();\r
+    }\r
+\r
+    return $rval;\r
+  }\r
+\r
+  /**\r
+   * Sends the command RCPT to the SMTP server with the TO: argument of $to.\r
+   * Returns true if the recipient was accepted false if it was rejected.\r
+   *\r
+   * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>\r
+   *\r
+   * SMTP CODE SUCCESS: 250,251\r
+   * SMTP CODE FAILURE: 550,551,552,553,450,451,452\r
+   * SMTP CODE ERROR  : 500,501,503,421\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Recipient($to) {\r
+    $this->error = null; // so no confusion is caused\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array(\r
+              "error" => "Called Recipient() without being connected");\r
+      return false;\r
+    }\r
+\r
+    fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 250 && $code != 251) {\r
+      $this->error =\r
+        array("error" => "RCPT not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Sends the RSET command to abort and transaction that is\r
+   * currently in progress. Returns true if successful false\r
+   * otherwise.\r
+   *\r
+   * Implements rfc 821: RSET <CRLF>\r
+   *\r
+   * SMTP CODE SUCCESS: 250\r
+   * SMTP CODE ERROR  : 500,501,504,421\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Reset() {\r
+    $this->error = null; // so no confusion is caused\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array(\r
+              "error" => "Called Reset() without being connected");\r
+      return false;\r
+    }\r
+\r
+    fputs($this->smtp_conn,"RSET" . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 250) {\r
+      $this->error =\r
+        array("error" => "RSET failed",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Starts a mail transaction from the email address specified in\r
+   * $from. Returns true if successful or false otherwise. If True\r
+   * the mail transaction is started and then one or more Recipient\r
+   * commands may be called followed by a Data command. This command\r
+   * will send the message to the users terminal if they are logged\r
+   * in and send them an email.\r
+   *\r
+   * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>\r
+   *\r
+   * SMTP CODE SUCCESS: 250\r
+   * SMTP CODE SUCCESS: 552,451,452\r
+   * SMTP CODE SUCCESS: 500,501,502,421\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function SendAndMail($from) {\r
+    $this->error = null; // so no confusion is caused\r
+\r
+    if(!$this->connected()) {\r
+      $this->error = array(\r
+          "error" => "Called SendAndMail() without being connected");\r
+      return false;\r
+    }\r
+\r
+    fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);\r
+\r
+    $rply = $this->get_lines();\r
+    $code = substr($rply,0,3);\r
+\r
+    if($this->do_debug >= 2) {\r
+      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';\r
+    }\r
+\r
+    if($code != 250) {\r
+      $this->error =\r
+        array("error" => "SAML not accepted from server",\r
+              "smtp_code" => $code,\r
+              "smtp_msg" => substr($rply,4));\r
+      if($this->do_debug >= 1) {\r
+        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';\r
+      }\r
+      return false;\r
+    }\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * This is an optional command for SMTP that this class does not\r
+   * support. This method is here to make the RFC821 Definition\r
+   * complete for this class and __may__ be implimented in the future\r
+   *\r
+   * Implements from rfc 821: TURN <CRLF>\r
+   *\r
+   * SMTP CODE SUCCESS: 250\r
+   * SMTP CODE FAILURE: 502\r
+   * SMTP CODE ERROR  : 500, 503\r
+   * @access public\r
+   * @return bool\r
+   */\r
+  public function Turn() {\r
+    $this->error = array("error" => "This method, TURN, of the SMTP ".\r
+                                    "is not implemented");\r
+    if($this->do_debug >= 1) {\r
+      echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';\r
+    }\r
+    return false;\r
+  }\r
+\r
+  /**\r
+  * Get the current error\r
+  * @access public\r
+  * @return array\r
+  */\r
+  public function getError() {\r
+    return $this->error;\r
+  }\r
+\r
+  /////////////////////////////////////////////////\r
+  // INTERNAL FUNCTIONS\r
+  /////////////////////////////////////////////////\r
+\r
+  /**\r
+   * Read in as many lines as possible\r
+   * either before eof or socket timeout occurs on the operation.\r
+   * With SMTP we can tell if we have more lines to read if the\r
+   * 4th character is '-' symbol. If it is a space then we don't\r
+   * need to read anything else.\r
+   * @access private\r
+   * @return string\r
+   */\r
+  private function get_lines() {\r
+    $data = "";\r
+    while($str = @fgets($this->smtp_conn,515)) {\r
+      if($this->do_debug >= 4) {\r
+        echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';\r
+        echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';\r
+      }\r
+      $data .= $str;\r
+      if($this->do_debug >= 4) {\r
+        echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';\r
+      }\r
+      // if 4th character is a space, we are done reading, break the loop\r
+      if(substr($str,3,1) == " ") { break; }\r
+    }\r
+    return $data;\r
+  }\r
+\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ar.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ar.php
new file mode 100755 (executable)
index 0000000..b7c5057
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Arabic Version, UTF-8
+* by : bahjat al mostafa <bahjat983@hotmail.com>
+*/
+
+$PHPMAILER_LANG['authenticate']         = 'SMTP Error: لم نستطع تأكيد الهوية.';
+$PHPMAILER_LANG['connect_host']         = 'SMTP Error: لم نستطع الاتصال بمخدم SMTP.';
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Error: لم يتم قبول المعلومات .';
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';
+$PHPMAILER_LANG['encoding']             = 'ترميز غير معروف: ';
+$PHPMAILER_LANG['execute']              = 'لم أستطع تنفيذ : ';
+$PHPMAILER_LANG['file_access']          = 'لم نستطع الوصول للملف: ';
+$PHPMAILER_LANG['file_open']            = 'File Error: لم نستطع فتح الملف: ';
+$PHPMAILER_LANG['from_failed']          = 'البريد التالي لم نستطع ارسال البريد له : ';
+$PHPMAILER_LANG['instantiate']          = 'لم نستطع توفير خدمة البريد.';
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer غير مدعوم.';
+//$PHPMAILER_LANG['provide_address']      = 'You must provide at least one recipient email address.';
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Error: الأخطاء التالية ' .
+                                          'فشل في الارسال لكل من : ';
+$PHPMAILER_LANG['signing']              = 'خطأ في التوقيع: ';
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-br.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-br.php
new file mode 100755 (executable)
index 0000000..7d64ce4
--- /dev/null
@@ -0,0 +1,26 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Portuguese Version\r
+* By Paulo Henrique Garcia - paulo@controllerweb.com.br\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'Erro de SMTP: Não foi possível autenticar.';\r
+$PHPMAILER_LANG['connect_host']         = 'Erro de SMTP: Não foi possível conectar com o servidor SMTP.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'Erro de SMTP: Dados não aceitos.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Codificação desconhecida: ';\r
+$PHPMAILER_LANG['execute']              = 'Não foi possível executar: ';\r
+$PHPMAILER_LANG['file_access']          = 'Não foi possível acessar o arquivo: ';\r
+$PHPMAILER_LANG['file_open']            = 'Erro de Arquivo: Não foi possível abrir o arquivo: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Os endereços de rementente a seguir falharam: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Não foi possível instanciar a função mail.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não suportado.';\r
+$PHPMAILER_LANG['provide_address']      = 'Você deve fornecer pelo menos um endereço de destinatário de email.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'Erro de SMTP: Os endereços de destinatário a seguir falharam: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ca.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ca.php
new file mode 100644 (file)
index 0000000..1127567
--- /dev/null
@@ -0,0 +1,26 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Catalan Version\r
+* By Ivan: web AT microstudi DOT com\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'Error SMTP: No s\'hapogut autenticar.';\r
+$PHPMAILER_LANG['connect_host']         = 'Error SMTP: No es pot connectar al servidor SMTP.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'Error SMTP: Dades no acceptades.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Codificació desconeguda: ';\r
+$PHPMAILER_LANG['execute']              = 'No es pot executar: ';\r
+$PHPMAILER_LANG['file_access']          = 'No es pot accedir a l\'arxiu: ';\r
+$PHPMAILER_LANG['file_open']            = 'Error d\'Arxiu: No es pot obrir l\'arxiu: ';\r
+$PHPMAILER_LANG['from_failed']          = 'La(s) següent(s) adreces de remitent han fallat: ';\r
+$PHPMAILER_LANG['instantiate']          = 'No s\'ha pogut crear una instància de la funció Mail.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no està suportat';\r
+$PHPMAILER_LANG['provide_address']      = 'S\'ha de proveir almenys una adreça d\'email com a destinatari.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'Error SMTP: Els següents destinataris han fallat: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ch.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ch.php
new file mode 100755 (executable)
index 0000000..31ebd86
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Chinese Version
+* By LiuXin: www.80x86.cn/blog/
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'SMTP 错误:身份验证失败。';
+$PHPMAILER_LANG['connect_host'] = 'SMTP 错误: 不能连接SMTP主机。';
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 错误: 数据不可接受。';
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';
+$PHPMAILER_LANG['encoding'] = '未知编码:';
+$PHPMAILER_LANG['execute'] = '不能执行: ';
+$PHPMAILER_LANG['file_access'] = '不能访问文件:';
+$PHPMAILER_LANG['file_open'] = '文件错误:不能打开文件:';
+$PHPMAILER_LANG['from_failed'] = '下面的发送地址邮件发送失败了: ';
+$PHPMAILER_LANG['instantiate'] = '不能实现mail方法。';
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['mailer_not_supported'] = ' 您所选择的发送邮件的方法并不支持。';
+$PHPMAILER_LANG['provide_address'] = '您必须提供至少一个 收信人的email地址。';
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误: 下面的 收件人失败了: ';
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-cz.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-cz.php
new file mode 100755 (executable)
index 0000000..f9589ca
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Czech Version\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP Error: Chyba autentikace.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP Error: Nelze navázat spojení se SMTP serverem.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Error: Data nebyla pøijata';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Neznámé kódování: ';\r
+$PHPMAILER_LANG['execute']              = 'Nelze provést: ';\r
+$PHPMAILER_LANG['file_access']          = 'Soubor nenalezen: ';\r
+$PHPMAILER_LANG['file_open']            = 'File Error: Nelze otevøít soubor pro ètení: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Následující adresa From je nesprávná: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Nelze vytvoøit instanci emailové funkce.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailový klient není podporován.';\r
+$PHPMAILER_LANG['provide_address']      = 'Musíte zadat alespoò jednu emailovou adresu pøíjemce.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Error: Adresy pøíjemcù nejsou správné ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-de.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-de.php
new file mode 100755 (executable)
index 0000000..165a86f
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* German Version\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP Fehler: Authentifizierung fehlgeschlagen.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP Fehler: Konnte keine Verbindung zum SMTP-Host herstellen.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Fehler: Daten werden nicht akzeptiert.';\r
+$PHPMAILER_LANG['empty_message']        = 'E-Mail Inhalt ist leer.';\r
+$PHPMAILER_LANG['encoding']             = 'Unbekanntes Encoding-Format: ';\r
+$PHPMAILER_LANG['execute']              = 'Konnte folgenden Befehl nicht ausführen: ';\r
+$PHPMAILER_LANG['file_access']          = 'Zugriff auf folgende Datei fehlgeschlagen: ';\r
+$PHPMAILER_LANG['file_open']            = 'Datei Fehler: konnte folgende Datei nicht öffnen: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Die folgende Absenderadresse ist nicht korrekt: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Mail Funktion konnte nicht initialisiert werden.';\r
+$PHPMAILER_LANG['invalid_email']        = 'E-Mail wird nicht gesendet, die Adresse ist ungültig.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wird nicht unterstützt.';\r
+$PHPMAILER_LANG['provide_address']      = 'Bitte geben Sie mindestens eine Empfänger E-Mailadresse an.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Fehler: Die folgenden Empfänger sind nicht korrekt: ';\r
+$PHPMAILER_LANG['signing']              = 'Fehler beim Signieren: ';\r
+$PHPMAILER_LANG['smtp_connect_failed']  = 'Verbindung zu SMTP Server fehlgeschlagen.';\r
+$PHPMAILER_LANG['smtp_error']           = 'Fehler vom SMTP Server: ';\r
+$PHPMAILER_LANG['variable_set']         = 'Kann Variable nicht setzen oder zurücksetzen: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-dk.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-dk.php
new file mode 100644 (file)
index 0000000..59b58c0
--- /dev/null
@@ -0,0 +1,26 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Danish Version\r
+* Author: Mikael Stokkebro <info@stokkebro.dk>\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP fejl: Kunne ikke logge på.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP fejl: Kunne ikke tilslutte SMTP serveren.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP fejl: Data kunne ikke accepteres.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Ukendt encode-format: ';\r
+$PHPMAILER_LANG['execute']              = 'Kunne ikke køre: ';\r
+$PHPMAILER_LANG['file_access']          = 'Ingen adgang til fil: ';\r
+$PHPMAILER_LANG['file_open']            = 'Fil fejl: Kunne ikke åbne filen: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Følgende afsenderadresse er forkert: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Kunne ikke initialisere email funktionen.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer understøttes ikke.';\r
+$PHPMAILER_LANG['provide_address']      = 'Du skal indtaste mindst en modtagers emailadresse.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP fejl: Følgende modtagere er forkerte: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-en.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-en.php
new file mode 100755 (executable)
index 0000000..f7d4286
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+/**
+ * PHPMailer language file.
+ * English Version
+ */
+
+$PHPMAILER_LANG = array();
+
+$PHPMAILER_LANG["provide_address"]      = 'You must provide at least one ' .
+                                          'recipient email address.';
+$PHPMAILER_LANG["mailer_not_supported"] = ' mailer is not supported.';
+$PHPMAILER_LANG["execute"]              = 'Could not execute: ';
+$PHPMAILER_LANG["instantiate"]          = 'Could not instantiate mail function.';
+$PHPMAILER_LANG["authenticate"]         = 'SMTP Error: Could not authenticate.';
+$PHPMAILER_LANG["from_failed"]          = 'The following From address failed: ';
+$PHPMAILER_LANG["recipients_failed"]    = 'SMTP Error: The following ' .
+                                          'recipients failed: ';
+$PHPMAILER_LANG["data_not_accepted"]    = 'SMTP Error: Data not accepted.';
+$PHPMAILER_LANG["connect_host"]         = 'SMTP Error: Could not connect to SMTP host.';
+$PHPMAILER_LANG["file_access"]          = 'Could not access file: ';
+$PHPMAILER_LANG["file_open"]            = 'File Error: Could not open file: ';
+$PHPMAILER_LANG["encoding"]             = 'Unknown encoding: ';
+$PHPMAILER_LANG["signing"]              = 'Signing Error: ';
+
+?>
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-es.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-es.php
new file mode 100755 (executable)
index 0000000..0b69825
--- /dev/null
@@ -0,0 +1,26 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Spanish version\r
+* Versión en español\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'Error SMTP: No se pudo autentificar.';\r
+$PHPMAILER_LANG['connect_host']         = 'Error SMTP: No puedo conectar al servidor SMTP.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'Error SMTP: Datos no aceptados.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Codificación desconocida: ';\r
+$PHPMAILER_LANG['execute']              = 'No puedo ejecutar: ';\r
+$PHPMAILER_LANG['file_access']          = 'No puedo acceder al archivo: ';\r
+$PHPMAILER_LANG['file_open']            = 'Error de Archivo: No puede abrir el archivo: ';\r
+$PHPMAILER_LANG['from_failed']          = 'La(s) siguiente(s) direcciones de remitente fallaron: ';\r
+$PHPMAILER_LANG['instantiate']          = 'No pude crear una instancia de la función Mail.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no está soportado.';\r
+$PHPMAILER_LANG['provide_address']      = 'Debe proveer al menos una dirección de email como destinatario.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'Error SMTP: Los siguientes destinatarios fallaron: ';\r
+$PHPMAILER_LANG['signing']              = 'Error al firmar: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-et.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-et.php
new file mode 100755 (executable)
index 0000000..cf61779
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Estonian Version
+* By Indrek Päri
+*/
+
+$PHPMAILER_LANG['authenticate']         = 'SMTP Viga: Autoriseerimise viga.';
+$PHPMAILER_LANG['connect_host']         = 'SMTP Viga: Ei õnnestunud luua ühendust SMTP serveriga.';
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Viga: Vigased andmed.';
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';
+$PHPMAILER_LANG['encoding']             = 'Tundmatu Unknown kodeering: ';
+$PHPMAILER_LANG['execute']              = 'Tegevus ebaõnnestus: ';
+$PHPMAILER_LANG['file_access']          = 'Pole piisavalt õiguseid järgneva faili avamiseks: ';
+$PHPMAILER_LANG['file_open']            = 'Faili Viga: Faili avamine ebaõnnestus: ';
+$PHPMAILER_LANG['from_failed']          = 'Järgnev saatja e-posti aadress on vigane: ';
+$PHPMAILER_LANG['instantiate']          = 'mail funktiooni käivitamine ebaõnnestus.';
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['provide_address']      = 'Te peate määrama vähemalt ühe saaja e-posti aadressi.';
+$PHPMAILER_LANG['mailer_not_supported'] = ' maileri tugi puudub.';
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Viga: Järgnevate saajate e-posti aadressid on vigased: ';
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fi.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fi.php
new file mode 100644 (file)
index 0000000..6d7dcce
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Finnish Version\r
+* By Jyry Kuukanen\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP-virhe: käyttäjätunnistus epäonnistui.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP-virhe: yhteys palvelimeen ei onnistu.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP-virhe: data on virheellinen.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Tuntematon koodaustyyppi: ';\r
+$PHPMAILER_LANG['execute']              = 'Suoritus epäonnistui: ';\r
+$PHPMAILER_LANG['file_access']          = 'Seuraavaan tiedostoon ei ole oikeuksia: ';\r
+$PHPMAILER_LANG['file_open']            = 'Tiedostovirhe: Ei voida avata tiedostoa: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Seuraava lähettäjän osoite on virheellinen: ';\r
+$PHPMAILER_LANG['instantiate']          = 'mail-funktion luonti epäonnistui.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = 'postivälitintyyppiä ei tueta.';\r
+$PHPMAILER_LANG['provide_address']      = 'Aseta vähintään yksi vastaanottajan sähk&ouml;postiosoite.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP-virhe: seuraava vastaanottaja osoite on virheellinen.';\r
+$PHPMAILER_LANG['encoding']             = 'Tuntematon koodaustyyppi: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fo.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fo.php
new file mode 100644 (file)
index 0000000..704c477
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Faroese Version [language of the Faroe Islands, a Danish dominion]\r
+* This file created: 11-06-2004\r
+* Supplied by Dávur Sørensen [www.profo-webdesign.dk]\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP feilur: Kundi ikki góðkenna.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP feilur: Kundi ikki knýta samband við SMTP vert.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP feilur: Data ikki góðkent.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Ókend encoding: ';\r
+$PHPMAILER_LANG['execute']              = 'Kundi ikki útføra: ';\r
+$PHPMAILER_LANG['file_access']          = 'Kundi ikki tilganga fílu: ';\r
+$PHPMAILER_LANG['file_open']            = 'Fílu feilur: Kundi ikki opna fílu: ';\r
+$PHPMAILER_LANG['from_failed']          = 'fylgjandi Frá/From adressa miseydnaðist: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Kuni ikki instantiera mail funktión.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' er ikki supporterað.';\r
+$PHPMAILER_LANG['provide_address']      = 'Tú skal uppgeva minst móttakara-emailadressu(r).';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Feilur: Fylgjandi móttakarar miseydnaðust: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fr.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-fr.php
new file mode 100755 (executable)
index 0000000..52e9ae2
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* French Version\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'Erreur SMTP : Echec de l\'authentification.';\r
+$PHPMAILER_LANG['connect_host']         = 'Erreur SMTP : Impossible de se connecter au serveur SMTP.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'Erreur SMTP : Données incorrects.';\r
+$PHPMAILER_LANG['empty_message']        = 'Corps de message vide';\r
+$PHPMAILER_LANG['encoding']             = 'Encodage inconnu : ';\r
+$PHPMAILER_LANG['execute']              = 'Impossible de lancer l\'exécution : ';\r
+$PHPMAILER_LANG['file_access']          = 'Impossible d\'accéder au fichier : ';\r
+$PHPMAILER_LANG['file_open']            = 'Erreur Fichier : ouverture impossible : ';\r
+$PHPMAILER_LANG['from_failed']          = 'L\'adresse d\'expéditeur suivante a échouée : ';\r
+$PHPMAILER_LANG['instantiate']          = 'Impossible d\'instancier la fonction mail.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' client de messagerie non supporté.';\r
+$PHPMAILER_LANG['provide_address']      = 'Vous devez fournir au moins une adresse de destinataire.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'Erreur SMTP : Les destinataires suivants sont en erreur : ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-hu.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-hu.php
new file mode 100644 (file)
index 0000000..a266484
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Hungarian Version\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP Hiba: Sikertelen autentikáció.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP Hiba: Nem tudtam csatlakozni az SMTP host-hoz.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Hiba: Nem elfogadható adat.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Ismeretlen kódolás: ';\r
+$PHPMAILER_LANG['execute']              = 'Nem tudtam végrehajtani: ';\r
+$PHPMAILER_LANG['file_access']          = 'Nem sikerült elérni a következõ fájlt: ';\r
+$PHPMAILER_LANG['file_open']            = 'Fájl Hiba: Nem sikerült megnyitni a következõ fájlt: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Az alábbi Feladó cím hibás: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Nem sikerült példányosítani a mail funkciót.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address']      = 'Meg kell adnod legalább egy címzett email címet.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' levelezõ nem támogatott.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Hiba: Az alábbi címzettek hibásak: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-it.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-it.php
new file mode 100755 (executable)
index 0000000..59bf4fb
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Italian version\r
+* @package PHPMailer\r
+* @author Ilias Bartolini <brain79@inwind.it>\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP Error: Impossibile autenticarsi.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP Error: Impossibile connettersi all\'host SMTP.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Error: Data non accettati dal server.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Encoding set dei caratteri sconosciuto: ';\r
+$PHPMAILER_LANG['execute']              = 'Impossibile eseguire l\'operazione: ';\r
+$PHPMAILER_LANG['file_access']          = 'Impossibile accedere al file: ';\r
+$PHPMAILER_LANG['file_open']            = 'File Error: Impossibile aprire il file: ';\r
+$PHPMAILER_LANG['from_failed']          = 'I seguenti indirizzi mittenti hanno generato errore: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Impossibile istanziare la funzione mail';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address']      = 'Deve essere fornito almeno un indirizzo ricevente';\r
+$PHPMAILER_LANG['mailer_not_supported'] = 'Mailer non supportato';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Error: I seguenti indirizzi destinatari hanno generato errore: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ja.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ja.php
new file mode 100644 (file)
index 0000000..66da1b6
--- /dev/null
@@ -0,0 +1,26 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Japanese Version\r
+* By Mitsuhiro Yoshida - http://mitstek.com/\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate'] = 'SMTPエラー: 認証できませんでした。';\r
+$PHPMAILER_LANG['connect_host'] = 'SMTPエラー: SMTPホストに接続できませんでした。';\r
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTPエラー: データが受け付けられませんでした。';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding'] = '不明なエンコーディング: ';\r
+$PHPMAILER_LANG['execute'] = '実行できませんでした: ';\r
+$PHPMAILER_LANG['file_access'] = 'ファイルにアクセスできません: ';\r
+$PHPMAILER_LANG['file_open'] = 'ファイルエラー: ファイルを開けません: ';\r
+$PHPMAILER_LANG['from_failed'] = '次のFromアドレスに間違いがあります: ';\r
+$PHPMAILER_LANG['instantiate'] = 'メール関数が正常に動作しませんでした。';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address'] = '少なくとも1つメールアドレスを 指定する必要があります。';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' メーラーがサポートされていません。';\r
+$PHPMAILER_LANG['recipients_failed'] = 'SMTPエラー: 次の受信者アドレスに 間違いがあります: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-nl.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-nl.php
new file mode 100755 (executable)
index 0000000..355dcdc
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Dutch Version\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP Fout: authenticatie mislukt.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP Fout: Kon niet verbinden met SMTP host.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Fout: Data niet geaccepteerd.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Onbekende codering: ';\r
+$PHPMAILER_LANG['execute']              = 'Kon niet uitvoeren: ';\r
+$PHPMAILER_LANG['file_access']          = 'Kreeg geen toegang tot bestand: ';\r
+$PHPMAILER_LANG['file_open']            = 'Bestandsfout: Kon bestand niet openen: ';\r
+$PHPMAILER_LANG['from_failed']          = 'De volgende afzender adressen zijn mislukt: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Kon mail functie niet initialiseren.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address']      = 'Er moet tenmiste één ontvanger emailadres opgegeven worden.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer wordt niet ondersteund.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Fout: De volgende ontvangers zijn mislukt: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-no.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-no.php
new file mode 100755 (executable)
index 0000000..bf2f84e
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Norwegian Version\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP Feil: Kunne ikke authentisere.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP Feil: Kunne ikke koble til SMTP host.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Feil: Data ble ikke akseptert.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Ukjent encoding: ';\r
+$PHPMAILER_LANG['execute']              = 'Kunne ikke utføre: ';\r
+$PHPMAILER_LANG['file_access']          = 'Kunne ikke få tilgang til filen: ';\r
+$PHPMAILER_LANG['file_open']            = 'Fil feil: Kunne ikke åpne filen: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Følgende Fra feilet: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Kunne ikke instantiate mail funksjonen.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address']      = 'Du må ha med minst en mottager adresse.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer er ikke supportert.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Feil: Følgende mottagere feilet: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-pl.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-pl.php
new file mode 100644 (file)
index 0000000..e8bd512
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Polish Version\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate'] = 'Błąd SMTP: Nie można przeprowadzić autentykacji.';\r
+$PHPMAILER_LANG['connect_host'] = 'Błąd SMTP: Nie można połączyć się z wybranym hostem.';\r
+$PHPMAILER_LANG['data_not_accepted'] = 'Błąd SMTP: Dane nie zostały przyjęte.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding'] = 'Nieznany sposób kodowania znaków: ';\r
+$PHPMAILER_LANG['execute'] = 'Nie można uruchomić: ';\r
+$PHPMAILER_LANG['file_access'] = 'Brak dostępu do pliku: ';\r
+$PHPMAILER_LANG['file_open'] = 'Nie można otworzyć pliku: ';\r
+$PHPMAILER_LANG['from_failed'] = 'Następujący adres Nadawcy jest jest nieprawidłowy: ';\r
+$PHPMAILER_LANG['instantiate'] = 'Nie można wywołać funkcji mail(). Sprawdź konfigurację serwera.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address'] = 'Należy podać prawidłowy adres email Odbiorcy.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = 'Wybrana metoda wysyłki wiadomości nie jest obsługiwana.';\r
+$PHPMAILER_LANG['recipients_failed'] = 'Błąd SMTP: Następujący odbiorcy są nieprawidłowi: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ro.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ro.php
new file mode 100644 (file)
index 0000000..17cddb7
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Romanian Version\r
+* @package PHPMailer\r
+* @author Catalin Constantin <catalin@dazoot.ro>\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'Eroare SMTP: Nu a functionat autentificarea.';\r
+$PHPMAILER_LANG['connect_host']         = 'Eroare SMTP: Nu m-am putut conecta la adresa SMTP.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'Eroare SMTP: Continutul mailului nu a fost acceptat.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Encodare necunoscuta: ';\r
+$PHPMAILER_LANG['execute']              = 'Nu pot executa:  ';\r
+$PHPMAILER_LANG['file_access']          = 'Nu pot accesa fisierul: ';\r
+$PHPMAILER_LANG['file_open']            = 'Eroare de fisier: Nu pot deschide fisierul: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Urmatoarele adrese From au dat eroare: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Nu am putut instantia functia mail.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nu este suportat.';\r
+$PHPMAILER_LANG['provide_address']      = 'Trebuie sa adaugati cel putin un recipient (adresa de mail).';\r
+$PHPMAILER_LANG['recipients_failed']    = 'Eroare SMTP: Urmatoarele adrese de mail au dat eroare: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ru.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-ru.php
new file mode 100644 (file)
index 0000000..295a56e
--- /dev/null
@@ -0,0 +1,25 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Russian Version by Alexey Chumakov <alex@chumakov.ru>\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'Ошибка SMTP: ошибка авторизации.';\r
+$PHPMAILER_LANG['connect_host']         = 'Ошибка SMTP: не удается подключиться к серверу SMTP.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'Ошибка SMTP: данные не приняты.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Неизвестный вид кодировки: ';\r
+$PHPMAILER_LANG['execute']              = 'Невозможно выполнить команду: ';\r
+$PHPMAILER_LANG['file_access']          = 'Нет доступа к файлу: ';\r
+$PHPMAILER_LANG['file_open']            = 'Файловая ошибка: не удается открыть файл: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Неверный адрес отправителя: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Невозможно запустить функцию mail.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address']      = 'Пожалуйста, введите хотя бы один адрес e-mail получателя.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' - почтовый сервер не поддерживается.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'Ошибка SMTP: отправка по следующим адресам получателей не удалась: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-se.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-se.php
new file mode 100755 (executable)
index 0000000..d459667
--- /dev/null
@@ -0,0 +1,26 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Swedish Version\r
+* Author: Johan Linnér <johan@linner.biz>\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP fel: Kunde inte autentisera.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP fel: Kunde inte ansluta till SMTP-server.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP fel: Data accepterades inte.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Okänt encode-format: ';\r
+$PHPMAILER_LANG['execute']              = 'Kunde inte köra: ';\r
+$PHPMAILER_LANG['file_access']          = 'Ingen åtkomst till fil: ';\r
+$PHPMAILER_LANG['file_open']            = 'Fil fel: Kunde inte öppna fil: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Följande avsändaradress är felaktig: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Kunde inte initiera e-postfunktion.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address']      = 'Du måste ange minst en mottagares e-postadress.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailer stöds inte.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP fel: Följande mottagare är felaktig: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-tr.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-tr.php
new file mode 100755 (executable)
index 0000000..8a069d1
--- /dev/null
@@ -0,0 +1,27 @@
+<?php\r
+/**\r
+* PHPMailer language file: refer to English translation for definitive list\r
+* Turkish version\r
+* Türkçe Versiyonu\r
+* ÝZYAZILIM - Elçin Özel - Can Yýlmaz - Mehmet Benlioðlu\r
+*/\r
+\r
+$PHPMAILER_LANG['authenticate']         = 'SMTP Hatasý: Doðrulanamýyor.';\r
+$PHPMAILER_LANG['connect_host']         = 'SMTP Hatasý: SMTP hosta baðlanýlamýyor.';\r
+$PHPMAILER_LANG['data_not_accepted']    = 'SMTP Hatasý: Veri kabul edilmedi.';\r
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';\r
+$PHPMAILER_LANG['encoding']             = 'Bilinmeyen þifreleme: ';\r
+$PHPMAILER_LANG['execute']              = 'Çalýþtýrýlamýyor: ';\r
+$PHPMAILER_LANG['file_access']          = 'Dosyaya eriþilemiyor: ';\r
+$PHPMAILER_LANG['file_open']            = 'Dosya Hatasý: Dosya açýlamýyor: ';\r
+$PHPMAILER_LANG['from_failed']          = 'Baþarýsýz olan gönderici adresi: ';\r
+$PHPMAILER_LANG['instantiate']          = 'Örnek mail fonksiyonu yaratýlamadý.';\r
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';\r
+$PHPMAILER_LANG['provide_address']      = 'En az bir tane mail adresi belirtmek zorundasýnýz alýcýnýn email adresi.';\r
+$PHPMAILER_LANG['mailer_not_supported'] = ' mailler desteklenmemektedir.';\r
+$PHPMAILER_LANG['recipients_failed']    = 'SMTP Hatasý: alýcýlara ulaþmadý: ';\r
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';\r
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';\r
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';\r
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';\r
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-zh.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-zh.php
new file mode 100755 (executable)
index 0000000..fef66f8
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Traditional Chinese Version
+* @author liqwei <liqwei@liqwei.com>
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'SMTP 錯誤:登錄失敗。';
+$PHPMAILER_LANG['connect_host'] = 'SMTP 錯誤:無法連接到 SMTP 主機。';
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 錯誤:數據不被接受。';
+//$PHPMAILER_LANG['empty_message']        = 'Message body empty';
+$PHPMAILER_LANG['encoding'] = '未知編碼: ';
+$PHPMAILER_LANG['file_access'] = '無法訪問文件:';
+$PHPMAILER_LANG['file_open'] = '文件錯誤:無法打開文件:';
+$PHPMAILER_LANG['from_failed'] = '發送地址錯誤:';
+$PHPMAILER_LANG['execute'] = '無法執行:';
+$PHPMAILER_LANG['instantiate'] = '未知函數調用。';
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['provide_address'] = '必須提供至少一個收件人地址。';
+$PHPMAILER_LANG['mailer_not_supported'] = '發信客戶端不被支持。';
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP 錯誤:收件人地址錯誤:';
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-zh_cn.php b/www/plugins/facteur/phpmailer-php5/language/phpmailer.lang-zh_cn.php
new file mode 100755 (executable)
index 0000000..b188404
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+/**
+* PHPMailer language file: refer to English translation for definitive list
+* Simplified Chinese Version
+* @author liqwei <liqwei@liqwei.com>
+*/
+
+$PHPMAILER_LANG['authenticate'] = 'SMTP 错误:登录失败。';
+$PHPMAILER_LANG['connect_host'] = 'SMTP 错误:无法连接到 SMTP 主机。';
+$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 错误:数据不被接受。';
+//$P$PHPMAILER_LANG['empty_message']        = 'Message body empty';
+$PHPMAILER_LANG['encoding'] = '未知编码: ';
+$PHPMAILER_LANG['execute'] = '无法执行:';
+$PHPMAILER_LANG['file_access'] = '无法访问文件:';
+$PHPMAILER_LANG['file_open'] = '文件错误:无法打开文件:';
+$PHPMAILER_LANG['from_failed'] = '发送地址错误:';
+$PHPMAILER_LANG['instantiate'] = '未知函数调用。';
+//$PHPMAILER_LANG['invalid_email']        = 'Not sending, email address is invalid: ';
+$PHPMAILER_LANG['mailer_not_supported'] = '发信客户端不被支持。';
+$PHPMAILER_LANG['provide_address'] = '必须提供至少一个收件人地址。';
+$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误:收件人地址错误:';
+//$PHPMAILER_LANG['signing']              = 'Signing Error: ';
+//$PHPMAILER_LANG['smtp_connect_failed']  = 'SMTP Connect() failed.';
+//$PHPMAILER_LANG['smtp_error']           = 'SMTP server error: ';
+//$PHPMAILER_LANG['variable_set']         = 'Cannot set or reset variable: ';
+?>
\ No newline at end of file
diff --git a/www/plugins/facteur/prive/squelettes/contenu/configurer_facteur.html b/www/plugins/facteur/prive/squelettes/contenu/configurer_facteur.html
new file mode 100644 (file)
index 0000000..3bbab56
--- /dev/null
@@ -0,0 +1,5 @@
+[(#AUTORISER{configurer,facteur}|sinon_interdire_acces)]
+<h1 class="grostitre"><:facteur:configuration_facteur:></h1>
+<div class="ajax">
+       #FORMULAIRE_CONFIGURER_FACTEUR
+</div>
\ No newline at end of file
diff --git a/www/plugins/facteur/prive/themes/spip/images/facteur-16.png b/www/plugins/facteur/prive/themes/spip/images/facteur-16.png
new file mode 100644 (file)
index 0000000..29a7f05
Binary files /dev/null and b/www/plugins/facteur/prive/themes/spip/images/facteur-16.png differ
diff --git a/www/plugins/facteur/prive/themes/spip/images/facteur-24.png b/www/plugins/facteur/prive/themes/spip/images/facteur-24.png
new file mode 100644 (file)
index 0000000..c2e2154
Binary files /dev/null and b/www/plugins/facteur/prive/themes/spip/images/facteur-24.png differ
diff --git a/www/plugins/facteur/prive/themes/spip/images/facteur-32.png b/www/plugins/facteur/prive/themes/spip/images/facteur-32.png
new file mode 100644 (file)
index 0000000..b27394e
Binary files /dev/null and b/www/plugins/facteur/prive/themes/spip/images/facteur-32.png differ
diff --git a/www/plugins/facteur/svn.revision b/www/plugins/facteur/svn.revision
new file mode 100644 (file)
index 0000000..9140772
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/facteur/branches/v2
+Revision: 70525
+Dernier commit: 2013-03-08 18:00:06 +0100 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/facteur/branches/v2</origine>
+<revision>70525</revision>
+<commit>2013-03-08 18:00:06 +0100 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/action/dupliquer_formulaire.php b/www/plugins/formidable_1_0/action/dupliquer_formulaire.php
new file mode 100644 (file)
index 0000000..90a5f15
--- /dev/null
@@ -0,0 +1,70 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/config');
+
+/**
+ * Dupliquer un formulaire
+ * @param unknown_type $arg
+ * @return unknown_type
+ */
+function action_dupliquer_formulaire_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+       $id_formulaire = intval($arg);
+
+       // Si le formulaire existe bien
+       if ($id_formulaire > 0 and $formulaire = sql_fetsel('*', 'spip_formulaires', 'id_formulaire = '.$id_formulaire)){
+               include_spip('action/editer_formulaire');
+               // On enlève les champs inutiles
+               unset($formulaire['id_formulaire']);
+               // On modifie un peu le titre
+               $formulaire['titre'] = $formulaire['titre'].' '._T('formidable:formulaires_dupliquer_copie');
+               // On s'assure que l'identifiant n'existe pas déjà
+               $formulaire['identifiant'] = $formulaire['identifiant'].'_'.time();
+               // On insère un nouveau formulaire
+               $id_formulaire = insert_formulaire();
+               // Si ça a marché on modifie les champs de base
+               if ($id_formulaire > 0 and !($erreur = formulaire_set($id_formulaire, $formulaire))){
+                       // Et ensuite les saisies et les traitements
+                       $ok = sql_updateq(
+                               'spip_formulaires',
+                               array(
+                                       'saisies' => $formulaire['saisies'],
+                                       'traitements' => $formulaire['traitements']
+                               ),
+                               'id_formulaire = '.$id_formulaire
+                       );
+                       // Tout a fonctionné. En fonction de la config, on attribue l'auteur courant
+                       $auteurs = lire_config('formidable/analyse/auteur');
+                       if ($auteurs == 'on') {
+                               if ($id_auteur = session_get('id_auteur')) {
+                                       // association (par défaut) du formulaire et de l'auteur courant
+                                       objet_associer(array('formulaire'=>$id_formulaire), array('auteur'=>$id_auteur));
+                               }
+                       }
+                       // Et on redirige vers la vue
+                       $redirect = parametre_url(generer_url_ecrire('formulaire'), 'id_formulaire', $id_formulaire, '&');
+               }
+               // Sinon on reste sur la page qui liste tout
+               else{
+                       $redirect = generer_url_ecrire('formulaires');
+               }
+       }
+
+       // Si on a précisé une direction on va plutôt là
+       if (_request('redirect')) {
+               $redirect = parametre_url(urldecode(_request('redirect')),
+                       'id_formulaire', $id_formulaire, '&') . $erreur;
+       }
+       
+       // On redirige
+       include_spip('inc/headers');
+       redirige_par_entete($redirect);
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/action/editer_formulaire.php b/www/plugins/formidable_1_0/action/editer_formulaire.php
new file mode 100644 (file)
index 0000000..2254bf8
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Action de création / Modification d'un formulaire
+ * @param unknown_type $arg
+ * @return unknown_type
+ */
+function action_editer_formulaire_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+
+       // si id_formulaire n'est pas un nombre, c'est une creation
+       if (!$id_formulaire = intval($arg)) {
+               $id_formulaire = insert_formulaire();
+       }
+
+       // Enregistre l'envoi dans la BD
+       if ($id_formulaire > 0) $err = formulaire_set($id_formulaire);
+
+       if (_request('redirect')) {
+               $redirect = parametre_url(urldecode(_request('redirect')),
+                       'id_formulaire', $id_formulaire, '&') . $err;
+
+               include_spip('inc/headers');
+               redirige_par_entete($redirect);
+       }
+       else
+               return array($id_formulaire,$err);
+}
+
+/**
+ * Crée un nouveau formulaire et retourne son ID
+ *
+ * @return int id_formulaire
+ */
+function insert_formulaire() {
+       // Envoyer aux plugins
+       $champs = pipeline('pre_insertion',
+               array(
+                       'args' => array(
+                               'table' => 'spip_formulaires',
+                       ),
+                       'data' => $champs
+               )
+       );
+       $id_formulaire = sql_insertq("spip_formulaires");
+
+       return $id_formulaire;
+}
+
+/**
+ * Appelle la fonction de modification d'un formulaire
+ *
+ * @param int $id_formulaire
+ * @param unknown_type $set
+ * @return $err
+ */
+function formulaire_set($id_formulaire, $set=null) {
+       include_spip('inc/saisies');
+       $err = '';
+
+       $c = array();
+       $champs = saisies_lister_champs($GLOBALS['formulaires']['editer_formulaire']);
+       foreach ($champs as $champ)
+               $c[$champ] = _request($champ,$set);
+       
+       include_spip('inc/modifier');
+       revision_formulaire($id_formulaire, $c);
+
+       return $err;
+}
+
+/**
+ * Enregistre une révision de formulaire
+ *
+ * @param int $id_formulaire
+ * @param array $c
+ * @return
+ */
+function revision_formulaire($id_formulaire, $c=false) {
+       $invalideur = "id='id_formulaire/$id_formulaire'";
+
+       modifier_contenu('formulaire', $id_formulaire,
+               array(
+                       'nonvide' => array('titre' => _T('info_sans_titre')),
+                       'invalideur' => $invalideur
+               ),
+               $c);
+
+       return ''; // pas d'erreur
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/action/exporter_analyse_reponses.php b/www/plugins/formidable_1_0/action/exporter_analyse_reponses.php
new file mode 100755 (executable)
index 0000000..5175de8
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/*
+ * Exporter l'analyse des réponses d'un formulaire
+ * @param unknown_type $arg
+ * @return unknown_type
+ */
+function action_exporter_analyse_reponses_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+
+       // on ne fait des choses seulements si le formulaire existe et qu'il a des enregistrements
+       $ok = false;
+       if (
+               $id_formulaire = intval($arg)
+               and $formulaire = sql_fetsel('*','spip_formulaires','id_formulaire = '.$id_formulaire)
+               and $reponses = sql_allfetsel('*', 'spip_formulaires_reponses', 'id_formulaire = '.$id_formulaire.' and statut = '.sql_quote('publie'))
+       ) {
+               include_spip('inc/saisies');
+               include_spip('classes/facteur');
+               include_spip('inc/filtres');
+        $reponses_completes = array();
+
+        $saisies = saisies_lister_par_nom(unserialize($formulaire['saisies']), false);
+
+               $res = sql_select(
+            array('nom, valeur'),
+
+            'spip_formulaires_reponses_champs AS FRC,
+            spip_formulaires_reponses AS FR,
+            spip_formulaires AS F',
+
+            "FRC.id_formulaires_reponse=FR.id_formulaires_reponse
+            AND FR.statut='publie'
+            AND F.id_formulaire=FR.id_formulaire
+            AND F.id_formulaire=$id_formulaire"
+        );
+
+        $valeurs = array();
+        while($r = sql_fetch($res)) {
+            $valeurs[$r['nom']][] = is_array(unserialize($r['valeur']))
+                ? unserialize($r['valeur'])
+                : $r['valeur'];
+        }
+
+        foreach ($saisies as $nom=>$saisie){
+            $valeur = sql_getfetsel(
+                'valeur',
+                'spip_formulaires_reponses_champs',
+                'id_formulaires_reponse = '.intval($reponse['id_formulaires_reponse']).' and nom = '.sql_quote($nom)
+            );
+            if (is_array(unserialize($valeur)))
+                $valeur = unserialize($valeur);
+
+            $reponse_complete[] = formidable_analyser_saisie($saisie, $valeurs, 0, true);
+        }
+
+        $colonnes = array(_T('formidable:champs'), _T('formidable:sans_reponses'));
+        foreach($reponse_complete as $reponses) {
+            foreach($reponses as $key => $reponse) {
+                if ($key == 'header' || $key == 'sans_reponse') continue;
+                if (in_array($key, $colonnes) == false)
+                    array_push($colonnes, $key);
+            }
+        }
+
+        $csv = array();
+        foreach($reponse_complete as $reponses) {
+            foreach($colonnes as $colonne) {
+                $csv[$reponses['header']][$colonne] =
+                    isset($reponses[$colonne])
+                        ? $reponses[$colonne]
+                        : '';
+            }
+            $csv[$reponses['header']][_T('formidable:champs')] = $reponses['header'];
+            $csv[$reponses['header']][_T('formidable:sans_reponses')]
+                = $reponses['formidable:sans_reponse'];
+        }
+
+        $cpt_ligne = 1;
+        $reponses_completes = array();
+        $reponses_completes[0] = $colonnes;
+        foreach($csv as $ligne => $colonnes) {
+            $cpt_colonne = 0;
+            foreach($colonnes as $colonne) {
+                $reponses_completes[$cpt_ligne][$cpt_colonne++] = $colonne;
+            }
+            $cpt_ligne++;
+        }
+
+               if ($reponses_completes and $exporter_csv = charger_fonction('exporter_csv', 'inc/', true)){
+                       echo $exporter_csv('analyses-formulaire-'.$formulaire['identifiant'], $reponses_completes);
+                       exit();
+               }
+       }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/action/exporter_formulaire.php b/www/plugins/formidable_1_0/action/exporter_formulaire.php
new file mode 100644 (file)
index 0000000..df24083
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_exporter_formulaire_dist(){
+       include_spip('inc/formidable');
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+       
+       list($id_formulaire, $type_export) = preg_split('/[\W]/', $arg);
+       
+       if ($id_formulaire > 0
+               and $type_export
+               and $types_echange = echanges_formulaire_lister_disponibles()
+               and $exporter = $types_echange['exporter'][$type_export]
+       ){
+               $exporter($id_formulaire);
+       }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/action/exporter_formulaires_reponses.php b/www/plugins/formidable_1_0/action/exporter_formulaires_reponses.php
new file mode 100644 (file)
index 0000000..4105d4f
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/*
+ * Exporter toutes les réponses d'un formulaire
+ * @param unknown_type $arg
+ * @return unknown_type
+ */
+function action_exporter_formulaires_reponses_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+
+       // on ne fait des choses seulements si le formulaire existe et qu'il a des enregistrements
+       $ok = false;
+       if (
+               $id_formulaire = intval($arg)
+               and $formulaire = sql_fetsel('*','spip_formulaires','id_formulaire = '.$id_formulaire)
+               and $reponses = sql_allfetsel('*', 'spip_formulaires_reponses', 'id_formulaire = '.$id_formulaire.' and statut = '.sql_quote('publie'))
+       ) {
+               include_spip('inc/saisies');
+               include_spip('classes/facteur');
+               include_spip('inc/filtres');
+               $reponses_completes = array();
+               
+               // La première ligne des titres
+               $titres = array(_T('public:date'), _T('formidable:reponses_auteur'), _T('formidable:reponses_ip'));
+               $saisies = saisies_lister_par_nom(unserialize($formulaire['saisies']), false);
+               foreach ($saisies as $nom=>$saisie){
+                       $options = $saisie['options'];
+                       $titres[] = sinon($options['label_case'], sinon($options['label'], $nom));
+               }
+               $reponses_completes[] = $titres;
+               
+               // On parcourt chaque réponse
+               foreach ($reponses as $reponse){
+                       // Est-ce qu'il y a un auteur avec un nom
+                       $nom_auteur = '';
+                       if ($id_auteur = intval($reponse['id_auteur'])){
+                               $nom_auteur = sql_getfetsel('nom', 'spip_auteurs', 'id_auteur = '.$id_auteur);
+                       }
+                       if (!$nom_auteur) $nom_auteur = '';
+                       
+                       // Le début de la réponse avec les infos (date, auteur, etc)
+                       $reponse_complete = array($reponse['date'], $nom_auteur, $reponse['ip']);
+                       
+                       // Ensuite tous les champs
+                       foreach ($saisies as $nom=>$saisie){
+                               $valeur = sql_getfetsel(
+                                       'valeur',
+                                       'spip_formulaires_reponses_champs',
+                                       'id_formulaires_reponse = '.intval($reponse['id_formulaires_reponse']).' and nom = '.sql_quote($nom)
+                               );
+                               if (is_array(unserialize($valeur)))
+                                       $valeur = unserialize($valeur);
+                               $reponse_complete[] = Facteur::html2text(
+                                       recuperer_fond(
+                                               'saisies-vues/_base',
+                                               array_merge(
+                                                       array(
+                                                               'valeur_uniquement' => 'oui',
+                                                               'type_saisie' => $saisie['saisie'],
+                                                               'valeur' => $valeur
+                                                       ),
+                                                       $saisie['options']
+                                               )
+                                       )
+                               );
+                       }
+                       
+                       // On ajoute la ligne à l'ensemble des réponses
+                       $reponses_completes[] = $reponse_complete;
+               }
+               
+               if ($reponses_completes and $exporter_csv = charger_fonction('exporter_csv', 'inc/', true)){
+                       echo $exporter_csv('reponses-formulaire-'.$formulaire['identifiant'], $reponses_completes);
+                       exit();
+               }
+       }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/action/instituer_formulaires_reponse.php b/www/plugins/formidable_1_0/action/instituer_formulaires_reponse.php
new file mode 100644 (file)
index 0000000..211057e
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Action de création / Modification d'un truc
+ * @param unknown_type $arg
+ * @return unknown_type
+ */
+function action_instituer_formulaires_reponse_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+
+       list($id_formulaires_reponse, $statut) = preg_split('/\W/', $arg);
+       if (!$statut) return; // impossible mais sait-on jamais
+       
+       $id_formulaires_reponse = intval($id_formulaires_reponse);
+       
+       $ok = sql_updateq(
+               'spip_formulaires_reponses',
+               array(
+                       'statut' => $statut
+               ),
+               'id_formulaires_reponse = '.$id_formulaires_reponse
+       );
+       if (!$ok) $err = 'erreur';
+       
+       return array($id_formulaires_reponse, $err);
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/action/supprimer_formulaire.php b/www/plugins/formidable_1_0/action/supprimer_formulaire.php
new file mode 100644 (file)
index 0000000..372cebe
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Action de suppression d'un formulaire
+ * @param int $arg
+ * @return unknown_type
+ */
+function action_supprimer_formulaire_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+
+       // si id_formulaire n'est pas un nombre, on ne fait rien
+       if ($id_formulaire = intval($arg)) {
+               // On supprime le formulaire lui-même
+               $ok = sql_delete(
+                       'spip_formulaires',
+                       'id_formulaire = '.$id_formulaire
+               );
+               
+               if ($ok){
+                       // Si c'est bon, on récupère les réponses pour les supprimer
+                       $reponses = sql_allfetsel(
+                               'id_formulaires_reponse',
+                               'spip_formulaires_reponses',
+                               'id_formulaire = '.$id_formulaire
+                       );
+                       $reponses = $reponses ? array_map('reset', $reponses) : false;
+               
+                       // On supprime les réponses s'il y en a
+                       if ($reponses){
+                               $ok = sql_delete(
+                                       'spip_formulaires_reponses',
+                                       sql_in('id_formulaires_reponse', $reponses)
+                               );
+                       
+                               // Si c'est bon, on supprime les champs des réponses
+                               if ($ok){
+                                       $ok = sql_delete(
+                                               'spip_formulaires_reponses_champs',
+                                               sql_in('id_formulaires_reponse', $reponses)
+                                       );
+                               }
+                       }
+               }
+       }
+       
+       if ($ok){
+               if (!$redirect = _request('redirect'))
+                       $redirect = generer_url_ecrire('formulaires');
+               
+               include_spip('inc/headers');
+               redirige_par_entete(str_replace("&amp;","&",urldecode($redirect)));
+       }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/action/supprimer_formulaires_reponse.php b/www/plugins/formidable_1_0/action/supprimer_formulaires_reponse.php
new file mode 100644 (file)
index 0000000..98f106e
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Action de suppression d'une réponse
+ * @param int $arg
+ * @return unknown_type
+ */
+function action_supprimer_formulaires_reponse_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+
+       // si id_formulaires_reponse n'est pas un nombre, on ne fait rien
+       if ($id_formulaires_reponse = intval($arg)) {
+               // On récupère l'id_formulaire pour la redirection
+               $id_formulaire = intval(sql_getfetsel(
+                       'id_formulaire',
+                       'spip_formulaires_reponses',
+                       'id_formulaires_reponse = '.$id_formulaires_reponse
+               ));
+               
+               // On supprime la réponse
+               $ok = sql_delete(
+                       'spip_formulaires_reponses',
+                       'id_formulaires_reponse = '.$id_formulaires_reponse
+               );
+               
+               // Si c'est bon, on supprime les champs des réponses
+               if ($ok){
+                       $ok = sql_delete(
+                               'spip_formulaires_reponses_champs',
+                               'id_formulaires_reponse = '.$id_formulaires_reponse
+                       );
+               }
+       }
+       
+       if ($ok){
+               if (!$redirect = _request('redirect'))
+                       $redirect = parametre_url(generer_url_ecrire('formulaires_reponses'), 'id_formulaire', $id_formulaire);
+               
+               include_spip('inc/headers');
+               redirige_par_entete(str_replace("&amp;","&",urldecode($redirect)));
+       }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/base/formidable_tables.php b/www/plugins/formidable_1_0/base/formidable_tables.php
new file mode 100644 (file)
index 0000000..4d5f433
--- /dev/null
@@ -0,0 +1,187 @@
+<?php
+
+/**
+ * Déclarations relatives à la base de données
+ * 
+ * @package SPIP\Formidable\Pipelines
+**/
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Déclarer les interfaces des tables de formidable pour le compilateur
+ * 
+ * @pipeline declarer_tables_interfaces
+ * 
+ * @param array $interfaces
+ *     Déclarations d'interface pour le compilateur
+ * @return array
+ *     Déclarations d'interface pour le compilateur
+**/
+function formidable_declarer_tables_interfaces($interfaces) {
+       // 'spip_' dans l'index de $tables_principales
+       $interfaces['table_des_tables']['formulaires'] = 'formulaires';
+       $interfaces['table_des_tables']['formulaires_reponses'] = 'formulaires_reponses';
+       $interfaces['table_des_tables']['formulaires_reponses_champs'] = 'formulaires_reponses_champs';
+
+       $interfaces['tables_jointures']['spip_formulaires'][] = 'formulaires_liens';
+       $interfaces['tables_jointures']['spip_articles'][] = 'formulaires_liens';
+       $interfaces['tables_jointures']['spip_rubriques'][] = 'formulaires_liens';
+
+       return $interfaces;
+}
+
+/**
+ * Déclarer les objets éditoriaux des formulaires
+ *
+ * @pipeline declarer_tables_objets_sql
+ * @param array $tables
+ *     Description des tables
+ * @return array
+ *     Description complétée des tables
+ */
+function formidable_declarer_tables_objets_sql($tables) {
+       $tables['spip_formulaires'] = array(
+               'type'=>'formulaire',
+               'titre' => "titre, '' AS lang",
+               'date' => '',
+               'principale' => 'oui',
+               
+               'field' => array(
+                       "id_formulaire" => "bigint(21) NOT NULL",
+                       "identifiant" => "varchar(200)",
+                       "titre" => "text NOT NULL default ''",
+                       "descriptif" => "text",
+                       "message_retour" => "text NOT NULL default ''",
+                       "saisies" => "text NOT NULL default ''",
+                       "traitements" => "text NOT NULL default ''",
+                       "public" => "enum('non', 'oui') DEFAULT 'non' NOT NULL",
+                       "statut" => "varchar(10) NOT NULL default ''",
+                       "maj" => "timestamp",
+                       "apres" => "varchar(12) NOT NULL default ''",
+                       "url_redirect" => "varchar(255)"
+               ),
+               'key' => array(
+                       "PRIMARY KEY" => "id_formulaire"
+               ),
+               'join'=> array(
+                       'id_formulaire' => 'id_formulaire'
+               ),
+               'rechercher_champs' => array(
+                 'titre' => 5, 'descriptif' => 3
+               ),
+       );
+
+       $tables['spip_formulaires_reponses'] = array(
+               'type'=>'formulaires_reponse',
+               'titre' => "'' AS titre, '' AS lang",
+               'date' => 'date',
+               'principale' => 'oui',
+
+               'field' => array(
+                       "id_formulaires_reponse" => "bigint(21) NOT NULL",
+                       "id_formulaire" => "bigint(21) NOT NULL default 0",
+                       "date" => "datetime NOT NULL default '0000-00-00 00:00:00'",
+                       "ip" => "varchar(255) NOT NULL default ''",
+                       "id_auteur" => "bigint(21) NOT NULL default 0",
+                       "cookie" => "varchar(255) NOT NULL default ''",
+                       "statut" => "varchar(10) NOT NULL default ''",
+                       "maj" => "timestamp"
+               ),
+               'key' => array(
+                       "PRIMARY KEY" => "id_formulaires_reponse",
+                       "KEY id_formulaire" => "id_formulaire",
+                       "KEY id_auteur" => "id_auteur",
+                       "KEY cookie" => "cookie"
+               ),
+               'join' => array(
+                       'id_formulaires_reponse' => 'id_formulaires_reponse',
+                       'id_formulaire' => 'id_formulaire',
+                       'id_auteur' => 'id_auteur'
+               ),
+               'statut'=> array(
+                       array(
+                               'champ' => 'statut',
+                               'publie' => 'publie',
+                               'previsu' => 'publie,prop',
+                               'exception' => array('statut', 'tout'),
+                       )
+               ),
+               'texte_changer_statut' => 'formulaires_reponse:changer_statut',
+               'statut_titres' => array(
+                       'prop'=>'info_article_propose',
+                       'publie'=>'info_article_publie',
+                       'poubelle'=>'info_article_supprime'
+               ),
+               'statut_textes_instituer' => array(
+                       'prop' => 'texte_statut_propose_evaluation',
+                       'publie' => 'texte_statut_publie',
+                       'refuse' => 'texte_statut_poubelle',
+               ),
+       );
+       return $tables;
+}
+
+/**
+ * Déclarer les tables principales de formidable
+ *
+ * @pipeline declarer_tables_principales
+ * @param array $tables_principales
+ *     Description des tables
+ * @return array
+ *     Description complétée des tables
+**/
+function formidable_declarer_tables_principales($tables_principales){
+
+       // Table formulaires_reponses_champs 
+       $formulaires_reponses_champs = array(
+               "id_formulaires_reponse" => "bigint(21) NOT NULL default 0",
+               "nom" => "varchar(255) NOT NULL default ''",
+               "valeur" => "text NOT NULL DEFAULT ''",
+               "maj" => "timestamp"
+       );
+       $formulaires_reponses_champs_cles = array(
+               "PRIMARY KEY" => "id_formulaires_reponse, nom",
+               "KEY id_formulaires_reponse" => "id_formulaires_reponse"
+       );
+       $tables_principales['spip_formulaires_reponses_champs'] = array(
+               'field' => &$formulaires_reponses_champs,
+               'key' => &$formulaires_reponses_champs_cles
+       );
+       
+       return $tables_principales;
+}
+
+/**
+ * Déclarer les tables auxiliaires de formidable
+ *
+ * @pipeline declarer_tables_auxiliaires
+ * @param array $tables_auxiliaires
+ *     Description des tables
+ * @return array
+ *     Description complétée des tables
+**/
+function formidable_declarer_tables_auxiliaires($tables_auxiliaires){
+       $formulaires_liens = array(
+               "id_formulaire" => "bigint(21) DEFAULT '0' NOT NULL",
+               "id_objet"      => "bigint(21) DEFAULT '0' NOT NULL",
+               "objet" => "VARCHAR (25) DEFAULT '' NOT NULL"
+       );
+
+       $formulaires_liens_cles = array(
+               "PRIMARY KEY" => "id_formulaire,id_objet,objet",
+               "KEY id_formulaire" => "id_formulaire"
+       );
+       
+       $tables_auxiliaires['spip_formulaires_liens'] = array(
+               'field' => &$formulaires_liens,
+               'key' => &$formulaires_liens_cles
+       );
+       
+       return $tables_auxiliaires;
+}
+
+
+
+?>
diff --git a/www/plugins/formidable_1_0/css/formidable_analyse.css.html b/www/plugins/formidable_1_0/css/formidable_analyse.css.html
new file mode 100644 (file)
index 0000000..3a82a97
--- /dev/null
@@ -0,0 +1,90 @@
+.formidable_analyse .stat {width:70%;}
+
+.progress-bar {
+       background-color: #f1f1f1;
+       height: 20px;
+       padding: 1px;
+       margin: 2px 0;
+       -moz-border-radius: 5px;
+       -webkit-border-radius: 5px;
+       border-radius: 5px;
+       -moz-box-shadow: 0 1px 4px #eee inset, 0 1px 0 #bbb;
+       -webkit-box-shadow: 0 1px 4px #eee inset, 0 1px 0 #bbb;
+       box-shadow: 0 1px 4px #eee inset, 0 1px 0 #bbb;
+       position:relative; /* pour le strong du texte */
+}
+
+.progress-bar strong {
+       color:#000;
+       padding:0 .5em;
+       -webkit-moz-text-shadow: 0 1px 1px #fff;
+       -moz-text-shadow: 0 1px 1px #fff;
+       text-shadow: 0 1px 1px #fff;
+       position:absolute;
+       top:2px;
+       left:0;
+}
+.progress-bar strong small {font-size:90%; font-weight:normal;}
+
+.progress-bar span {
+       background-color: #bbb;
+         background-image: -webkit-gradient(linear, left top, left bottom, from(#bbb), to(#777));
+         background-image: -webkit-linear-gradient(top, #bbb, #777);
+         background-image: -moz-linear-gradient(top, #bbb, #777);
+         background-image: -ms-linear-gradient(top, #bbb, #777);
+         background-image: -o-linear-gradient(top, #bbb, #777);
+         background-image: linear-gradient(top, #bbb, #777); 
+       display: inline-block;
+       height: 100%;
+       -moz-border-radius: 3px;
+       -webkit-border-radius: 3px;
+       border-radius: 3px;
+       -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;
+       -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;
+       box-shadow: 0 1px 0 rgba(255, 255, 255, .5) inset;
+        -webkit-transition: width 2s ease-in-out;
+        -moz-transition: width 2s ease-in-out;
+        -ms-transition: width 2s ease-in-out;
+        -o-transition: width 2s ease-in-out;
+        transition: width 2s ease-in-out;    
+}
+
+.progress-bar.gray span {
+       background-color: #bbb;
+         background-image: -webkit-gradient(linear, left top, left bottom, from(#bbb), to(#777));
+         background-image: -webkit-linear-gradient(top, #bbb, #777);
+         background-image: -moz-linear-gradient(top, #bbb, #777);
+         background-image: -ms-linear-gradient(top, #bbb, #777);
+         background-image: -o-linear-gradient(top, #bbb, #777);
+         background-image: linear-gradient(top, #bbb, #777); 
+}
+
+.progress-bar.blue span {
+       background-color: #34c2e3;
+         background-image: -webkit-gradient(linear, left top, left bottom, from(#34c2e3), to(#13ACD1));
+         background-image: -webkit-linear-gradient(top, #34c2e3, #13ACD1);
+         background-image: -moz-linear-gradient(top, #34c2e3, #13ACD1);
+         background-image: -ms-linear-gradient(top, #34c2e3, #13ACD1);
+         background-image: -o-linear-gradient(top, #34c2e3, #13ACD1);
+         background-image: linear-gradient(top, #34c2e3, #13ACD1);  
+}
+
+.progress-bar.orange span {
+         background-color: #fecf23;
+         background-image: -webkit-gradient(linear, left top, left bottom, from(#fecf23), to(#fd9215));
+         background-image: -webkit-linear-gradient(top, #fecf23, #fd9215);
+         background-image: -moz-linear-gradient(top, #fecf23, #fd9215);
+         background-image: -ms-linear-gradient(top, #fecf23, #fd9215);
+         background-image: -o-linear-gradient(top, #fecf23, #fd9215);
+         background-image: linear-gradient(top, #fecf23, #fd9215);  
+}      
+
+.progress-bar.green span {
+         background-color: #a5df41;
+         background-image: -webkit-gradient(linear, left top, left bottom, from(#a5df41), to(#4ca916));
+         background-image: -webkit-linear-gradient(top, #a5df41, #4ca916);
+         background-image: -moz-linear-gradient(top, #a5df41, #4ca916);
+         background-image: -ms-linear-gradient(top, #a5df41, #4ca916);
+         background-image: -o-linear-gradient(top, #a5df41, #4ca916);
+         background-image: linear-gradient(top, #a5df41, #4ca916);  
+}
diff --git a/www/plugins/formidable_1_0/echanger/formulaire/forms.php b/www/plugins/formidable_1_0/echanger/formulaire/forms.php
new file mode 100644 (file)
index 0000000..c74aaef
--- /dev/null
@@ -0,0 +1,175 @@
+<?php\r
+\r
+// Sécurité\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+// Importation d'un formulaire forms&table\r
+\r
+function echanger_formulaire_forms_importer_dist($fichier){\r
+       include_spip('inc/xml');\r
+       $arbre = spip_xml_load($fichier, false);\r
+       \r
+       if ($arbre and is_array($arbre) and isset($arbre['forms'])){\r
+               foreach($arbre['forms'] as $forms){\r
+                       foreach ($forms['form'] as $form){\r
+                               $formulaire = array();\r
+                               \r
+                               // Le titre\r
+                               $titre = trim(spip_xml_aplatit($form['titre']));\r
+                               $formulaire['titre'] = $titre ? $titre : _T('info_sans_titre');\r
+                               \r
+                               // L'identifiant il faut le générer\r
+                               $formulaire['identifiant'] = 'form_'.time();\r
+                               \r
+                               // Le descriptif\r
+                               $descriptif = trim(spip_xml_aplatit($form['descriptif']));\r
+                               $formulaire['descriptif'] = $descriptif ? $descriptif : '';\r
+                               \r
+                               // Le message de retour si ok\r
+                               $message_retour = trim(spip_xml_aplatit($form['texte']));\r
+                               $formulaire['message_retour'] = $message_retour ? $message_retour : '';\r
+\r
+                               // Les champs\r
+                               $formulaire['saisies'] = array();\r
+                               foreach($form['fields'] as $fields){\r
+                                       foreach($fields['field'] as $field){\r
+                                               // Le truc par défaut\r
+                                               $saisie = array(\r
+                                                       'saisie' => 'input',\r
+                                                       'options' => array('size'=>40)\r
+                                               );\r
+                                               \r
+                                               // On essaye de traduire tous les types de champs\r
+                                               $type = trim(spip_xml_aplatit($field['type']));\r
+                                               switch ($type){\r
+                                                       case 'texte':\r
+                                                               $saisie['saisie'] = 'textarea';\r
+                                                               unset($saisie['options']['size']);\r
+                                                               $saisie['options']['rows'] = 5;\r
+                                                               $saisie['options']['cols'] = 40;\r
+                                                               break;\r
+                                                       case 'password':\r
+                                                               $saisie['options']['type'] = 'password';\r
+                                                               break;\r
+                                                       case 'date':\r
+                                                               $saisie['saisie'] = 'date';\r
+                                                               $saisie['verifier'] = array(\r
+                                                                       'type' => 'date'\r
+                                                               );\r
+                                                               break;\r
+                                                       case 'num':\r
+                                                       case 'monnaie':\r
+                                                               $saisie['verifier'] = array(\r
+                                                                       'type' => 'entier'\r
+                                                               );\r
+                                                               if ($taille = trim(spip_xml_aplatit($field['taille'])))\r
+                                                                       $saisie['verifier']['options'] = array('max' => (pow(10, $taille)-1));\r
+                                                               break;\r
+                                                       case 'email':\r
+                                                               $saisie['verifier'] = array(\r
+                                                                       'type' => 'email'\r
+                                                               );\r
+                                                               break;\r
+                                                       case 'telephone':\r
+                                                               $saisie['verifier'] = array(\r
+                                                                       'type' => 'telephone'\r
+                                                               );\r
+                                                               break;\r
+                                                       case 'select':\r
+                                                               unset($saisie['options']['size']);\r
+                                                               $liste = trim(spip_xml_aplatit($field['extra_info']));\r
+                                                               if ($liste == 'radio')\r
+                                                                       $saisie['saisie'] = 'radio';\r
+                                                               else\r
+                                                                       $saisie['saisie'] = 'selection';\r
+                                                               break;\r
+                                                       case 'multiple':\r
+                                                               $saisie['saisie'] = 'checkbox';\r
+                                                               unset($saisie['options']['size']);\r
+                                                               break;\r
+                                                       case 'fichier':\r
+                                                       case 'separateur':\r
+                                                               $saisie = null;\r
+                                               }\r
+                                               \r
+                                               // On continue seulement si on a toujours une saisie\r
+                                               if ($saisie){\r
+                                                       // Les choix pour les types select et multiple\r
+                                                       if(isset($field['les_choix']) and is_array($field['les_choix'])){\r
+                                                               $saisie['options']['datas'] = array();\r
+                                                               foreach($field['les_choix'] as $les_choix){\r
+                                                                       foreach($les_choix['un_choix'] as $un_choix){\r
+                                                                               $choix = trim(spip_xml_aplatit($un_choix['choix']));\r
+                                                                               $titre = trim(spip_xml_aplatit($un_choix['titre']));\r
+                                                                               $saisie['options']['datas'][$choix] = $titre;\r
+                                                                       }\r
+                                                               }\r
+                                                       }\r
+                                               \r
+                                                       // Le nom\r
+                                                       $saisie['options']['nom'] = trim(spip_xml_aplatit($field['champ']));\r
+                                               \r
+                                                       // Le label\r
+                                                       $saisie['options']['label'] = trim(spip_xml_aplatit($field['titre']));\r
+                                               \r
+                                                       // Obligatoire\r
+                                                       if (trim(spip_xml_aplatit($field['obligatoire'])) == 'oui')\r
+                                                               $saisie['options']['obligatoire'] = 'on';\r
+                                               \r
+                                                       // Explication éventuelle\r
+                                                       if ($explication = trim(spip_xml_aplatit($field['aide'])))\r
+                                                               $saisie['options']['explication'] = $explication;\r
+                                               \r
+                                                       // On ajoute enfin la saisie\r
+                                                       $formulaire['saisies'][] = $saisie;\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               // Les traitements\r
+                               $formulaire['traitements'] = array();\r
+                               \r
+                               // Le traitement email\r
+                               $config_email = unserialize(trim(spip_xml_aplatit($form['email'])));\r
+                               if (is_array($config_email)){\r
+                                       if ($email_defaut = $config_email['defaut'])\r
+                                               $formulaire['traitements']['email'] = array(\r
+                                                       'destinataires_plus' => $email_defaut\r
+                                               );\r
+                               }\r
+                               \r
+                               // Le traitement enregistrement\r
+                               $formulaire['traitements']['enregistrement'] = array(\r
+                                       'moderation' => (trim(spip_xml_aplatit($form['moderation'])) == 'priori') ? 'priori' : 'posteriori',\r
+                                       'modifiable' => (trim(spip_xml_aplatit($form['modifiable'])) == 'oui') ? 'on' : '',\r
+                                       'multiple' => (trim(spip_xml_aplatit($form['multiple'])) == 'non') ? '' : 'on'\r
+                               );\r
+                               \r
+                               include_spip('action/editer_formulaire');\r
+                               // On insère un nouveau formulaire\r
+                               $id_formulaire = insert_formulaire();\r
+                               // Si ça a marché on modifie les champs de base\r
+                               if ($id_formulaire > 0 and !($erreur = formulaire_set($id_formulaire, $formulaire))){\r
+                                       // Et ensuite les saisies et les traitements\r
+                                       $ok = sql_updateq(\r
+                                               'spip_formulaires',\r
+                                               array(\r
+                                                       'saisies' => serialize($formulaire['saisies']),\r
+                                                       'traitements' => serialize($formulaire['traitements'])\r
+                                               ),\r
+                                               'id_formulaire = '.$id_formulaire\r
+                                       );\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       \r
+       if ($id_formulaire and $ok){\r
+               return $id_formulaire;\r
+       }\r
+       else{\r
+               return _T('formidable:erreur_importer_forms');\r
+       }\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/formidable_1_0/echanger/formulaire/wcs.php b/www/plugins/formidable_1_0/echanger/formulaire/wcs.php
new file mode 100644 (file)
index 0000000..c12100a
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function echanger_formulaire_wcs_importer_dist($fichier){
+       include_spip('inc/xml');
+       include_spip('inc/filtres');
+       include_spip('inc/saisies');
+       $arbre = spip_xml_load($fichier, false);
+       
+       if ($arbre and is_array($arbre) and isset($arbre['formdef'])){
+               foreach($arbre['formdef'] as $form){
+                       $formulaire = array();
+                       
+                       // Le titre
+                       $titre = filtrer_entites(trim(spip_xml_aplatit($form['name'])));
+                       $formulaire['titre'] = $titre ? $titre : _T('info_sans_titre');
+                       
+                       // On vérifie que l'identifiant n'existe pas déjà
+                               $formulaire['identifiant'] = str_replace('-', '_', trim(spip_xml_aplatit($form['url_name'])));
+                               $deja = sql_getfetsel(
+                                       'id_formulaire',
+                                       'spip_formulaires',
+                                       'identifiant = '.sql_quote($formulaire['identifiant'])
+                               );
+                               if ($deja)
+                                       $formulaire['identifiant'] = $formulaire['identifiant'].'_'.time();
+                       
+                       // Les champs
+                       $formulaire['saisies'] = array();
+                       // Par défaut le conteneur c'est le formulaire
+                       $conteneur =& $formulaire;
+                       foreach($form['fields'] as $fields){
+                               foreach($fields['field'] as $field){
+                                       $changer_conteneur = false;
+                                       
+                                       // Le truc par défaut
+                                       $saisie = array(
+                                               'saisie' => 'input',
+                                               'options' => array('size'=>40)
+                                       );
+                                       
+                                       // Le label
+                                       $saisie['options']['label'] = filtrer_entites(trim(spip_xml_aplatit($field['label'])));
+                                       
+                                       // On essaye de traduire tous les types de champs
+                                       $type = trim(spip_xml_aplatit($field['type']));
+                                       switch ($type){
+                                               case 'string':
+                                                       if ($size = intval(trim(spip_xml_aplatit($field['size'])))){
+                                                               $saisie['options']['maxlength'] = $size;
+                                                               $saisie['verifier'] = array(
+                                                                       'type' => 'taille',
+                                                                       'options' => array('max'=>$size)
+                                                               );
+                                                       }
+                                                       break;
+                                               case 'text':
+                                                       $saisie['saisie'] = 'textarea';
+                                                       unset($saisie['options']['size']);
+                                                       $saisie['options']['rows'] = 5;
+                                                       $saisie['options']['cols'] = 40;
+                                                       if ($rows = intval(trim(spip_xml_aplatit($field['rows'])))){
+                                                               $saisie['options']['rows'] = $rows;
+                                                       }
+                                                       if ($cols = intval(trim(spip_xml_aplatit($field['cols'])))){
+                                                               $saisie['options']['cols'] = $cols;
+                                                       }
+                                                       break;
+                                               case 'date':
+                                                       $saisie['verifier'] = array(
+                                                               'type' => 'date'
+                                                       );
+                                                       break;
+                                               case 'email':
+                                                       $saisie['verifier'] = array(
+                                                               'type' => 'email'
+                                                       );
+                                                       break;
+                                               case 'item':
+                                                       unset($saisie['options']['size']);
+                                                       $saisie['saisie'] = 'selection';
+                                                       $saisie['options']['cacher_option_intro'] = 'on';
+                                                       break;
+                                               case 'bool':
+                                                       unset($saisie['options']['size']);
+                                                       $saisie['saisie'] = 'case';
+                                                       $saisie['options']['label_case'] = $saisie['options']['label'];
+                                                       unset($saisie['options']['label']);
+                                                       break;
+                                               case 'multiple':
+                                                       $saisie['saisie'] = 'checkbox';
+                                                       unset($saisie['options']['size']);
+                                                       break;
+                                               case 'comment':
+                                                       $saisie['saisie'] = 'explication';
+                                                       $saisie['options']['texte'] = $saisie['options']['label'];
+                                                       unset($saisie['options']['label']);
+                                                       break;
+                                               case 'page':
+                                                       $saisie['saisie'] = 'fieldset';
+                                                       unset($saisie['options']['size']);
+                                                       $saisie['saisies'] = array();
+                                                       $changer_conteneur = true;
+                                                       // On remet le conteneur au niveau du formulaire
+                                                       $conteneur =& $formulaire;
+                                                       break;
+                                               case 'subtitle':
+                                               case 'file':
+                                                       $saisie = null;
+                                       }
+                                       
+                                       // On continue seulement si on a toujours une saisie
+                                       if ($saisie){
+                                               // Les choix pour les types select
+                                               if(isset($field['items']) and is_array($field['items'])){
+                                                       $saisie['options']['datas'] = array();
+                                                       foreach($field['items'] as $items){
+                                                               foreach($items['item'] as $cle=>$item){
+                                                                       $titre = filtrer_entites(trim($item));
+                                                                       $saisie['options']['datas']['choix_'.$cle] = $titre;
+                                                               }
+                                                       }
+                                               }
+                                       
+                                               // Le nom
+                                               $saisie['options']['nom'] = saisies_generer_nom($formulaire['saisies'], $saisie['saisie']);
+                                       
+                                               // Obligatoire
+                                               if (trim(spip_xml_aplatit($field['required'])) == 'True')
+                                                       $saisie['options']['obligatoire'] = 'on';
+                                       
+                                               // Explication éventuelle
+                                               if ($explication = trim(spip_xml_aplatit($field['hint'])))
+                                                       $saisie['options']['explication'] = $explication;
+                                       
+                                               // On ajoute enfin la saisie
+                                               $conteneur['saisies'][] = $saisie;
+                                               
+                                               // Faut-il changer de conteneur ?
+                                               if ($changer_conteneur){
+                                                       $conteneur =& $conteneur['saisies'][count($conteneur['saisies'])-1];
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       include_spip('action/editer_formulaire');
+                       // On insère un nouveau formulaire
+                       $id_formulaire = insert_formulaire();
+                       // Si ça a marché on modifie les champs de base
+                       if ($id_formulaire > 0 and !($erreur = formulaire_set($id_formulaire, $formulaire))){
+                               // Et ensuite les saisies et les traitements
+                               $ok = sql_updateq(
+                                       'spip_formulaires',
+                                       array(
+                                               'saisies' => serialize($formulaire['saisies']),
+                                               'traitements' => serialize($formulaire['traitements'])
+                                       ),
+                                       'id_formulaire = '.$id_formulaire
+                               );
+                       }
+               }
+       }
+       
+       if ($id_formulaire and $ok){
+               return $id_formulaire;
+       }
+       else{
+               return _T('formidable:erreur_importer_wcs');
+       }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/echanger/formulaire/yaml.php b/www/plugins/formidable_1_0/echanger/formulaire/yaml.php
new file mode 100644 (file)
index 0000000..162331d
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function echanger_formulaire_yaml_exporter_dist($id_formulaire){
+       include_spip('base/abstract_sql');
+       include_spip('inc/yaml');
+       $id_formulaire = intval($id_formulaire);
+       $export = '';
+       
+       if ($id_formulaire > 0){
+               // On récupère le formulaire
+               $formulaire = sql_fetsel(
+                       '*',
+                       'spip_formulaires',
+                       'id_formulaire = '.$id_formulaire
+               );
+               
+               // On décompresse les trucs sérialisés
+               $formulaire['saisies'] = unserialize($formulaire['saisies']);
+               $formulaire['traitements'] = unserialize($formulaire['traitements']);
+               
+               // On envode en yaml
+               $export = yaml_encode($formulaire);
+       }
+       
+       Header("Content-Type: text/x-yaml;");
+       Header('Content-Disposition: attachment; filename=formulaire-'.$formulaire['identifiant'].'.yaml');
+       Header("Content-Length: ".strlen($export));
+       echo $export;
+       exit();
+}
+
+function echanger_formulaire_yaml_importer_dist($fichier){
+       $yaml = '';
+       lire_fichier($fichier, $yaml);
+       // Si on a bien recupere une chaine on tente de la decoder
+       if ($yaml){
+               include_spip('inc/yaml');
+               $formulaire = yaml_decode($yaml);
+               // Si le decodage marche on importe alors le contenu
+               if (is_array($formulaire)){
+                       include_spip('action/editer_formulaire');
+                       // On enlève les champs inutiles
+                       unset($formulaire['id_formulaire']);
+                       // On vérifie que l'identifiant n'existe pas déjà
+                       $deja = sql_getfetsel(
+                               'id_formulaire',
+                               'spip_formulaires',
+                               'identifiant = '.sql_quote($formulaire['identifiant'])
+                       );
+                       if ($deja)
+                               $formulaire['identifiant'] = $formulaire['identifiant'].'_'.time();
+                       // On insère un nouveau formulaire
+                       $id_formulaire = insert_formulaire();
+                       // Si ça a marché on modifie les champs de base
+                       if ($id_formulaire > 0 and !($erreur = formulaire_set($id_formulaire, $formulaire))){
+                               // Et ensuite les saisies et les traitements
+                               $ok = sql_updateq(
+                                       'spip_formulaires',
+                                       array(
+                                               'saisies' => serialize($formulaire['saisies']),
+                                               'traitements' => serialize($formulaire['traitements'])
+                                       ),
+                                       'id_formulaire = '.$id_formulaire
+                               );
+                       }
+               }
+       }
+       
+       if ($id_formulaire and $ok){
+               return $id_formulaire;
+       }
+       else{
+               return _T('formidable:erreur_importer_yaml');
+       }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/exec/puce_statut_formulaires.php b/www/plugins/formidable_1_0/exec/puce_statut_formulaires.php
new file mode 100644 (file)
index 0000000..6aadef3
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Gestion des puces d'action rapide de formulaires
+ *
+ * @package SPIP\Formidable\Puce_statut
+**/
+
+include_spip('inc/presentation');
+
+/**
+ * Gestion de l'affichage ajax des puces d'action rapide de formulaires
+ *
+ * Récupère l'identifiant id et le type d'objet dans les données postées
+ * et appelle la fonction de traitement de cet exec.
+ * 
+ * @see exec_puce_statut_formulaires_args()
+ * @return string Code HTML
+**/
+function exec_puce_statut_formulaires_dist()
+{
+       exec_puce_statut_formulaires_args(_request('id'),  _request('type'));
+}
+
+/**
+ * Traitement de l'affichage ajax des puces d'action rapide
+ *
+ * Appelle la fonction de traitement des puces statuts
+ * après avoir retrouvé le statut en cours de l'objet
+ * et son parent s'il en a un
+ * 
+ * @param int $id
+ *     Identifiant de l'objet
+ * @param string $type
+ *     Type d'objet
+ * @return string Code HTML
+**/
+function exec_puce_statut_formulaires_args($id, $type)
+{
+       if (in_array($type,array('formulaires','formulaires_reponse'))) {
+               $table = table_objet_sql($type);
+               $prim = id_table_objet($type);
+               $id = intval($id);
+               $r = sql_fetsel("id_formulaire,statut", "$table", "$prim=$id");
+               $statut = $r['statut'];
+               $id_formulaire = $r['id_formulaire'];
+       } else {
+               $id_formulaire = intval($id);
+               $statut = 'prop'; // arbitraire
+       }
+       $puce_statut = charger_fonction('puce_statut', 'inc');
+       ajax_retour($puce_statut($id,$statut,$id_formulaire,$type, true));
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formidable_administrations.php b/www/plugins/formidable_1_0/formidable_administrations.php
new file mode 100644 (file)
index 0000000..d273617
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * Fichier gérant l'installation et désinstallation du plugin
+ *
+ * @package SPIP\Formidable\Installation
+**/
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Installation/maj des tables de formidable...
+ *
+ * @param string $nom_meta_base_version
+ *     Nom de la meta informant de la version du schéma de données du plugin installé dans SPIP
+ * @param string $version_cible
+ *     Version du schéma de données dans ce plugin (déclaré dans paquet.xml)
+ * @return void
+ */
+function formidable_upgrade($nom_meta_base_version, $version_cible){
+       // Création des tables
+       include_spip('base/create');
+       include_spip('base/abstract_sql');
+
+       $maj = array();
+       $maj['create'] = array(
+               array('maj_tables',array(
+                       'spip_formulaires',
+                       'spip_formulaires_reponses',
+                       'spip_formulaires_reponses_champs',
+                       'spip_formulaires_liens')),
+       );
+       // Ajout du choix de ce qu'on affiche à la fin des traitements
+       $maj['0.4.0'] = array(array('maj_tables',array('spip_formulaires')));
+       // Ajout d'une URL de redirection
+       $maj['0.5.0'] = array(array('maj_tables',array('spip_formulaires')));
+       // Modif du type du message de retour pour pouvoir mettre plus de chose
+       $maj['0.5.1'] = array(array('sql_alter','TABLE spip_formulaires CHANGE message_retour message_retour text NOT NULL default ""'));
+
+       include_spip('base/upgrade');
+       maj_plugin($nom_meta_base_version, $version_cible, $maj);
+}
+
+/**
+ * Désinstallation/suppression des tables de formidable
+ *
+ * @param string $nom_meta_base_version
+ *     Nom de la meta informant de la version du schéma de données du plugin installé dans SPIP
+ * @return void
+ */
+function formidable_vider_tables($nom_meta_base_version){
+
+       include_spip('inc/meta');
+       include_spip('base/abstract_sql');
+
+       // On efface les tables du plugin
+       sql_drop_table('spip_formulaires');
+       sql_drop_table('spip_formulaires_reponses');
+       sql_drop_table('spip_formulaires_reponses_champs');
+       sql_drop_table('spip_formulaires_liens');
+
+       // On efface la version entregistrée
+       effacer_meta($nom_meta_base_version);
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formidable_autorisations.php b/www/plugins/formidable_1_0/formidable_autorisations.php
new file mode 100644 (file)
index 0000000..411ee3f
--- /dev/null
@@ -0,0 +1,222 @@
+<?php
+
+/**
+ * Déclaration des autorisations
+ *
+ * @package SPIP\Formidable\Autorisations
+**/
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('action/editer_liens');
+include_spip('inc/config');
+
+/**
+ * Autorisation par auteur et par formulaire
+ *
+ * Seuls les auteurs associés à un formulaire peuvent y accéder
+ *
+ * @param  int   $id        id du formulaire à tester
+ * @param  int   $id_auteur id de l'auteur à tester, si ==0 => auteur courant
+ * @return bool  true s'il a le droit, false sinon
+ *
+*/
+function formidable_autoriser_par_auteur($id, $id_auteur = 0) {
+       if ($id == 0) return true;
+
+       $retour = false;
+
+       if ($id_auteur == 0)
+               $id_auteur = session_get('id_auteur');
+
+       if ($id_auteur == null) {
+               $retour = false;
+       } else {
+               $autorisations = objet_trouver_liens(array('formulaire'=>$id),array('auteur'=>$id_auteur));
+               $retour = count($autorisations) > 0;
+       }
+       return $retour;
+}
+
+/**
+ * Fonction d'appel pour le pipeline
+ * @pipeline autoriser
+ */
+function formidable_autoriser(){}
+
+/**
+ * Autorisation d'éditer un formulaire formidable
+ *
+ * Seuls les admins peuvent éditer les formulaires
+ *
+ * @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_formulaire_editer_dist($faire, $type, $id, $qui, $opt){
+       $auteurs = lire_config('formidable/analyse/auteur');
+
+       /* administrateur ? */
+       if (isset($qui['statut']) and $qui['statut'] <= '0minirezo' and (!$qui['restreint']))
+               return true;
+
+       /* Test des autorisations par auteur */
+       if ($auteurs == 'on') {
+               return formidable_autoriser_par_auteur($id);
+       } else {
+               /* dans un else car la config 'auteurs' doit primer sur l'admin restreint */
+               if ($GLOBALS['formulaires']['autoriser_admin_restreint'])
+                       return true;
+               else
+                       return false;
+       }
+}
+
+/**
+ * Autorisation de voir la liste des formulaires formidable
+ *
+ *  Admins et rédacteurs peuvent voir les formulaires existants
+ *
+ * @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_formulaires_menu_dist($faire, $type, $id, $qui, $opt){
+    if (isset($qui['statut']) and $qui['statut'] <= '1comite') return true;
+    else return false;
+}
+
+
+/**
+ * Autorisation de répondre à un formidable formidable
+ *
+ * On peut répondre à un formulaire si :
+ * - c'est un formulaire classique
+ * - on enregistre et que multiple = oui
+ * - on enregistre et que multiple = non et que la personne n'a pas répondu encore
+ * - on enregistre et que multiple = non et que modifiable = oui
+ *
+ * @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_formulaire_repondre_dist($faire, $type, $id, $qui, $opt){
+// On regarde si il y a déjà le formulaire dans les options
+    if (isset($options['formulaire']))
+        $formulaire = $options['formulaire'];
+    // Sinon on va le chercher
+    else{
+        $formulaire = sql_fetsel('*', 'spip_formulaires', 'id_formulaire = '.$id);
+    }
+
+    $traitements = unserialize($formulaire['traitements']);
+
+    // S'il n'y a pas d'enregistrement, c'est forcément bon
+    if (!($options = $traitements['enregistrement']))
+        return true;
+    // Sinon faut voir les options
+    else{
+        // Si multiple = oui c'est bon
+        if ($options['multiple'])
+            return true;
+        else{
+            // Si c'est modifiable, c'est bon
+            if ($options['modifiable'])
+                return true;
+            else{
+                include_spip('inc/formidable');
+                // Si la personne n'a jamais répondu, c'est bon
+                if (!formidable_verifier_reponse_formulaire($id))
+                    return true;
+                else
+                    return false;
+            }
+        }
+    }
+}
+
+/**
+ * Autorisation d'associer un nouvel auteur à un formulaire
+ *
+ * mêmes autorisations que pour éditer le formulaire
+ *
+**/
+function autoriser_formulaire_associerauteurs_dist($faire, $type, $id, $qui, $opt) {
+       return autoriser_formulaire_editer_dist($faire, $type, $id, $qui, $opt);
+}
+
+/**
+ * Autorisation de modifier un formulaire
+ *
+ * mêmes autorisations que pour éditer le formulaire
+ *
+**/
+function autoriser_formulaire_modifier_dist($faire, $type, $id, $qui, $opt) {
+       return autoriser_formulaire_editer_dist($faire, $type, $id, $qui, $opt);
+}
+
+
+/**
+ * Autorisation d'instituer une réponse
+ *
+ * On peut modérer une réponse si on est admin
+ *
+ * @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_formulaires_reponse_instituer_dist($faire, $type, $id, $qui, $opt){
+    if (isset($qui['statut']) and $qui['statut'] <= '0minirezo' and !$qui['restreint']) return true;
+    else return false;
+}
+
+/**
+ * Autorisation de voir les réponses d'un formulaire formidable
+ *
+ * Au moins rédacteur pour voir les résultats
+ *
+ * @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_formulairesreponse_voir_dist($faire, $type, $id, $qui, $opt){
+       return autoriser_formulaire_editer_dist($faire, $type, $id, $qui, $opt);
+}
+
+/**
+ * Autorisation de supprimer une réponse d'un formulaire formidable
+ *
+ * Il faut pouvoir éditer un formulaire pour pouvoir en supprimer des réponses
+ *
+ * @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_formulairesreponse_supprimer_dist($faire, $type, $id, $qui, $opt){
+    // On récupère l'id du formulaire
+    if ($id_formulaire = intval(sql_getfetsel('id_formulaire', 'spip_formulaires_reponses', $id)))
+        return autoriser('editer', 'formulaire', $id_formulaire);
+    else
+        return false;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formidable_fonctions.php b/www/plugins/formidable_1_0/formidable_fonctions.php
new file mode 100644 (file)
index 0000000..c802999
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+
+/**
+ * Chargement des fonctions pour les squelettes 
+ *
+ * @package SPIP\Formidable\Fonctions
+**/
+
+include_spip('inc/formidable');
+include_spip('public/formidable_criteres');
diff --git a/www/plugins/formidable_1_0/formidable_options.php b/www/plugins/formidable_1_0/formidable_options.php
new file mode 100644 (file)
index 0000000..3530bbd
--- /dev/null
@@ -0,0 +1,126 @@
+<?php
+
+/**
+ * Options globales chargées à chaque hit
+ *
+ * @package SPIP\Formidable\Options
+**/
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// On déclare le formulaire pour éditer un formulaire
+$GLOBALS['formulaires']['editer_formulaire'] = array(
+    array(
+        'saisie' => 'input',
+        'options' => array(
+            'nom' => 'titre',
+            'label' => '<:formidable:editer_titre:>',
+            'obligatoire' => 'oui',
+            'class' => 'multilang'
+        )
+    ),
+    array(
+        'saisie' => 'input',
+        'options' => array(
+            'nom' => 'identifiant',
+            'label' => '<:formidable:editer_identifiant:>',
+            'explication' => '<:formidable:editer_identifiant_explication:>',
+            'obligatoire' => 'oui'
+        ),
+        'verifier' => array(
+            'type' => 'regex',
+            'options' => array(
+                'modele' => '/^[\w]+$/'
+            )
+        )
+    ),
+    array(
+        'saisie' => 'textarea',
+        'options' => array(
+            'nom' => 'message_retour',
+            'label' => '<:formidable:editer_message_ok:>',
+            'explication' => '<:formidable:editer_message_ok_explication:>',
+            'rows' => 5,
+            'li_class' => 'editer_texte',
+            'class' => 'multilang'
+        )
+    ),
+    array(
+        'saisie' => 'textarea',
+        'options' => array(
+            'nom' => 'descriptif',
+            'label' => '<:formidable:editer_descriptif:>',
+            'explication' => '<:formidable:editer_descriptif_explication:>',
+            'rows' => 5,
+            'class' => 'multilang'
+        )
+    ),
+    array(
+        'saisie' => 'selection',
+        'options' => array(
+            'nom' => 'apres',
+            'label' => '<:formidable:editer_apres_label:>',
+            'explication' => '<:formidable:editer_apres_explication:>',
+            'datas' => array(
+                'formulaire' => _T('formidable:editer_apres_choix_formulaire'),
+                'valeurs' => _T('formidable:editer_apres_choix_valeurs'),
+                'stats' => _T('formidable:editer_apres_choix_stats'),
+                'rien' => _T('formidable:editer_apres_choix_rien'),
+                'redirige' => _T('formidable:editer_apres_choix_redirige'),
+            ),
+            'defaut' => 'formulaire',
+            'cacher_option_intro' => 'on'
+        )
+    ),
+    array(
+        'saisie' => 'input',
+        'options' => array(
+            'nom' => 'url_redirect',
+            'label' => '<:formidable:editer_redirige_url:>',
+            'explication' => '<:formidable:editer_redirige_url_explication:>',
+            'obligatoire' => 'non'
+        )
+    )
+);
+
+/* déclaration des différentes variables utilisées pour effectuer l'anonymisation */
+$GLOBALS['formulaires']['variables_anonymisation'] = array(
+       'remote_user' => '$_SERVER["REMOTE_USER"]',
+       'php_auth_user' => '$_SERVER["PHP_AUTH_USER"]',
+);
+
+/*
+* on se contente d'initialiser si ces variable si elles ne
+* le sont pas dans mes_options.php de l'instance
+*/
+if (isset($GLOBALS['formulaires']['passwd']) == false) {
+       $GLOBALS['formulaires']['passwd'] = array(
+               'interne' => 'palabresecreta',
+       );
+}
+
+if (isset($GLOBALS['formulaires']['autoriser_admin_restreint']) == false) {
+       $GLOBALS['formulaires']['autoriser_admin_restreint'] = false;
+}
+
+if (!function_exists('array_fill_keys')) {
+    /**
+     * Remplit un tableau avec des valeurs, en spécifiant les clés
+     *
+     * Fonction dans PHP 5.2+
+     * @see http://php.net/manual/fr/function.array-fill-keys.php
+     *
+     * @param array $keys
+     *     Tableau de valeurs qui sera utilisé comme clés.
+     * @param mixed $value
+     *     Valeur à utiliser pour remplir le tableau.
+     * @return array
+     *     Le tableau rempli.
+    **/
+    function array_fill_keys($keys, $value){
+        array_combine($keys,array_fill(0,count($keys),$value));
+    }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formidable_pipelines.php b/www/plugins/formidable_1_0/formidable_pipelines.php
new file mode 100644 (file)
index 0000000..902224b
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * Utilisation de pipelines
+ * 
+ * @package SPIP\Formidable\Pipelines
+**/
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+/**
+ * Optimiser la base de donnée en enlevant les liens de formulaires supprimés
+ * 
+ * @pipeline optimiser_base_disparus
+ * @param array $flux
+ *     Données du pipeline
+ * @return array
+ *     Données du pipeline
+ */
+function formidable_optimiser_base_disparus($flux){
+       // Les réponses qui sont à la poubelle
+       $res = sql_select(
+               'id_formulaires_reponse AS id',
+               'spip_formulaires_reponses',
+               'statut = '.sql_quote('poubelle')
+       );
+       
+       // On génère la suppression
+       $flux['data'] += optimiser_sansref('spip_formulaires_reponses', 'id_formulaires_reponse', $res);
+       return $flux;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formulaires/configurer_formidable_analyse.html b/www/plugins/formidable_1_0/formulaires/configurer_formidable_analyse.html
new file mode 100644 (file)
index 0000000..f93413b
--- /dev/null
@@ -0,0 +1,24 @@
+<div class="formulaire_spip formulaire_configurer formulaire_#FORM">
+
+       <h3 class="titrem"><:formidable:cfg_titre_parametrages_analyse:></h3>
+
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+       <form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+
+               [(#SAISIE{input,classe,
+                       label=<:formidable:cfg_analyse_classe_label:>,
+                       explication=<:formidable:cfg_analyse_classe_explication:>
+                       })]
+               [(#SAISIE{oui_non,auteur,
+                       label=<:formidable:traiter_enregistrement_option_auteur:>,
+                       explication=<:formidable:traiter_enregistrement_option_auteur_explication:>
+                       })]
+               <input type="hidden" name="_meta_casier" value="formidable/analyse" />
+               <p class="boutons"><span class="image_loading">&nbsp;</span><input type="submit" class="submit" value="<:bouton_enregistrer:>" /></p>
+       </div>
+       </form>
+</div>
diff --git a/www/plugins/formidable_1_0/formulaires/editer_formulaire.html b/www/plugins/formidable_1_0/formulaires/editer_formulaire.html
new file mode 100644 (file)
index 0000000..cd8445e
--- /dev/null
@@ -0,0 +1,23 @@
+<div class="formulaire_spip formulaire_editer formulaire_#ENV{form}[ formulaire_#ENV{form}-(#ENV{id_formulaire,nouveau})]">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       [(#ENV{editable}|oui)
+       <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire 
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               
+               <ul>
+                       #GENERER_SAISIES{#ENV{_contenu}}
+               </ul>
+               
+               [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
+               <!--extra-->
+               
+               <p class='boutons'>
+                       <span class='image_loading'></span>
+                       <input type='submit' class='submit' value='<:bouton_enregistrer:>' />
+               </p>
+       </div></form>
+       ]
+</div>
diff --git a/www/plugins/formidable_1_0/formulaires/editer_formulaire.php b/www/plugins/formidable_1_0/formulaires/editer_formulaire.php
new file mode 100644 (file)
index 0000000..5975036
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/saisies');
+include_spip('action/editer_liens');
+include_spip('inc/config');
+
+function formulaires_editer_formulaire_charger($id_formulaire, $nouveau){
+       $contexte = array();
+       $editer_formulaire = $GLOBALS['formulaires']['editer_formulaire'];
+       $champs = saisies_lister_champs($editer_formulaire);
+       $id_formulaire = intval($id_formulaire);
+       
+       $contexte['_contenu'] = $editer_formulaire;
+       
+       // Est-ce qu'on a le droit ?
+       if (autoriser('editer', 'formulaire', $id_formulaire)){
+               // Est-ce que le formulaire existe ?
+               if ($id_formulaire > 0 and $formulaire = sql_fetsel('*', 'spip_formulaires', 'id_formulaire = '.$id_formulaire)){
+                       // Alors on pré-remplit avec les valeurs
+                       foreach($champs as $champ)
+                               $contexte[$champ] = $formulaire[$champ];
+                       $contexte['_action'] = array('editer_formulaire', $id_formulaire);
+               }
+               // Sinon si c'est une création
+               elseif ($nouveau == 'oui'){
+                       // On déclare juste les champs
+                       foreach ($champs as $champ)
+                               $contexte[$champ] = '';
+                       $contexte['_action'] = array('editer_formulaire', $nouveau);
+               }
+               // Sinon c'est n'importe quoi
+               else{
+                       $contexte['editable'] = false;
+                       $contexte['message_erreur'] = 'Erreur dans les parametres.';
+               }
+       }
+       else{
+               $contexte['editable'] = false;
+               $contexte['message_erreur'] = _T('formidable:erreur_autorisation');
+       }
+       
+       return $contexte;
+}
+
+function formulaires_editer_formulaire_verifier($id_formulaire, $nouveau){
+       $configurer_formulaire = $GLOBALS['formulaires']['editer_formulaire'];
+       $erreurs = saisies_verifier($configurer_formulaire);
+       // On vérifie l'unicité de l'identifiant
+       if (!$erreurs['identifiant'] and sql_getfetsel('id_formulaire', 'spip_formulaires', 'identifiant = '.sql_quote(_request('identifiant').' and id_formulaire != '.$id_formulaire)))
+               $erreurs['identifiant'] = _T('formidable:erreur_identifiant');
+       return $erreurs;
+}
+
+function formulaires_editer_formulaire_traiter($id_formulaire, $nouveau){
+       include_spip('inc/editer');
+       $id_formulaire = $id_formulaire ? $id_formulaire : $nouveau;
+       $retours = formulaires_editer_objet_traiter('formulaire', $id_formulaire);
+       
+       // S'il n'y a pas d'erreur et que le formulaire est bien là
+       if (!$retours['message_erreur'] and $retours['id_formulaire'] > 0){
+               // Si c'était un nouveau on reste sur l'édition
+               if (!intval($id_formulaire) and $nouveau == 'oui'){
+                       // Tout a fonctionné. En fonction de la config, on attribue l'auteur courant
+                       $auteurs = lire_config('formidable/analyse/auteur');
+                       if ($auteurs == 'on') {
+                               if ($id_auteur = session_get('id_auteur')) {
+                                       // association (par défaut) du formulaire et de l'auteur courant
+                                       objet_associer(array('formulaire'=>$retours['id_formulaire']), array('auteur'=>$id_auteur));
+                               }
+                       }
+                       $retours['redirect'] = parametre_url(generer_url_ecrire('formulaire_edit'), 'id_formulaire', $retours['id_formulaire'], '&');
+               }
+               // Sinon on redirige vers la page de visualisation
+               else{
+                       $retours['redirect'] = parametre_url(generer_url_ecrire('formulaire'), 'id_formulaire', $retours['id_formulaire'], '&');
+               }
+       }
+       
+       return $retours;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formulaires/editer_formulaire_champs.html b/www/plugins/formidable_1_0/formulaires/editer_formulaire_champs.html
new file mode 100644 (file)
index 0000000..8e88ff4
--- /dev/null
@@ -0,0 +1,39 @@
+
+<div class="formulaire_spip formulaire_editer formulaire_#ENV{form}[ formulaire_#ENV{form}-(#ENV{id,nouveau})]">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       
+       [(#ENV*{message_erreur}|non)
+       <div class="ajax">
+               #FORMULAIRE_CONSTRUIRE_FORMULAIRE{formidable_#ENV{id}, #ENV{_saisies}}
+       </div>
+       ]
+
+       [(#ENV{editable}|oui)
+       <form method="post" action="#ENV{action}" enctype="multipart/form-data"><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire 
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               
+               <p class="boutons">
+                       <span class="image_loading"></span>
+                       [(#ENV*{message_erreur}|non)
+                       <em class="attention"><:saisies:construire_attention_enregistrer:></em>
+                       <button type="submit" class="submit">
+                               <img src="#CHEMIN{images/formulaire-enregistrer-16.png}" alt="" />
+                               <:bouton_enregistrer:>
+                       </button>
+                       ]
+                       [(#ENV*{message_erreur}|oui)
+                       <button type="submit" class="link" name="annulation" value="oui">
+                               <:bouton_annuler:>
+                       </button>
+                       <button type="submit" class="submit" name="confirmation" value="oui">
+                               <img src="#CHEMIN{images/formulaire-enregistrer-16.png}" alt="" />
+                               <:bouton_enregistrer:>
+                       </button>
+                       ]
+               </p>
+       </div></form>
+       ]
+</div>
diff --git a/www/plugins/formidable_1_0/formulaires/editer_formulaire_champs.php b/www/plugins/formidable_1_0/formulaires/editer_formulaire_champs.php
new file mode 100644 (file)
index 0000000..e999c7b
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+function formulaires_editer_formulaire_champs_charger($id_formulaire){
+       $contexte = array();
+       $id_formulaire = intval($id_formulaire);
+       
+       // On teste si le formulaire existe
+       if ($id_formulaire
+               and $formulaire = sql_fetsel('*', 'spip_formulaires', 'id_formulaire = '.$id_formulaire)
+               and autoriser('editer', 'formulaire', $id_formulaire)
+       ){
+               $saisies = unserialize($formulaire['saisies']);
+               if (!is_array($saisies)) $saisies = array();
+               $contexte['_saisies'] = $saisies;
+               $contexte['id'] = $id_formulaire;
+       }
+       
+       return $contexte;
+}
+
+function formulaires_editer_formulaire_champs_verifier($id_formulaire){
+       include_spip('inc/saisies');
+       $erreurs = array();
+       
+       // Si c'est pas une confirmation ni une annulation
+       if (!_request('confirmation') and !($annulation = _request('annulation'))){
+               // On récupère le formulaire dans la session
+               $saisies_nouvelles = session_get("constructeur_formulaire_formidable_$id_formulaire");
+       
+               // On récupère les anciennes saisies
+               $saisies_anciennes = unserialize(sql_getfetsel(
+                       'saisies',
+                       'spip_formulaires',
+                       'id_formulaire = '.$id_formulaire
+               ));
+       
+               // On compare
+               $comparaison = saisies_comparer($saisies_anciennes, $saisies_nouvelles);
+       
+               // S'il y a des suppressions, on demande confirmation avec attention
+               if ($comparaison['supprimees'])
+                       $erreurs['message_erreur'] = _T('saisies:construire_attention_supprime');
+       }
+       // Si on annule on génère une erreur bidon juste pour réafficher le formulaire
+       elseif ($annulation){
+               $erreurs['pouetpouet'] = true;
+       }
+       
+       return $erreurs;
+}
+
+function formulaires_editer_formulaire_champs_traiter($id_formulaire){
+       include_spip('inc/saisies');
+       $retours = array();
+       $id_formulaire = intval($id_formulaire);
+       
+       // On récupère le formulaire dans la session
+       $saisies_nouvelles = session_get("constructeur_formulaire_formidable_$id_formulaire");
+       
+       // On récupère les anciennes saisies
+       $saisies_anciennes = unserialize(sql_getfetsel(
+               'saisies',
+               'spip_formulaires',
+               'id_formulaire = '.$id_formulaire
+       ));
+       
+       // On envoie les nouvelles dans la table dans la table
+       $ok = sql_updateq(
+               'spip_formulaires',
+               array(
+                       'saisies' => serialize($saisies_nouvelles)
+               ),
+               'id_formulaire = '.$id_formulaire
+       );
+       
+       // Si c'est bon on appelle d'éventuelles fonctions d'update des traitements puis on renvoie vers la config des traitements
+       if ($ok){
+               // On va chercher les traitements
+               $traitements = unserialize(sql_getfetsel(
+                       'traitements',
+                       'spip_formulaires',
+                       'id_formulaire = '.$id_formulaire
+               ));
+               
+               // Pour chaque traitements on regarde s'i y a une fonction d'update
+               if (is_array($traitements))
+                       foreach ($traitements as $type_traitement => $traitement){
+                               if ($update = charger_fonction('update', "traiter/$type_traitement", true)){
+                                       $update($id_formulaire, $traitement, $saisies_anciennes, $saisies_nouvelles);
+                               }
+                       }
+               
+               // On redirige vers la config suivante
+               $retours['redirect'] = parametre_url(
+                       parametre_url(
+                               parametre_url(
+                                       generer_url_ecrire('formulaire_edit')
+                                       , 'id_formulaire', $id_formulaire
+                               )
+                               , 'configurer', 'traitements'
+                       )
+                       , 'avertissement', 'oui'
+               );
+       }
+       
+       return $retours;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formulaires/editer_formulaire_traitements.html b/www/plugins/formidable_1_0/formulaires/editer_formulaire_traitements.html
new file mode 100644 (file)
index 0000000..31dbc36
--- /dev/null
@@ -0,0 +1,41 @@
+<div class="formulaire_spip formulaire_editer formulaire_#ENV{form}[ formulaire_#ENV{form}-(#ENV{id,nouveau})]">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       
+       [(#ENV{editable}|oui)
+       <form method="post" action="#ENV{action}" enctype="multipart/form-data"><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire 
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               
+               <ul>
+                       #GENERER_SAISIES{#ENV{_configurer_traitements}}
+               </ul>
+               
+               [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
+               <!--extra-->
+               
+               <p class="boutons"><span class="image_loading"></span><input type="submit" class="submit" value="<:bouton_enregistrer:>" /></p>
+       </div></form>
+       <script type="text/javascript">
+               $(function(){
+                       // On commence par cacher toutes les options
+                       $('.options_traiter').hide().find('h3').hide();
+                       
+                       // Ensuite on parcourt les traitements choisis
+                       $('.editer_traitements_choisis input')
+                               .each(function(){
+                                       // Si c'est coché on affiche le fieldset d'options
+                                       if ($(this).is(':checked')){
+                                               $('.options_traiter.'+$(this).val()).show();
+                                               $(this).parents('.editer_traitements_choisis').toggleClass('hover');
+                                       }
+                               })
+                               .click(function(){
+                                       $('.options_traiter.'+$(this).val()).slideToggle('fast');
+                                       $(this).parents('.editer_traitements_choisis').toggleClass('hover');
+                               });
+               });
+       </script>
+       ]
+</div>
diff --git a/www/plugins/formidable_1_0/formulaires/editer_formulaire_traitements.php b/www/plugins/formidable_1_0/formulaires/editer_formulaire_traitements.php
new file mode 100644 (file)
index 0000000..2303ec6
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/formidable');
+
+function formulaires_editer_formulaire_traitements_charger($id_formulaire){
+       $contexte = array();
+       $id_formulaire = intval($id_formulaire);
+       
+       // On teste si le formulaire existe
+       if ($id_formulaire
+               and $formulaire = sql_fetsel('*', 'spip_formulaires', 'id_formulaire = '.$id_formulaire)
+               and autoriser('editer', 'formulaire', $id_formulaire)
+       ){
+               $traitements = unserialize($formulaire['traitements']);
+               $saisies = unserialize($formulaire['saisies']);
+               if (!is_array($traitements)) $traitements = array();
+               if (!is_array($saisies)) $saisies = array();
+               $contexte['traitements'] = $traitements;
+               $contexte['traitements_choisis'] = array_keys($traitements);
+               $contexte['formulaire'] = _T_ou_typo($saisies, 'multi');
+               $contexte['id'] = $id_formulaire;
+               
+               $traitements_disponibles = traitements_lister_disponibles();
+               $configurer_traitements = array();
+               foreach ($traitements_disponibles as $type_traitement => $traitement){
+                       $configurer_traitements[] = array(
+                               'saisie' => 'checkbox',
+                               'options' => array(
+                                       'nom' => 'traitements_choisis',
+                                       'label' => $traitement['titre'],
+                                       'datas' => array(
+                                               $type_traitement => $traitement['description']
+                                       )
+                               )
+                       );
+                       $configurer_traitements[] = array(
+                               'saisie' => 'fieldset',
+                               'options' => array(
+                                       'nom' => 'options',
+                                       'label' => $traitement['titre'],
+                                       'li_class' => "$type_traitement options_traiter"
+                               ),
+                               'saisies' => saisies_transformer_noms($traitement['options'], '/^.*$/', "traitements[$type_traitement][\\0]")
+                       );
+               }
+               $contexte['_configurer_traitements'] = $configurer_traitements;
+               
+               // Si on demande un avertissement et qu'il y a déjà des traitements de configurés
+               if (_request('avertissement') == 'oui')
+                       $contexte['message_ok'] = $traitements ? _T('formidable:traitements_avertissement_modification') : _T('formidable:traitements_avertissement_creation');
+       }
+       else{
+               $contexte['editable'] = false;
+       }
+       
+       // On enlève l'éventuel avertissement pour le prochain envoi
+       $contexte['action'] = parametre_url(self(), 'avertissement', '');
+       
+       return $contexte;
+}
+
+function formulaires_editer_formulaire_traitements_verifier($id_formulaire){
+       include_spip('inc/saisies');
+       $erreurs = array();
+       $traitements_disponibles = traitements_lister_disponibles();
+       
+       // On regarde quels traitements sont demandés
+       $traitements_choisis = _request('traitements_choisis');
+       
+       if (is_array($traitements_choisis))
+               foreach ($traitements_choisis as $type_traitement){
+                       $erreurs = array_merge($erreurs, saisies_verifier(saisies_transformer_noms($traitements_disponibles[$type_traitement]['options'], '/^.*$/', "traitements[$type_traitement][\\0]")));
+               }
+       
+       return $erreurs;
+}
+
+function formulaires_editer_formulaire_traitements_traiter($id_formulaire){
+       $retours = array();
+       $id_formulaire = intval($id_formulaire);
+       
+       // On récupère tout le tableau des traitements
+       $traitements = _request('traitements');
+       // On ne garde que les morceaux qui correspondent aux traitements choisis
+       $traitements_choisis = _request('traitements_choisis');
+       if (!$traitements_choisis) $traitements_choisis = array();
+       $traitements_choisis = array_flip($traitements_choisis);
+       $traitements = array_intersect_key($traitements, $traitements_choisis);
+       
+       // Et on l'enregistre tel quel
+       $ok = sql_updateq(
+               'spip_formulaires',
+               array(
+                       'traitements' => serialize($traitements)
+               ),
+               'id_formulaire = '.$id_formulaire
+       );
+       
+       // On va sur la page de visualisation quand c'est fini
+       if ($ok){
+               $retours['redirect'] = parametre_url(generer_url_ecrire('formulaire'), 'id_formulaire', $id_formulaire);
+       }
+       else{
+               $retours['editable'] = true;
+               $retours['message_erreur'] = _T('formidable:erreur_base');
+       }
+       
+       return $retours;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formulaires/formidable.html b/www/plugins/formidable_1_0/formulaires/formidable.html
new file mode 100644 (file)
index 0000000..9727ab5
--- /dev/null
@@ -0,0 +1,46 @@
+<BOUCLE_remplacer_le_formulaire(CONDITION){si #ENV{_remplacer_formulaire}}>\r
+    [(#REM) Afficher du HTML si prévu par un plugin ou pour les stats ]\r
+    [(#ENV**{_remplacer_formulaire})]\r
+</BOUCLE_remplacer_le_formulaire>\r
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire=#ENV{id}}>\r
+       [(#SET{enregistrement,[(#TRAITEMENTS**|unserialize|table_valeur{'enregistrement'})]})]\r
+       [(#SET{anonymiser,[(#GET{enregistrement}|table_valeur{'anonymiser'})]})]\r
+       [(#GET{anonymiser}|=={on}|oui)<h3><:formidable:formulaire_anonyme_explication:></h3>]\r
+</BOUCLE_formulaire>\r
+<div class="formulaire_spip formulaire_#ENV{form}[ formulaire_#ENV{form}-(#ENV{id,nouveau})]">\r
+    [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+    [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+\r
+    [(#ENV{editable}|oui)\r
+    <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div>\r
+        [(#REM) declarer les hidden qui declencheront le service du formulaire\r
+        parametre : url d'action ]\r
+        #ACTION_FORMULAIRE{#ENV{action}}\r
+\r
+        <ul>\r
+            #GENERER_SAISIES{#ENV{_saisies}}\r
+            <li style="display:none;">\r
+                <label for="mechantrobot-#ENV{id}"><:antispam_champ_vide:></label>\r
+                <input type="text" id="mechantrobot-#ENV{id}" name="mechantrobot" value="#ENV{mechantrobot}" />\r
+            </li>\r
+        </ul>\r
+\r
+        [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]\r
+        <!--extra-->\r
+\r
+        <p class='boutons'>\r
+            <span class='image_loading'></span>\r
+            <input type='submit' class='submit' value='<:bouton_valider:>' />\r
+        </p>\r
+    </div></form>\r
+    ]\r
+    [(#EDITABLE|non)\r
+        [(#ENV{formidable_afficher_apres}|=={valeurs}|oui)\r
+            #VOIR_SAISIES{#ENV*{_saisies},#ENV}\r
+        ]\r
+        [(#ENV{formidable_afficher_apres}|=={rien}|oui)\r
+        ]\r
+    ]\r
+    <br />\r
+</div>\r
+<//B_remplacer_le_formulaire>\r
diff --git a/www/plugins/formidable_1_0/formulaires/formidable.php b/www/plugins/formidable_1_0/formulaires/formidable.php
new file mode 100644 (file)
index 0000000..4198c46
--- /dev/null
@@ -0,0 +1,292 @@
+<?php
+
+/**
+ * Gestion de l'affichage et traitement d'un formulaire Formidable
+ *
+ * @package SPIP\Formidable\Formulaires
+**/
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/formidable');
+include_spip('inc/saisies');
+include_spip('base/abstract_sql');
+include_spip('inc/autoriser');
+
+/**
+ * Chargement du formulaire CVT de Formidable.
+ *
+ * Genere le formulaire dont l'identifiant (numerique ou texte est indique)
+ *
+ * @param int|string $id_formulaire
+ *     Identifiant numerique ou textuel du formulaire formidable
+ * @param array $valeurs
+ *     Valeurs par défauts passées au contexte du formulaire
+ *     Exemple : array('hidden_1' => 3) pour que champ identifie "@hidden_1@" soit prerempli
+ * @param int|bool $id_formulaires_reponse
+ *     Identifiant d'une réponse pour forcer la reedition de cette reponse spécifique
+ *
+ * @return array
+ *     Contexte envoyé au squelette HTML du formulaire.
+**/
+function formulaires_formidable_charger($id_formulaire, $valeurs=array(), $id_formulaires_reponse=false){
+    $contexte = array();
+
+    // On peut donner soit un id soit un identifiant
+    if (intval($id_formulaire) > 0)
+        $where = 'id_formulaire = '.intval($id_formulaire);
+    elseif (is_string($id_formulaire))
+        $where = 'identifiant = '.sql_quote($id_formulaire);
+    else
+        return;
+
+    // On cherche si le formulaire existe
+    if ($formulaire = sql_fetsel('*', 'spip_formulaires', $where)) {
+        // on ajoute un point d'entrée avec les infos de ce formulaire
+        // pour d'eventuels plugins qui en ont l'utilité
+        $contexte += array('_formidable' => $formulaire);
+        // Est-ce que la personne a le droit de répondre ?
+        if (autoriser('repondre', 'formulaire', $formulaire['id_formulaire'], null, array('formulaire'=>$formulaire))){
+            $saisies = unserialize($formulaire['saisies']);
+            $traitements = unserialize($formulaire['traitements']);
+            // On déclare les champs
+            $contexte += array_fill_keys(saisies_lister_champs($saisies), '');
+            $contexte['mechantrobot'] = '';
+            // On ajoute le formulaire complet
+            $contexte['_saisies'] = $saisies;
+
+            $contexte['id'] = $formulaire['id_formulaire'];
+            $contexte['_hidden'] = '<input type="hidden" name="id_formulaire" value="'.$contexte['id'].'"/>';
+
+            // S'il y a des valeurs par défaut dans l'appel, alors on pré-remplit
+            if ($valeurs){
+                // Si c'est une chaine on essaye de la parser
+                if (is_string($valeurs)){
+                    $liste = explode(',', $valeurs);
+                    $liste = array_map('trim', $liste);
+                    $valeurs = array();
+                    foreach ($liste as $i=>$cle_ou_valeur){
+                        if ($i % 2 == 0)
+                            $valeurs[$liste[$i]] = $liste[$i+1];
+                    }
+                }
+
+                // On regarde si maintenant on a un tableau
+                if ($valeurs and is_array($valeurs)){
+                    $contexte = array_merge($contexte, $valeurs);
+                }
+            }
+
+            // Si on passe un identifiant de reponse, on edite cette reponse si elle existe
+            if ($id_formulaires_reponse = intval($id_formulaires_reponse)) {
+                $contexte = formidable_definir_contexte_avec_reponse($contexte, $id_formulaires_reponse, $ok);
+                if ($ok) {
+                    // On ajoute un hidden pour dire que c'est une modif
+                    $contexte['_hidden'] .= "\n".'<input type="hidden" name="deja_enregistre_'.$formulaire['id_formulaire'].'" value="'.$id_formulaires_reponse.'"/>';
+                } else {
+                    $contexte['editable'] = false;
+                    $contexte['message_erreur'] = _T('formidable:traiter_enregistrement_erreur_edition_reponse_inexistante');
+                }
+            } else {
+
+                // calcul des paramètres d'anonymisation
+                $anonymisation = (isset($options['anonymiser']) && $options['anonymiser'] == true)
+                    ? isset($options['anonymiser_variable']) ? $options['anonymiser_variable'] : ''
+                    : '';
+
+                // Si multiple = non mais que c'est modifiable, alors on va chercher
+                // la dernière réponse si elle existe
+                if ($options = $traitements['enregistrement']
+                    and !$options['multiple']
+                    and $options['modifiable']
+                    and $reponses = formidable_verifier_reponse_formulaire($formulaire['id_formulaire'], $options['identification'], $anonymisation)
+                ){
+                    $id_formulaires_reponse = array_pop($reponses);
+                    $contexte = formidable_definir_contexte_avec_reponse($contexte, $id_formulaires_reponse, $ok);
+
+                    // On ajoute un hidden pour dire que c'est une modif
+                    $contexte['_hidden'] .= "\n".'<input type="hidden" name="deja_enregistre_'.$formulaire['id_formulaire'].'" value="'.$id_formulaires_reponse.'"/>';
+                }
+
+            }
+        }
+        else{
+            $contexte['editable'] = false;
+            // le formulaire a déjà été répondu.
+            // peut être faut il afficher les statistiques des réponses
+            if ($formulaire['apres'] == 'stats') {
+                // Nous sommes face à un sondage auquel on a déjà répondu !
+                // On remplace complètement l'affichage du formulaire
+                // par un affichage du résultat de sondage !
+                $contexte['_remplacer_formulaire'] = recuperer_fond('modeles/formulaire_analyse', array(
+                    'id_formulaire' => $formulaire['id_formulaire'],
+                ));
+            } else {
+                $contexte['message_erreur'] = _T('formidable:traiter_enregistrement_erreur_deja_repondu');
+            }
+        }
+    }
+    else{
+        $contexte['editable'] = false;
+        $contexte['message_erreur'] = _T('formidable:erreur_inexistant');
+    }
+    if (!isset($contexte['_hidden'])) {
+        $contexte['_hidden'] = '';
+    }
+    $contexte['_hidden'] .= "\n".'<input type="hidden" name="formidable_afficher_apres'/*.$formulaire['id_formulaire']*/.'" value="'.$formulaire['apres'].'"/>';// marche pas
+
+    $contexte['formidable_afficher_apres']=$formulaire['apres'];
+
+    return $contexte;
+}
+
+
+/**
+ * Vérification du formulaire CVT de Formidable.
+ *
+ * Pour chaque champ posté, effectue les vérifications demandées par
+ * les saisies et retourne éventuellement les erreurs de saisie.
+ *
+ * @param int|string $id_formulaire
+ *     Identifiant numerique ou textuel du formulaire formidable
+ * @param array $valeurs
+ *     Valeurs par défauts passées au contexte du formulaire
+ *     Exemple : array('hidden_1' => 3) pour que champ identifie "@hidden_1@" soit prerempli
+ * @param int|bool $id_formulaires_reponse
+ *     Identifiant d'une réponse pour forcer la reedition de cette reponse spécifique
+ *
+ * @return array
+ *     Tableau des erreurs
+**/
+function formulaires_formidable_verifier($id_formulaire, $valeurs=array(), $id_formulaires_reponse=false){
+    $erreurs = array();
+
+    // Sale bête !
+    if (_request('mechantrobot') != ''){
+        $erreurs['hahahaha'] = 'hahahaha';
+        return $erreurs;
+    }
+
+    $id_formulaire = intval(_request('id_formulaire'));
+    $formulaire = sql_fetsel('*', 'spip_formulaires', 'id_formulaire = '.$id_formulaire);
+    $saisies = unserialize($formulaire['saisies']);
+
+    $erreurs = saisies_verifier($saisies);
+
+    if ($erreurs and !isset($erreurs['message_erreur']))
+        $erreurs['message_erreur'] = _T('formidable:erreur_generique');
+
+    return $erreurs;
+}
+
+
+/**
+ * Traitement du formulaire CVT de Formidable.
+ *
+ * Exécute les traitements qui sont indiqués dans la configuration des
+ * traitements de ce formulaire formidable.
+ *
+ * Une fois fait, gère le retour après traitements des saisies en fonction
+ * de ce qui a été configuré dans le formulaire, par exemple :
+ * - faire réafficher le formulaire,
+ * - faire afficher les saisies
+ * - rediriger sur une autre page...
+ *
+ * @param int|string $id_formulaire
+ *     Identifiant numerique ou textuel du formulaire formidable
+ * @param array $valeurs
+ *     Valeurs par défauts passées au contexte du formulaire
+ *     Exemple : array('hidden_1' => 3) pour que champ identifie "@hidden_1@" soit prerempli
+ * @param int|bool $id_formulaires_reponse
+ *     Identifiant d'une réponse pour forcer la reedition de cette reponse spécifique
+ *
+ * @return array
+ *     Tableau des erreurs
+**/
+function formulaires_formidable_traiter($id_formulaire, $valeurs=array(), $id_formulaires_reponse=false){
+    $retours = array();
+
+    $id_formulaire = intval(_request('id_formulaire'));
+    $formulaire = sql_fetsel('*', 'spip_formulaires', 'id_formulaire = '.$id_formulaire);
+    $traitements = unserialize($formulaire['traitements']);
+
+    // selon le choix, le formulaire se remet en route à la fin ou non
+    $retours['editable'] = ($formulaire['apres']=='formulaire');
+    $retours['formidable_afficher_apres'] = $formulaire['apres'];
+
+    // Si on a une redirection valide
+    if (($formulaire['apres']== "redirige") AND ($formulaire['url_redirect']!="")) {
+        refuser_traiter_formulaire_ajax();
+        // traiter les raccourcis artX, brX
+        include_spip("inc/lien");
+        $url_redirect = typer_raccourci($formulaire['url_redirect']);
+        if (count($url_redirect)>2) {
+            $url_redirect = $url_redirect[0].$url_redirect[2];
+        } else {
+            $url_redirect = $formulaire['url_redirect'];      // URL classique
+        }
+
+        $retours['redirect'] = $url_redirect;
+    }
+
+    // Si on a des traitements
+    if (is_array($traitements) and !empty($traitements)) {
+        foreach($traitements as $type_traitement=>$options){
+            if ($appliquer_traitement = charger_fonction($type_traitement, 'traiter/', true)) {
+                $retours = $appliquer_traitement(
+                    array(
+                        'formulaire' => $formulaire,
+                        'options' => $options
+                    ),
+                    $retours
+                );
+            }
+        }
+
+        // Si on a personnalisé le message de retour, c'est lui qui est affiché uniquement
+        if ($formulaire['message_retour']) {
+            $retours['message_ok'] = _T_ou_typo($formulaire['message_retour']);
+        }
+    }
+    else{
+        $retours['message_ok'] = _T('formidable:retour_aucun_traitement');
+    }
+
+    return $retours;
+}
+
+
+/**
+ * Ajoute dans le contexte les elements
+ * donnés par une reponse de formulaire indiquée
+ *
+ * @param array $contexte
+ *     Contexte pour le squelette HTML du formulaire
+ * @param int $id_formulaires_reponse
+ *     Identifiant de réponse
+ * @param bool $ok
+ *     La reponse existe bien ?
+ * @return array $contexte
+ *     Contexte complète des nouvelles informations
+ *
+**/
+function formidable_definir_contexte_avec_reponse($contexte, $id_formulaires_reponse, &$ok) {
+    // On va chercher tous les champs
+    $champs = sql_allfetsel(
+        'nom, valeur',
+        'spip_formulaires_reponses_champs',
+        'id_formulaires_reponse = '.$id_formulaires_reponse
+    );
+    $ok = count($champs) ? true : false;
+
+    // On remplit le contexte avec
+    foreach ($champs as $champ){
+        $test_array = unserialize($champ['valeur']);
+        $contexte[$champ['nom']] = is_array($test_array) ? $test_array : $champ['valeur'];
+    }
+
+    return $contexte;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/formulaires/importer_formulaire.html b/www/plugins/formidable_1_0/formulaires/importer_formulaire.html
new file mode 100644 (file)
index 0000000..0d71a5f
--- /dev/null
@@ -0,0 +1,30 @@
+<div class="formulaire_spip formulaire_#ENV{form}[ formulaire_#ENV{form}-(#ENV{id})]">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       
+       [(#ENV{editable}|oui)
+       <form method="post" action="#ENV{action}" enctype="multipart/form-data"><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire 
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               
+               <ul>
+                       [(#SAISIE{selection, type_import,
+                               label=<:formidable:importer_formulaire_format_label:>,
+                               datas=#ENV{_types_import},
+                               defaut=yaml,
+                               cacher_option_intro=oui})]
+                       
+                       [(#SAISIE{input, fichier,
+                               label=<:formidable:importer_formulaire_fichier_label:>,
+                               type=file,
+                               size=6})]
+               </ul>
+               
+               [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
+               <!--extra-->
+               
+               <p class="boutons"><span class="image_loading"></span><input type="submit" class="submit" value="<:bouton_telecharger:>" /></p>
+       </div></form>
+       ]
+</div>
diff --git a/www/plugins/formidable_1_0/formulaires/importer_formulaire.php b/www/plugins/formidable_1_0/formulaires/importer_formulaire.php
new file mode 100644 (file)
index 0000000..be0759f
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/formidable');
+include_spip('inc/config');
+
+function formulaires_importer_formulaire_charger(){
+       
+       $contexte = array();
+       
+       // On va chercher toutes les fonctions d'importation existantes
+       $types_echange = echanges_formulaire_lister_disponibles();
+       $types_import = array();
+       foreach ($types_echange['importer'] as $type=>$fonction){
+               $types_import[$type] = _T("formidable:echanger_formulaire_${type}_importer");
+       }
+       
+       $contexte['_types_import'] = $types_import;
+       
+       return $contexte;
+}
+
+function formulaires_importer_formulaire_verifier(){
+       $erreurs = array();
+       
+       return $erreurs;
+}
+
+function formulaires_importer_formulaire_traiter(){
+       $retours = array();
+       
+       if (!$_FILES['fichier']['error']){
+               $type_import = _request('type_import');
+               $fichier = $_FILES['fichier']['tmp_name'];
+       
+               $importer = charger_fonction('importer', "echanger/formulaire/$type_import", true);
+               $erreur_ou_id = $importer($fichier);
+               
+               if (!is_numeric($erreur_ou_id)){
+                       $retours['message_erreur'] = $erreur;
+                       $retours['editable'] = true;
+               }
+               else{
+                       $id_formulaire = intval($erreur_ou_id);
+                       // Tout a fonctionné. En fonction de la config, on attribue l'auteur courant
+                       $auteurs = lire_config('formidable/analyse/auteur');
+                       if ($auteurs == 'on') {
+                               if ($id_auteur = session_get('id_auteur')) {
+                                       // association (par défaut) du formulaire et de l'auteur courant
+                                       objet_associer(array('formulaire'=>$id_formulaire), array('auteur'=>$id_auteur));
+                               }
+                       }
+                       $retours['redirect'] = generer_url_ecrire('formulaire', "id_formulaire=$id_formulaire");
+               }
+       }
+       
+       return $retours;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/icones_barre/formulaire.png b/www/plugins/formidable_1_0/icones_barre/formulaire.png
new file mode 100644 (file)
index 0000000..0cf4900
Binary files /dev/null and b/www/plugins/formidable_1_0/icones_barre/formulaire.png differ
diff --git a/www/plugins/formidable_1_0/images/formidable-128.png b/www/plugins/formidable_1_0/images/formidable-128.png
new file mode 100644 (file)
index 0000000..8d6b21c
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formidable-128.png differ
diff --git a/www/plugins/formidable_1_0/images/formidable-24.png b/www/plugins/formidable_1_0/images/formidable-24.png
new file mode 100644 (file)
index 0000000..c8c577f
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formidable-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formidable-64.png b/www/plugins/formidable_1_0/images/formidable-64.png
new file mode 100644 (file)
index 0000000..80d5ab8
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formidable-64.png differ
diff --git a/www/plugins/formidable_1_0/images/formidable.svg b/www/plugins/formidable_1_0/images/formidable.svg
new file mode 100644 (file)
index 0000000..5baf77e
--- /dev/null
@@ -0,0 +1,1104 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg:svg
+   xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg9991"
+   sodipodi:version="0.32"
+   inkscape:version="0.47pre4 r22446"
+   sodipodi:docname="formidable.svg"
+   inkscape:export-filename="/home/vincent/public_html/collectivite/plugins/formidable/images/formidable-128.png"
+   inkscape:export-xdpi="180"
+   inkscape:export-ydpi="180"
+   version="1.1">
+  <svg:defs
+     id="defs9993">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 32 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="64 : 32 : 1"
+       inkscape:persp3d-origin="32 : 21.333333 : 1"
+       id="perspective227" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       id="linearGradient9806">
+      <svg:stop
+         style="stop-color:#000000;stop-opacity:1;"
+         offset="0"
+         id="stop9808" />
+      <svg:stop
+         style="stop-color:#000000;stop-opacity:0;"
+         offset="1"
+         id="stop9810" />
+    </svg:linearGradient>
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient9806"
+       id="radialGradient9812"
+       cx="24.35099"
+       cy="41.591846"
+       fx="24.35099"
+       fy="41.591846"
+       r="19.136078"
+       gradientTransform="matrix(1,0,0,0.242494,0,31.50606)"
+       gradientUnits="userSpaceOnUse" />
+    <svg:linearGradient
+       id="XMLID_3_"
+       gradientUnits="userSpaceOnUse"
+       x1="26.2524"
+       y1="34.8477"
+       x2="26.2524"
+       y2="32.5825">
+      <svg:stop
+         offset="0"
+         style="stop-color:#EF2929"
+         id="stop227" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#A40000"
+         id="stop229" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="path2756_1_"
+       gradientUnits="userSpaceOnUse"
+       x1="-4.2974"
+       y1="72.0352"
+       x2="-4.2974"
+       y2="69.3176"
+       gradientTransform="matrix(1.1501,0,0,-1.1501,31.1956,114.7217)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#555753"
+         id="stop215" />
+      <svg:stop
+         offset="0.1275"
+         style="stop-color:#484C4A"
+         id="stop217" />
+      <svg:stop
+         offset="0.3459"
+         style="stop-color:#393E3F"
+         id="stop219" />
+      <svg:stop
+         offset="0.6043"
+         style="stop-color:#313638"
+         id="stop221" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#2E3436"
+         id="stop223" />
+    </svg:linearGradient>
+    <svg:radialGradient
+       id="path2327_1_"
+       cx="169.5005"
+       cy="-40.2339"
+       r="9.5353"
+       gradientTransform="matrix(0.788,0,0,-0.788,-109.0825,-6.0314)"
+       gradientUnits="userSpaceOnUse">
+      <svg:stop
+         offset="0"
+         style="stop-color:#E9B96E"
+         id="stop199" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#C17D11"
+         id="stop201" />
+    </svg:radialGradient>
+    <svg:linearGradient
+       id="XMLID_2_"
+       gradientUnits="userSpaceOnUse"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646"
+       gradientTransform="matrix(0.4034,-0.1906,0.427,0.9042,34.7974,24.8318)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#C17D11"
+         id="stop186" />
+      <svg:stop
+         offset="0.2735"
+         style="stop-color:#BD7A10"
+         id="stop188" />
+      <svg:stop
+         offset="0.5694"
+         style="stop-color:#B0700C"
+         id="stop190" />
+      <svg:stop
+         offset="0.8747"
+         style="stop-color:#9A6105"
+         id="stop192" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#8F5902"
+         id="stop194" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="XMLID_1_"
+       gradientUnits="userSpaceOnUse"
+       x1="-25.4316"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493"
+       gradientTransform="matrix(-0.4034,-0.1906,-0.427,0.9042,17.9775,24.8318)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#C17D11"
+         id="stop173" />
+      <svg:stop
+         offset="0.2735"
+         style="stop-color:#BD7A10"
+         id="stop175" />
+      <svg:stop
+         offset="0.5694"
+         style="stop-color:#B0700C"
+         id="stop177" />
+      <svg:stop
+         offset="0.8747"
+         style="stop-color:#9A6105"
+         id="stop179" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#8F5902"
+         id="stop181" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="path4173_1_"
+       gradientUnits="userSpaceOnUse"
+       x1="65.4673"
+       y1="21.7046"
+       x2="65.4673"
+       y2="15.4519"
+       gradientTransform="matrix(1,0,0,-1,-34.4082,61.0186)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#FFFFFF"
+         id="stop163" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#C9C9C9"
+         id="stop165" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="path29441_5_"
+       gradientUnits="userSpaceOnUse"
+       x1="-764.8428"
+       y1="70.6904"
+       x2="-768.0942"
+       y2="65.1441"
+       gradientTransform="matrix(-0.9772,0,0,-0.9959,-719.1876,75.5817)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#F5F5F5"
+         id="stop80" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#E9E9E9"
+         id="stop82" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="path29441_4_"
+       gradientUnits="userSpaceOnUse"
+       x1="-776.0811"
+       y1="62.5264"
+       x2="-779.3325"
+       y2="56.9801"
+       gradientTransform="matrix(-0.9772,0,0,-0.9959,-719.1876,75.5817)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#F5F5F5"
+         id="stop71" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#E9E9E9"
+         id="stop73" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="rect29408_3_"
+       gradientUnits="userSpaceOnUse"
+       x1="35.4419"
+       y1="63.6533"
+       x2="40.9202"
+       y2="57.2008"
+       gradientTransform="matrix(1.0076,0,0,-0.9876,-21.8209,64.5593)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#F5F5F5"
+         id="stop62" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#E9E9E9"
+         id="stop64" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="path29441_3_"
+       gradientUnits="userSpaceOnUse"
+       x1="-777.9102"
+       y1="48.9697"
+       x2="-781.1614"
+       y2="43.4239"
+       gradientTransform="matrix(-0.9772,0,0,-0.9959,-719.1876,75.5817)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#F5F5F5"
+         id="stop53" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#E9E9E9"
+         id="stop55" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="rect29408_2_"
+       gradientUnits="userSpaceOnUse"
+       x1="29.3257"
+       y1="53.0791"
+       x2="34.8039"
+       y2="46.6266"
+       gradientTransform="matrix(1.0076,0,0,-0.9876,-21.8209,64.5593)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#F5F5F5"
+         id="stop44" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#E9E9E9"
+         id="stop46" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="path4370_1_"
+       gradientUnits="userSpaceOnUse"
+       x1="-695.4531"
+       y1="-64.7212"
+       x2="-696.7315"
+       y2="-64.0704"
+       gradientTransform="matrix(-0.9777,0.2101,-0.2101,-0.9777,-658.7002,129.0211)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#000000"
+         id="stop36" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#000000"
+         id="stop38" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="path4368_1_"
+       gradientUnits="userSpaceOnUse"
+       x1="95.3657"
+       y1="95.0371"
+       x2="97.3309"
+       y2="94.6373"
+       gradientTransform="matrix(0.9834,0.1816,0.1816,-0.9834,-95.5652,121.2474)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#000000"
+         id="stop30" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#000000"
+         id="stop32" />
+    </svg:linearGradient>
+    <svg:radialGradient
+       id="path2329_1_"
+       cx="46.8472"
+       cy="-100.144"
+       r="13.5656"
+       gradientTransform="matrix(1,0,0,-0.6819,-21.9902,-29.6113)"
+       gradientUnits="userSpaceOnUse">
+      <svg:stop
+         offset="0"
+         style="stop-color:#729FCF"
+         id="stop23" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#3465A4"
+         id="stop25" />
+    </svg:radialGradient>
+    <svg:radialGradient
+       id="XMLID_5_"
+       cx="23.436"
+       cy="33.9185"
+       r="19.7892"
+       gradientTransform="matrix(0.5861,1.37e-2,1.37e-2,0.6642,-2.6747,12.0504)"
+       gradientUnits="userSpaceOnUse">
+      <svg:stop
+         offset="0"
+         style="stop-color:#E9B96E"
+         id="stop14" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#C17D11"
+         id="stop16" />
+    </svg:radialGradient>
+    <svg:foreignObject
+       id="foreignObject7"
+       height="1"
+       width="1"
+       y="0"
+       x="0"
+       requiredExtensions="http://ns.adobe.com/AdobeIllustrator/10.0/">
+      <i:pgfRef
+         xlink:href="#adobe_illustrator_pgf" />
+    </svg:foreignObject>
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_5_"
+       id="radialGradient266885"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5861,1.37e-2,1.37e-2,0.6642,-2.6747,12.0504)"
+       cx="23.436"
+       cy="33.9185"
+       r="19.7892" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#path2329_1_"
+       id="radialGradient266887"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,-0.6819,-21.9902,-29.6113)"
+       cx="46.8472"
+       cy="-100.144"
+       r="13.5656" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path4368_1_"
+       id="linearGradient266889"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.9834,0.1816,0.1816,-0.9834,-95.5652,121.2474)"
+       x1="95.3657"
+       y1="95.0371"
+       x2="97.3309"
+       y2="94.6373" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path4370_1_"
+       id="linearGradient266891"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.9777,0.2101,-0.2101,-0.9777,-658.7002,129.0211)"
+       x1="-695.4531"
+       y1="-64.7212"
+       x2="-696.7315"
+       y2="-64.0704" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path4173_1_"
+       id="linearGradient266903"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1,0,0,-1,-34.4082,61.0186)"
+       x1="65.4673"
+       y1="21.7046"
+       x2="65.4673"
+       y2="15.4519" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_1_"
+       id="linearGradient266905"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.4034,-0.1906,-0.427,0.9042,17.9775,24.8318)"
+       x1="-25.4316"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_2_"
+       id="linearGradient266907"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.4034,-0.1906,0.427,0.9042,34.7974,24.8318)"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#path2327_1_"
+       id="radialGradient266909"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.788,0,0,-0.788,-109.0825,-6.0314)"
+       cx="169.5005"
+       cy="-40.2339"
+       r="9.5353" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path2756_1_"
+       id="linearGradient266911"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.1501,0,0,-1.1501,31.1956,114.7217)"
+       x1="-4.2974"
+       y1="72.0352"
+       x2="-4.2974"
+       y2="69.3176" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_3_"
+       id="linearGradient266913"
+       gradientUnits="userSpaceOnUse"
+       x1="26.2524"
+       y1="34.8477"
+       x2="26.2524"
+       y2="32.5825" />
+    <svg:radialGradient
+       id="radialGradient2174"
+       cx="46.847198"
+       cy="-100.144"
+       r="13.5656"
+       gradientTransform="matrix(1,0,0,-0.6819,-21.9902,-29.6113)"
+       gradientUnits="userSpaceOnUse">
+      <svg:stop
+         offset="0"
+         style="stop-color:#729FCF"
+         id="stop2176" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#3465A4"
+         id="stop2178" />
+    </svg:radialGradient>
+    <svg:linearGradient
+       id="linearGradient2182"
+       gradientUnits="userSpaceOnUse"
+       x1="95.3657"
+       y1="95.037102"
+       x2="97.330902"
+       y2="94.637299"
+       gradientTransform="matrix(0.9834,0.1816,0.1816,-0.9834,-95.5652,121.2474)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#000000"
+         id="stop2184" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#000000"
+         id="stop2186" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="linearGradient2189"
+       gradientUnits="userSpaceOnUse"
+       x1="-695.45312"
+       y1="-64.721199"
+       x2="-696.73151"
+       y2="-64.070396"
+       gradientTransform="matrix(-0.9777,0.2101,-0.2101,-0.9777,-658.7002,129.0211)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#000000"
+         id="stop2191" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#000000"
+         id="stop2193" />
+    </svg:linearGradient>
+    <namedview
+       zoom="9.8994949"
+       pageopacity="0.0"
+       pageshadow="2"
+       showpageshadow="false"
+       borderopacity="0.17254902"
+       pagecolor="#ffffff"
+       bordercolor="#666666"
+       cy="24.622653"
+       showgrid="false"
+       current-layer="layer1"
+       cx="25.799661"
+       window-y="167"
+       document-units="px"
+       window-width="770"
+       grid-bbox="true"
+       window-height="695"
+       window-x="472" />
+    <svg:linearGradient
+       id="linearGradient2280"
+       gradientUnits="userSpaceOnUse"
+       x1="65.4673"
+       y1="21.704599"
+       x2="65.4673"
+       y2="15.4519"
+       gradientTransform="matrix(1,0,0,-1,-34.4082,61.0186)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#FFFFFF"
+         id="stop2282" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#C9C9C9"
+         id="stop2284" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path4173_1_"
+       id="linearGradient266966"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7587571,0,0,-1.7587571,-73.922013,79.170666)"
+       x1="65.4673"
+       y1="21.7046"
+       x2="65.4673"
+       y2="15.4519" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path4370_1_"
+       id="linearGradient267038"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.7195361,0.36951432,-0.36951432,-1.7195361,-1171.8999,198.77048)"
+       x1="-695.4531"
+       y1="-64.7212"
+       x2="-696.7315"
+       y2="-64.0704" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path4368_1_"
+       id="linearGradient267041"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.7295622,0.31939001,0.31939001,-1.7295622,-181.4823,185.09853)"
+       x1="95.3657"
+       y1="95.0371"
+       x2="97.3309"
+       y2="94.6373" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#path2329_1_"
+       id="radialGradient267045"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.758757,0,0,-1.1992961,-52.081768,-80.225303)"
+       cx="46.8472"
+       cy="-100.144"
+       r="13.5656" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_5_"
+       id="radialGradient267053"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5861,1.37e-2,1.37e-2,0.6642,-2.6747,12.0504)"
+       cx="23.436"
+       cy="33.9185"
+       r="19.7892" />
+    <svg:radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.5861,1.37e-2,1.37e-2,0.6642,-2.6747,12.0504)"
+       r="19.7892"
+       cy="33.918499"
+       cx="23.436001"
+       id="radialGradient2166">
+      <svg:stop
+         id="stop2168"
+         style="stop-color:#E9B96E"
+         offset="0" />
+      <svg:stop
+         id="stop2170"
+         style="stop-color:#C17D11"
+         offset="1" />
+    </svg:radialGradient>
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_1_"
+       id="linearGradient267061"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.4034,-0.1906,-0.427,0.9042,17.9775,24.8318)"
+       x1="-25.4316"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_2_"
+       id="linearGradient267063"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.4034,-0.1906,0.427,0.9042,34.7974,24.8318)"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#path2327_1_"
+       id="radialGradient267065"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.788,0,0,-0.788,-109.0825,-6.0314)"
+       cx="169.5005"
+       cy="-40.2339"
+       r="9.5353" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path2756_1_"
+       id="linearGradient267067"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.1501,0,0,-1.1501,31.1956,114.7217)"
+       x1="-4.2974"
+       y1="72.0352"
+       x2="-4.2974"
+       y2="69.3176" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_3_"
+       id="linearGradient267069"
+       gradientUnits="userSpaceOnUse"
+       x1="26.2524"
+       y1="34.8477"
+       x2="26.2524"
+       y2="32.5825" />
+    <svg:radialGradient
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.788,0,0,-0.788,-109.0825,-6.0314)"
+       r="9.5353003"
+       cy="-40.233898"
+       cx="169.5005"
+       id="radialGradient2315">
+      <svg:stop
+         id="stop2317"
+         style="stop-color:#E9B96E"
+         offset="0" />
+      <svg:stop
+         id="stop2319"
+         style="stop-color:#C17D11"
+         offset="1" />
+    </svg:radialGradient>
+    <svg:linearGradient
+       gradientTransform="matrix(1.1501,0,0,-1.1501,31.1956,114.7217)"
+       y2="69.317596"
+       x2="-4.2974"
+       y1="72.035202"
+       x1="-4.2974"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient2329">
+      <svg:stop
+         id="stop2331"
+         style="stop-color:#555753"
+         offset="0" />
+      <svg:stop
+         id="stop2333"
+         style="stop-color:#484C4A"
+         offset="0.1275" />
+      <svg:stop
+         id="stop2335"
+         style="stop-color:#393E3F"
+         offset="0.3459" />
+      <svg:stop
+         id="stop2337"
+         style="stop-color:#313638"
+         offset="0.6043" />
+      <svg:stop
+         id="stop2339"
+         style="stop-color:#2E3436"
+         offset="1" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       y2="32.5825"
+       x2="26.252399"
+       y1="34.847698"
+       x1="26.252399"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient2342">
+      <svg:stop
+         id="stop2344"
+         style="stop-color:#EF2929"
+         offset="0" />
+      <svg:stop
+         id="stop2346"
+         style="stop-color:#A40000"
+         offset="1" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_3_"
+       id="linearGradient267084"
+       gradientUnits="userSpaceOnUse"
+       x1="26.2524"
+       y1="34.8477"
+       x2="26.2524"
+       y2="32.5825"
+       gradientTransform="matrix(2.7108449,0,0,2.7108449,-38.9913,-41.797214)" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path2756_1_"
+       id="linearGradient267087"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3.1177432,0,0,-3.1177432,45.575138,269.19554)"
+       x1="-4.2974"
+       y1="72.0352"
+       x2="-4.2974"
+       y2="69.3176" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#path2327_1_"
+       id="radialGradient267097"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.136146,0,0,-2.136146,-334.697,-58.147403)"
+       cx="169.5005"
+       cy="-40.2339"
+       r="9.5353" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_1_"
+       id="linearGradient267114"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-0.4034,-0.1906,-0.427,0.9042,17.9775,24.8318)"
+       x1="-25.4316"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_2_"
+       id="linearGradient267116"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.4034,-0.1906,0.427,0.9042,34.7974,24.8318)"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646" />
+    <svg:linearGradient
+       id="linearGradient2289"
+       gradientUnits="userSpaceOnUse"
+       x1="-25.431601"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493"
+       gradientTransform="matrix(-0.4034,-0.1906,-0.427,0.9042,17.9775,24.8318)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#C17D11"
+         id="stop2291" />
+      <svg:stop
+         offset="0.2735"
+         style="stop-color:#BD7A10"
+         id="stop2293" />
+      <svg:stop
+         offset="0.5694"
+         style="stop-color:#B0700C"
+         id="stop2295" />
+      <svg:stop
+         offset="0.8747"
+         style="stop-color:#9A6105"
+         id="stop2297" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#8F5902"
+         id="stop2299" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       id="linearGradient2302"
+       gradientUnits="userSpaceOnUse"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646"
+       gradientTransform="matrix(0.4034,-0.1906,0.427,0.9042,34.7974,24.8318)">
+      <svg:stop
+         offset="0"
+         style="stop-color:#C17D11"
+         id="stop2304" />
+      <svg:stop
+         offset="0.2735"
+         style="stop-color:#BD7A10"
+         id="stop2306" />
+      <svg:stop
+         offset="0.5694"
+         style="stop-color:#B0700C"
+         id="stop2308" />
+      <svg:stop
+         offset="0.8747"
+         style="stop-color:#9A6105"
+         id="stop2310" />
+      <svg:stop
+         offset="1"
+         style="stop-color:#8F5902"
+         id="stop2312" />
+    </svg:linearGradient>
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_2_"
+       id="linearGradient267131"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0935548,-0.51668813,1.15753,2.4511451,55.339053,25.517944)"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_1_"
+       id="linearGradient267134"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.0935548,-0.51668813,-1.15753,2.4511451,9.74292,25.517944)"
+       x1="-25.4316"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493" />
+    <inkscape:perspective
+       id="perspective3062"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3076"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3090"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3104"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3118"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_1_"
+       id="linearGradient3017"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.0935548,-0.51668813,-1.15753,2.4511451,9.74292,25.517944)"
+       x1="-25.4316"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_2_"
+       id="linearGradient3019"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0935548,-0.51668813,1.15753,2.4511451,55.339053,25.517944)"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#path2327_1_"
+       id="radialGradient3021"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.136146,0,0,-2.136146,-334.697,-58.147403)"
+       cx="169.5005"
+       cy="-40.2339"
+       r="9.5353" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path2756_1_"
+       id="linearGradient3023"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3.1177432,0,0,-3.1177432,45.575138,269.19554)"
+       x1="-4.2974"
+       y1="72.0352"
+       x2="-4.2974"
+       y2="69.3176" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_3_"
+       id="linearGradient3025"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.7108449,0,0,2.7108449,-38.9913,-41.797214)"
+       x1="26.2524"
+       y1="34.8477"
+       x2="26.2524"
+       y2="32.5825" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_3_"
+       id="linearGradient3030"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.7108449,0,0,2.7108449,-39.169171,-41.746948)"
+       x1="26.2524"
+       y1="34.8477"
+       x2="26.2524"
+       y2="32.5825" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#path2756_1_"
+       id="linearGradient3033"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(3.1177432,0,0,-3.1177432,45.397267,269.24581)"
+       x1="-4.2974"
+       y1="72.0352"
+       x2="-4.2974"
+       y2="69.3176" />
+    <svg:radialGradient
+       inkscape:collect="always"
+       xlink:href="#path2327_1_"
+       id="radialGradient3040"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(2.136146,0,0,-2.136146,-334.87487,-58.097137)"
+       cx="169.5005"
+       cy="-40.2339"
+       r="9.5353" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_2_"
+       id="linearGradient3043"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(1.0935548,-0.51668813,1.15753,2.4511451,55.161182,25.56821)"
+       x1="-25.979"
+       y1="-10.6646"
+       x2="-18.7339"
+       y2="-10.6646" />
+    <svg:linearGradient
+       inkscape:collect="always"
+       xlink:href="#XMLID_1_"
+       id="linearGradient3046"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(-1.0935548,-0.51668813,-1.15753,2.4511451,9.5650493,25.56821)"
+       x1="-25.4316"
+       y1="-10.5493"
+       x2="-18.1875"
+       y2="-10.5493" />
+  </svg:defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1"
+     inkscape:cx="24.999168"
+     inkscape:cy="36.55781"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="867"
+     inkscape:window-height="669"
+     inkscape:window-x="246"
+     inkscape:window-y="112"
+     inkscape:window-maximized="0" />
+  <svg:metadata
+     id="metadata9996">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </svg:metadata>
+  <svg:g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <svg:image
+       y="0.52496314"
+       x="79.286026"
+       id="image3064"
+       height="13.594464"
+       width="13.594464"
+       xlink:href="file:///usr/share/icons/gnome/24x24/stock/form/stock_form-combobox.png" />
+    <svg:path
+       d="m 41.665519,9.108502 c -1.867773,3.960546 -1.612951,8.007839 0.5747,9.04338 2.187651,1.032832 5.478619,-1.341865 7.349101,-5.302413 1.867773,-3.9605434 1.612955,-8.0051252 -0.574701,-9.0406662 -2.190363,-1.032836 -5.481326,1.3391575 -7.3491,5.2996992 z"
+       id="path183"
+       style="fill:url(#linearGradient3046);stroke:#8f5902;stroke-width:2.36402392;stroke-miterlimit:4;stroke-dasharray:none" />
+    <svg:path
+       d="m 22.33177,9.1057907 c 1.867773,3.9578363 1.612957,8.0078393 -0.574698,9.0406703 -2.187649,1.03283 -5.478616,-1.341867 -7.349099,-5.302413 -1.867773,-3.9605449 -1.612953,-8.005125 0.5747,-9.0379564 2.187648,-1.032836 5.475904,1.3391576 7.349097,5.2996991 z"
+       id="path196"
+       style="fill:url(#linearGradient3043);stroke:#8f5902;stroke-width:2.36402392;stroke-miterlimit:4;stroke-dasharray:none" />
+    <svg:path
+       style="fill:url(#radialGradient3040);stroke:#8f5902;stroke-width:2.36402392;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 55.477275,30.694962 c 0.0055,12.968683 -10.499103,29.735262 -23.465076,29.74068 -12.963262,0.0055 -23.4840487,-16.750309 -23.4894717,-29.716283 0,-0.0081 0,-0.01641 0,-0.02447 C 8.5146273,17.726208 19.021832,7.2081281 31.990516,7.1999959 44.951062,7.1944459 55.471855,17.701807 55.477275,30.667783 c 0,0.01095 0,0.01896 0,0.02705 z"
+       cx="31.112698"
+       type="arc"
+       rx="8.6620579"
+       cy="19.008621"
+       ry="8.6620579"
+       id="path2327" />
+    <svg:path
+       style="opacity:0.12660002;fill:none;stroke:#ffffff;stroke-width:2.36402392;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
+       d="m 52.590227,30.694962 c 0.0055,11.374707 -9.211453,26.850921 -20.580738,26.856344 -11.369282,0.0056 -20.599712,-15.459951 -20.605135,-26.834653 0,-0.0081 0,-0.01356 0,-0.02158 -0.0055,-11.374705 9.211452,-20.602421 20.583451,-20.607842 11.366569,-0.0055 20.596998,9.208739 20.602422,20.586154 0,0.0081 0,0.01356 0,0.02158 z"
+       enable-background="new    "
+       cx="31.112698"
+       type="arc"
+       rx="8.6620579"
+       cy="19.008621"
+       ry="8.6620579"
+       id="path3834" />
+    <svg:g
+       id="g205"
+       transform="matrix(2.7108452,0,0,2.7108452,-39.169172,-41.746951)">
+      <svg:ellipse
+         style="fill:#8f5902"
+         sodipodi:ry="0.54100001"
+         sodipodi:rx="1.041"
+         sodipodi:cy="29.219"
+         sodipodi:cx="24.940001"
+         id="ellipse207"
+         ry="0.54100001"
+         rx="1.041"
+         cy="29.219"
+         cx="24.940001"
+         transform="matrix(0.8505,0.526,-0.526,0.8505,19.0996,-8.7499)"
+         d="m 25.981001,29.219 c 0,0.298786 -0.466072,0.541 -1.041,0.541 -0.574929,0 -1.041,-0.242214 -1.041,-0.541 0,-0.298786 0.466071,-0.541 1.041,-0.541 0.574928,0 1.041,0.242214 1.041,0.541 z" />
+      <svg:ellipse
+         style="fill:#8f5902"
+         sodipodi:ry="0.54100001"
+         sodipodi:rx="1.0420001"
+         sodipodi:cy="29.219"
+         sodipodi:cx="27.565001"
+         id="ellipse209"
+         ry="0.54100001"
+         rx="1.0420001"
+         cy="29.219"
+         cx="27.565001"
+         transform="matrix(-0.8506,0.5258,-0.5258,-0.8506,66.3766,39.5785)"
+         d="m 28.607001,29.219 c 0,0.298786 -0.46652,0.541 -1.042,0.541 -0.575481,0 -1.042001,-0.242214 -1.042001,-0.541 0,-0.298786 0.46652,-0.541 1.042001,-0.541 0.57548,0 1.042,0.242214 1.042,0.541 z" />
+    </svg:g>
+    <svg:path
+       style="fill:url(#linearGradient3033);stroke:#2e3436;stroke-width:0.67771125;stroke-linecap:round;stroke-linejoin:round"
+       d="m 22.70858,43.845272 c 0.09486,5.055726 4.209941,9.463561 9.292779,9.463561 5.07741,0 9.192476,-4.407835 9.287353,-9.463561 l -18.580132,0 0,0 z"
+       nodetypes="cscc"
+       id="path2756" />
+    <svg:path
+       style="fill:url(#linearGradient3030);stroke:#a40000;stroke-width:0.67771125;stroke-linecap:round;stroke-linejoin:round"
+       id="path231"
+       d="m 33.009791,46.447685 -1.434034,1.989758 -0.872894,-1.962651 c -2.4994,0.393071 -4.489161,1.935545 -5.109946,3.922592 1.678014,1.772894 4.003921,2.908737 6.581934,2.908737 2.399098,0 4.578618,-0.99217 6.22681,-2.564457 -0.504216,-2.201206 -2.66476,-3.930725 -5.39187,-4.293979 z" />
+    <svg:image
+       y="12.687449"
+       x="11.29285"
+       id="image3078"
+       height="25.508533"
+       width="25.508533"
+       xlink:href="file:///usr/share/icons/gnome/24x24/stock/form/stock_form-checkbox.png" />
+    <svg:image
+       y="14.403575"
+       x="30.422155"
+       id="image3092"
+       height="22.700869"
+       width="22.700869"
+       xlink:href="file:///usr/share/icons/gnome/24x24/stock/form/stock_form-radio.png" />
+    <svg:image
+       y="-3.2308276"
+       x="-44.282436"
+       id="image3106"
+       height="16.103373"
+       width="16.103373"
+       xlink:href="file:///usr/share/icons/gnome/24x24/stock/form/stock_form-text-box.png" />
+    <svg:image
+       y="43.025379"
+       x="73.367607"
+       id="image3120"
+       height="14.591788"
+       width="14.591788"
+       xlink:href="file:///usr/share/icons/gnome/24x24/stock/form/stock_form-design-mode.png" />
+  </svg:g>
+</svg:svg>
diff --git a/www/plugins/formidable_1_0/images/formulaire-24.png b/www/plugins/formidable_1_0/images/formulaire-24.png
new file mode 100644 (file)
index 0000000..ff847d0
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-action-ajouter.png b/www/plugins/formidable_1_0/images/formulaire-action-ajouter.png
new file mode 100644 (file)
index 0000000..8aef295
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-action-ajouter.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-analyse-24.png b/www/plugins/formidable_1_0/images/formulaire-analyse-24.png
new file mode 100644 (file)
index 0000000..9965646
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-analyse-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-config-auteurs-24.png b/www/plugins/formidable_1_0/images/formulaire-config-auteurs-24.png
new file mode 100644 (file)
index 0000000..30f5ec5
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-config-auteurs-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-config-champs-24.png b/www/plugins/formidable_1_0/images/formulaire-config-champs-24.png
new file mode 100644 (file)
index 0000000..0d77271
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-config-champs-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-config-traitements-24.png b/www/plugins/formidable_1_0/images/formulaire-config-traitements-24.png
new file mode 100644 (file)
index 0000000..f362e72
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-config-traitements-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-dupliquer-24.png b/www/plugins/formidable_1_0/images/formulaire-dupliquer-24.png
new file mode 100644 (file)
index 0000000..a4ec44f
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-dupliquer-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-editer-24.png b/www/plugins/formidable_1_0/images/formulaire-editer-24.png
new file mode 100644 (file)
index 0000000..0bb3e26
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-editer-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-exporter-24.png b/www/plugins/formidable_1_0/images/formulaire-exporter-24.png
new file mode 100644 (file)
index 0000000..3350857
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-exporter-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-nouveau-48.png b/www/plugins/formidable_1_0/images/formulaire-nouveau-48.png
new file mode 100644 (file)
index 0000000..a0c803e
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-nouveau-48.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-reponse-24.png b/www/plugins/formidable_1_0/images/formulaire-reponse-24.png
new file mode 100644 (file)
index 0000000..1bbdb51
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-reponse-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-reponse-supprimer-24.png b/www/plugins/formidable_1_0/images/formulaire-reponse-supprimer-24.png
new file mode 100644 (file)
index 0000000..897c63e
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-reponse-supprimer-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-reponses-24.png b/www/plugins/formidable_1_0/images/formulaire-reponses-24.png
new file mode 100644 (file)
index 0000000..ec0a2b0
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-reponses-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-reponses-exporter-24.png b/www/plugins/formidable_1_0/images/formulaire-reponses-exporter-24.png
new file mode 100644 (file)
index 0000000..94d0cec
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-reponses-exporter-24.png differ
diff --git a/www/plugins/formidable_1_0/images/formulaire-supprimer-24.png b/www/plugins/formidable_1_0/images/formulaire-supprimer-24.png
new file mode 100644 (file)
index 0000000..1819e5e
Binary files /dev/null and b/www/plugins/formidable_1_0/images/formulaire-supprimer-24.png differ
diff --git a/www/plugins/formidable_1_0/inc/formidable.php b/www/plugins/formidable_1_0/inc/formidable.php
new file mode 100644 (file)
index 0000000..d50971f
--- /dev/null
@@ -0,0 +1,378 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/*
+ * Liste tous les traitements configurables (ayant une description)
+ *
+ * @return array Un tableau listant des saisies et leurs options
+ */
+function traitements_lister_disponibles(){
+    static $traitements = null;
+
+    if (is_null($traitements)){
+        $traitements = array();
+        $liste = find_all_in_path('traiter/', '.+[.]yaml$');
+
+        if (count($liste)){
+            foreach ($liste as $fichier=>$chemin){
+                $type_traitement = preg_replace(',[.]yaml$,i', '', $fichier);
+                $dossier = str_replace($fichier, '', $chemin);
+                // On ne garde que les traitements qui ont bien la fonction
+                if (charger_fonction($type_traitement, 'traiter', true)
+                    and (
+                        is_array($traitement = traitements_charger_infos($type_traitement))
+                    )
+                ){
+                    $traitements[$type_traitement] = $traitement;
+                }
+            }
+        }
+    }
+
+    return $traitements;
+}
+
+/**
+ * Charger les informations contenues dans le yaml d'un traitement
+ *
+ * @param string $type_saisie Le type de la saisie
+ * @return array Un tableau contenant le YAML décodé
+ */
+function traitements_charger_infos($type_traitement){
+    include_spip('inc/yaml');
+    $fichier = find_in_path("traiter/$type_traitement.yaml");
+    $traitement = yaml_decode_file($fichier);
+
+    if (is_array($traitement)) {
+        $traitement += array('titre' => '', 'description' => '', 'icone' => '');
+        $traitement['titre'] = $traitement['titre'] ? _T_ou_typo($traitement['titre']) : $type_traitement;
+        $traitement['description'] = $traitement['description'] ? _T_ou_typo($traitement['description']) : '';
+        $traitement['icone'] = $traitement['icone'] ? find_in_path($traitement['icone']) : '';
+    }
+    return $traitement;
+}
+
+/*
+ * Liste tous les types d'échanges (export et import) existant pour les formulaires
+ *
+ * @return array Retourne un tableau listant les types d'échanges
+ */
+function echanges_formulaire_lister_disponibles(){
+    // On va chercher toutes les fonctions existantes
+    $liste = find_all_in_path('echanger/formulaire/', '.+[.]php$');
+    $types_echange = array('exporter'=>array(), 'importer'=>array());
+    if (count($liste)){
+        foreach ($liste as $fichier=>$chemin){
+            $type_echange = preg_replace(',[.]php$,i', '', $fichier);
+            $dossier = str_replace($fichier, '', $chemin);
+            // On ne garde que les échanges qui ont bien la fonction
+            if ($f = charger_fonction('exporter', "echanger/formulaire/$type_echange", true)){
+                $types_echange['exporter'][$type_echange] = $f;
+            }
+            if ($f = charger_fonction('importer', "echanger/formulaire/$type_echange", true)){
+                $types_echange['importer'][$type_echange] = $f;
+            }
+        }
+    }
+    return $types_echange;
+}
+
+/*
+ * Génère le nom du cookie qui sera utilisé par le plugin lors d'une réponse
+ * par un visiteur non-identifié.
+ *
+ * @param int $id_formulaire L'identifiant du formulaire
+ * @return string Retourne le nom du cookie
+ */
+function formidable_generer_nom_cookie($id_formulaire){
+    return $GLOBALS['cookie_prefix'].'cookie_formidable_'.$id_formulaire;
+}
+
+/*
+ * Vérifie si le visiteur a déjà répondu à un formulaire
+ *
+ * @param int $id_formulaire L'identifiant du formulaire
+ * @param string $choix_identification Comment verifier une reponse. Priorite sur 'cookie' ou sur 'id_auteur'
+ * @param string $anonymisation : vaut '' si le formulaire n'est pas anonymisé, sinon c'est la variable d'anonymisation
+ * @return unknown_type Retourne un tableau contenant les id des réponses si elles existent, sinon false
+ */
+function formidable_verifier_reponse_formulaire($id_formulaire, $choix_identification='cookie', $anonymisation=''){
+    global $auteur_session;
+    $id_auteur = $auteur_session ? intval($auteur_session['id_auteur']) : 0;
+    $nom_cookie = formidable_generer_nom_cookie($id_formulaire);
+    $cookie = isset($_COOKIE[$nom_cookie]) ? $_COOKIE[$nom_cookie] : false;
+
+    $anonymiser = ($anonymisation == '') ? false : true;
+    if ($anonymiser) $anonymiser_variable = $anonymisation;
+
+    // traitement de l'anonymisation
+    if ($anonymiser) {
+        // mod de l'id_auteur
+        $variables_anonymisation =
+                $GLOBALS['formulaires']['variables_anonymisation'][$anonymiser_variable];
+        $id = eval("return $variables_anonymisation;");
+        $id_auteur = formidable_scramble($id);
+    }
+    // ni cookie ni id, on ne peut rien faire
+    if (!$cookie and !$id_auteur) {
+        return false;
+    }
+
+    // priorite sur le cookie
+    if ($choix_identification == 'cookie' or !$choix_identification) {
+        if ($cookie)
+            $where = '(cookie='.sql_quote($cookie).($id_auteur ? ' OR id_auteur='.$id_auteur.')' : ')');
+        else
+            $where = 'id_auteur='.$id_auteur;
+    }
+
+    // sinon sur l'id_auteur
+    else {
+        if ($id_auteur)
+            $where = 'id_auteur='.$id_auteur;
+        else
+            $where = '(cookie='.sql_quote($cookie).($id_auteur ? ' OR id_auteur='.$id_auteur.')' : ')');
+    }
+
+    $reponses = sql_allfetsel(
+        'id_formulaires_reponse',
+        'spip_formulaires_reponses',
+        array(
+            array('=', 'id_formulaire', intval($id_formulaire)),
+            array('=', 'statut', sql_quote('publie')),
+            $where
+        ),
+        '',
+        'date'
+    );
+
+    if (is_array($reponses))
+        return array_map('reset', $reponses);
+    else
+        return false;
+}
+
+/*
+ * Génère la vue d'analyse de toutes les réponses à une saisie
+ *
+ * @param array $saisie Un tableau décrivant une saisie
+ * @param array $env L'environnement, contenant normalement la réponse à la saisie
+ * @return string Retour le HTML des vues
+ */
+function formidable_analyser_saisie($saisie, $valeurs=array(), $reponses_total=0, $format_brut=false) {
+    // Si le paramètre n'est pas bon ou que c'est un conteneur, on génère du vide
+    if (!is_array($saisie) or (isset($saisie['saisies']) and $saisie['saisies']))
+        return '';
+
+    $contexte = array('reponses_total'=>$reponses_total);
+
+    // On sélectionne le type de saisie
+    $contexte['type_saisie'] = $saisie['saisie'];
+
+    // Peut-être des transformations à faire sur les options textuelles
+    $options = $saisie['options'];
+    foreach ($options as $option => $valeur){
+        $options[$option] = _T_ou_typo($valeur, 'multi');
+    }
+
+    // On ajoute les options propres à la saisie
+    $contexte = array_merge($contexte, $options);
+
+    // On récupère toutes les valeurs du champ
+    if (isset($valeurs[$contexte['nom']]) and $valeurs[$contexte['nom']] and is_array($valeurs[$contexte['nom']])){
+        $contexte['valeurs'] = $valeurs[$contexte['nom']];
+    }
+    else{
+        $contexte['valeurs'] = array();
+    }
+
+    // On génère la saisie
+    if ($format_brut) {
+        return analyser_saisie($contexte);
+    } else {
+        return recuperer_fond(
+            'saisies-analyses/_base',
+            $contexte
+        );
+    }
+}
+
+/*
+ * Renvoie une ligne de réponse sous la forme d'un tableau
+ *
+ * @param array $saisie Un tableau décrivant une saisie
+ * @return array Tableau contenant une ligne
+ */
+function analyser_saisie($saisie) {
+    if (!isset($saisie['type_saisie']) or $saisie['type_saisie'] == '')
+        return '';
+
+    $ligne = array();
+
+    switch($saisie['type_saisie']) {
+        case 'selecteur_rubrique' :
+        case 'selecteur_rubrique_article' :
+        case 'selecteur_article' :
+            $ligne['plein'] = count(array_filter($saisie['valeurs']));
+            $ligne['vide'] = count(array_diff_key($saisie['valeurs']
+                , array_filter($saisie['valeurs'])));
+        break;
+        case 'radio' :
+        case 'selection' :
+        case 'selection_multiple' :
+        case 'checkbox' :
+            $stats = array();
+            foreach($saisie['valeurs'] as $valeur) {
+                if (is_array($valeur)) {
+                    foreach($valeur as $choix) {
+                        if (isset($stats["choix-$choix"]))
+                            $stats["choix-$choix"]++;
+                        else $stats["choix-$choix"] = 1;
+                    }
+                } else {
+                    if (isset($stats["choix-$valeur"]))
+                            $stats["choix-$valeur"]++;
+                        else $stats["choix-$valeur"] = 1;
+                }
+            }
+            $datas = is_string($saisie['datas'])
+                ? saisies_chaine2tableau($saisie['datas'])
+                : $saisie['datas'];
+            foreach($datas as $key => $val) {
+                $nb = (isset($stats["choix-$key"]))
+                    ? $stats["choix-$key"]
+                    : 0;
+                $ligne[$val] = $nb;
+            }
+        break;
+        case 'destinataires' :
+            $stats = array();
+            foreach($saisie['valeurs'] as $valeur) {
+                foreach($valeur as $choix) {
+                    if (isset($stats["choix-$choix"]))
+                        $stats["choix-$choix"]++;
+                    else $stats["choix-$choix"] = 1;
+                }
+            }
+            foreach($stats as $key => $val) {
+                $key = str_replace('choix-', '', $key);
+                if ($key == '') $key = '<valeur vide>';
+                $auteur = sql_getfetsel('nom','spip_auteurs',"id_auteur=$key");
+                $ligne[$auteur] = $val;
+            }
+        break;
+    }
+
+    $vide = 0;
+    foreach($saisie['valeurs'] as $valeur) {
+        if ($valeur == '') $vide++;
+        switch($saisie['type_saisie']) {
+            case 'case' :
+            case 'oui_non' :
+                if(isset($ligne['oui']) == false) $ligne['oui'] = 0;
+                if(isset($ligne['non']) == false) $ligne['non'] = 0;
+                if ($valeur) $ligne['oui']++; else $ligne['non']++;
+            break;
+            case 'input' :
+            case 'hidden' :
+            case 'explication' :
+            break;
+        }
+    }
+    $ligne['sans_reponse'] = $vide;
+    $ligne['header'] = $saisie['label'] != ''
+        ? $saisie['label']
+        : $saisie['type_saisie'];
+
+    return $ligne;
+}
+
+
+/**
+ * Tente de déserialiser un texte
+ *
+ * Si le paramètre est un tableau, retourne le tableau,
+ * Si c'est une chaîne, tente de la désérialiser, sinon
+ * retourne la chaîne.
+ *
+ * @filtre tenter_unserialize
+ *
+ * @param string|array $texte
+ *     Le texte (possiblement sérializé) ou un tableau
+ * @return array|string
+ *     Tableau, texte désérializé ou texte
+**/
+function filtre_tenter_unserialize_dist($texte) {
+    if (is_array($texte)) {
+        return $texte;
+    }
+    if ($tmp = @unserialize($texte)) {
+        return $tmp;
+    }
+    return $texte;
+}
+
+
+/**
+ * Retourne un texte du nombre de réponses
+ *
+ * @param int $nb
+ *     Nombre de réponses
+ * @return string
+ *     Texte indiquant le nombre de réponses
+**/
+function titre_nb_reponses($nb) {
+    if (!$nb) return _T('formidable:reponse_aucune');
+    if ($nb == 1) return _T('formidable:reponse_une');
+    return _T('formidable:reponses_nb', array('nb' => $nb));
+}
+
+/**
+ * Transforme le hash MD5 en une valeur numérique unique
+ *
+ * trouvé ici : http://stackoverflow.com/questions/1422725/represent-md5-hash-as-an-integer
+ * @param string $hex_str La valeur alphanumérique à transformer
+ * @return string Valeur numérique
+*/
+function md5_hex_to_dec($hex_str) {
+    $arr = str_split($hex_str, 4);
+    foreach ($arr as $grp) {
+        $dec[] = str_pad(hexdec($grp), 5, '0', STR_PAD_LEFT);
+    }
+
+    /* on s'assure que $result ne commence pas par un zero */
+    $result = implode('', $dec);
+    for ($cpt = 0 ; $cpt < strlen($result) ; $cpt++) {
+        if ($result[$cpt] != '0') break;
+    }
+    $result = substr($result, $cpt);
+    return $result;
+}
+
+/**
+ * Transforme un login en une valeur numérique de 19 caractères
+ *
+ * NOTE: il devient impossible de retrouver la valeur d'origine car le HASH
+ * est coupé à 19cars et est donc incomplet. L'unicité n'est pas garantie mais
+ * les chances pour que deux logins tombent sur le même HASH sont de 1 sur
+ * 10 milliards de milliards
+ * A la fin, on recherche et supprime les éventuels zéros de début
+ * @param string $login Login à transformer
+ * @param string $passwd Chaîne 'secrète' ajoutée au login et id_formulaire pour éviter
+ *  les recoupements d'identité entre plusieurs formulaires
+ * @return string Un nombre de 19 chiffres
+*/
+function formidable_scramble($login, $passwd = '') {
+    $id_form = (isset($flux['args']['id_form']) ? $flux['args']['id_form'] : '');
+    if ($passwd == '')
+        $passwd = $GLOBALS['formulaires']['passwd']['interne'];
+    $login_md5 = md5("$login$passwd$id_form");
+    $login_num = md5_hex_to_dec($login_md5);
+    $login_num = substr($login_num, 0, 19);
+
+    return $login_num;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/lang/formidable.xml b/www/plugins/formidable_1_0/lang/formidable.xml
new file mode 100644 (file)
index 0000000..6b0c94e
--- /dev/null
@@ -0,0 +1,24 @@
+<traduction module="formidable" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/formidable/trunk/lang/" reference="fr">
+       <langue code="de" url="http://trad.spip.net/tradlang_module/formidable?lang_cible=de">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/formidable?lang_cible=en">
+               <traducteur nom="Benitron" lien="http://trad.spip.net/auteur/benitron" />
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+               <traducteur nom="Paolo" lien="http://trad.spip.net/auteur/paolo" />
+               <traducteur nom="twelf" lien="http://trad.spip.net/auteur/twelf" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/formidable?lang_cible=es">
+               <traducteur nom="tin" lien="http://trad.spip.net/auteur/tin" />
+       </langue>
+       <langue code="fr" url="http://trad.spip.net/tradlang_module/formidable?lang_cible=fr">
+               <traducteur nom="Salvatore" lien="http://trad.spip.net/auteur/salvatore" />
+       </langue>
+       <langue code="it" url="http://trad.spip.net/tradlang_module/formidable?lang_cible=it">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/formidable?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+</traduction>
diff --git a/www/plugins/formidable_1_0/lang/formidable_de.php b/www/plugins/formidable_1_0/lang/formidable_de.php
new file mode 100644 (file)
index 0000000..d1e6a7a
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/formidable?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'analyse_avec_reponse' => 'Ausgefüllte Antworten',
+       'analyse_exporter' => 'Analyse exportieren',
+       'analyse_longueur_moyenne' => 'Durchschnittliche Anzahl Worte',
+       'analyse_nb_reponses_total' => '@nb@ personnes ont répondu à ce formulaire.', # NEW
+       'analyse_sans_reponse' => 'Leere Antworten',
+       'analyse_une_reponse_total' => 'Une personne a répondu à ce formulaire.', # NEW
+       'analyse_zero_reponse_total' => 'Aucune personne n\'a répondu à ce formulaire.', # NEW
+       'aucun_traitement' => 'Aucun traitement', # NEW
+
+       // B
+       'bouton_formulaires' => 'Formulare',
+
+       // C
+       'cfg_analyse_classe_explication' => 'Vous pouvez indiquer des classes CSS qui seront ajoutées
+               sur le conteneur de chaque graphique, tel que <code>gray</code>,<code>blue</code>,
+               <code>orange</code>, <code>green</code> ou tout ce qui vous plairait !', # NEW
+       'cfg_analyse_classe_label' => 'Classe CSS de la barre de progression', # NEW
+       'cfg_titre_page_configurer_formidable' => 'Configurer Formidable', # NEW
+       'cfg_titre_parametrages_analyse' => 'Paramétrages de l\'analyse des réponses', # NEW
+       'champs' => 'Felder',
+
+       // E
+       'echanger_formulaire_forms_importer' => 'Forms & Tables (.xml)',
+       'echanger_formulaire_wcs_importer' => 'W.C.S. (.wcs)',
+       'echanger_formulaire_yaml_importer' => 'Formidable (.yaml)',
+       'editer_apres_choix_formulaire' => 'Le formulaire, à nouveau', # NEW
+       'editer_apres_choix_redirige' => 'Rediriger vers une nouvelle adresse', # NEW
+       'editer_apres_choix_rien' => 'Rien du tout', # NEW
+       'editer_apres_choix_stats' => 'Les statistiques des réponses', # NEW
+       'editer_apres_choix_valeurs' => 'Les valeurs saisies', # NEW
+       'editer_apres_explication' => 'Après validation, afficher à la place du formulaire :', # NEW
+       'editer_apres_label' => 'Afficher ensuite', # NEW
+       'editer_descriptif' => 'Beschreibung',
+       'editer_descriptif_explication' => 'Eine Beschreibung des Formulars für das Backend.',
+       'editer_identifiant' => 'Bezeichnung',
+       'editer_identifiant_explication' => 'Gegen sie eine Bezeichnung an, mit dem sie das Formular ansprechen können.',
+       'editer_menu_auteurs' => 'Configurer les auteurs', # NEW
+       'editer_menu_champs' => 'Felder konfigurieren',
+       'editer_menu_formulaire' => 'Formular konfigurieren',
+       'editer_menu_traitements' => 'Verarbeitung konfigurieren',
+       'editer_message_ok' => 'Bestätigungstext',
+       'editer_message_ok_explication' => 'Sie können die Nachricht festlegen, die nach dem Absenden des Formulars angezeigt wird.',
+       'editer_modifier_formulaire' => 'Formular ändern',
+       'editer_nouveau' => 'Neues Formular',
+       'editer_redirige_url' => 'Adresse de redirection après validation', # NEW
+       'editer_redirige_url_explication' => 'Laissez vide si vous souhaitez rester sur la même page', # NEW
+       'editer_titre' => 'Titel',
+       'erreur_autorisation' => 'Sie sind nicht berechtigt, die Formulare der Website zu ändern.',
+       'erreur_base' => 'Beim Speichern ist ein technischer Fehler aufgetreten.',
+       'erreur_generique' => 'Die Felder enthalten Fehler. Bitte überprüfen sie ihre Eingaben.',
+       'erreur_identifiant' => 'Diese Bezeichnung wird bereits verwendet.',
+       'erreur_importer_forms' => 'Fehler beim Importieren des Formulars aus Forms&Tables',
+       'erreur_importer_wcs' => 'Fehler beim Importieren des Formulars aus W.C.S',
+       'erreur_importer_yaml' => 'Fehler beim Importieren des Formulars aus YAML',
+       'erreur_inexistant' => 'Formular nicht vorhanden.',
+
+       // F
+       'formulaire_anonyme_explication' => 'Diese Form ist anonym, dh die Identität des Benutzers nicht registriert ist.', # MODIF
+       'formulaires_aucun' => 'Kein Formular vorhanden.',
+       'formulaires_dupliquer' => 'Formular kopieren',
+       'formulaires_dupliquer_copie' => '(Kopie)',
+       'formulaires_introduction' => 'Erstellen und bearbeiten sie Formulare für ihre Website.',
+       'formulaires_nouveau' => 'Neues Formular anlegen',
+       'formulaires_supprimer' => 'Formular löschen',
+       'formulaires_supprimer_confirmation' => 'Achtung - alle Daten aus dem Formular werden ebenfalls gelöscht. Sind sie sicher, dass sie das Formular löschen wollen?',
+       'formulaires_tous' => 'Alle Formulare',
+
+       // I
+       'identification_par_cookie' => 'Par cookie', # NEW
+       'identification_par_id_auteur' => 'Par l\'identifiant (id_auteur) de la personne authentifiée', # NEW
+       'importer_formulaire' => 'Formular importieren',
+       'importer_formulaire_fichier_label' => 'Dateien importeieren',
+       'importer_formulaire_format_label' => 'Format der Datei',
+
+       // M
+       'modele_label_formulaire_formidable' => 'Quel formulaire ?', # NEW
+       'modele_nom_formulaire' => 'un formulaire', # NEW
+
+       // N
+       'noisette_label_afficher_titre_formulaire' => 'Afficher le titre du formulaire ?', # NEW
+       'noisette_label_identifiant' => 'Formulaire à afficher :', # NEW
+       'noisette_nom_noisette_formulaire' => 'Formulaire', # NEW
+
+       // R
+       'reponse_aucune' => 'Aucune réponse', # NEW
+       'reponse_intro' => '@auteur@ hat auf das Formular geantwortet @formulaire@',
+       'reponse_numero' => 'Antwort Nummer:',
+       'reponse_statut' => 'Diese Antwort ist:',
+       'reponse_supprimer' => 'Diese Antwort löschen',
+       'reponse_supprimer_confirmation' => 'Wollen sie diese Antwor wirklich löschen?',
+       'reponse_une' => '1 réponse', # NEW
+       'reponses_analyse' => 'Analyse der Antworten',
+       'reponses_anonyme' => 'Anonym',
+       'reponses_auteur' => 'Nutzer',
+       'reponses_exporter' => 'Antworten exportieren',
+       'reponses_ip' => 'IP-Adresse',
+       'reponses_liste' => 'Liste der Antworten',
+       'reponses_liste_prop' => 'Nicht freigegebene Antworten',
+       'reponses_liste_publie' => 'Alle freigegebenen Antworten',
+       'reponses_nb' => '@nb@ réponses', # NEW
+       'reponses_voir_detail' => 'Antwort anzeigen',
+       'retour_aucun_traitement' => 'Ihre Antwort wurde gesendet, jedoch wurde keine Verarbeitungsoption für das Formular festgelegt. Deshalb geschieht mit den Daten aus diesem Formular überhaupt nichts. :)',
+
+       // S
+       'sans_reponses' => 'Unbeantwortet',
+
+       // T
+       'titre_cadre_raccourcis' => 'Raccourcis', # NEW
+       'traitements_actives' => 'Traitements activés', # NEW
+       'traitements_aide_memoire' => 'Merkzettel:',
+       'traitements_avertissement_creation' => 'Die Änderungen der Felder des Formulars wurden erfolgreich gespeichert. Jetzt können sie festlege, welche Verarbeitungsschritte nach dem Senden des Formulars ausgef',
+       'traitements_avertissement_modification' => 'Die Änderungen der Felder des Formulars wurden erfolgreich gespeichert. <strong>Manche Verarbeitungsoptionen müssen entsprechend neu konfiguriert werden.</strong>',
+       'traitements_champ_aucun' => 'Kein',
+       'traiter_email_description' => 'Sendet das Ergebnis des Formulars an eine Empfängerliste.',
+       'traiter_email_horodatage' => 'Formular "@formulaire@" am @date@ um @heure@ gesendet.',
+       'traiter_email_message_erreur' => 'Beim Versenden des Formulars ist ein Fehler aufgetreten.',
+       'traiter_email_message_ok' => 'Ihre Nachricht wurde per Mail gesendet.',
+       'traiter_email_option_activer_accuse_label' => 'Empfangsbestätigung',
+       'traiter_email_option_activer_accuse_label_case' => 'Ebenfalls eine Empfangsbestätigung an Absender senden.',
+       'traiter_email_option_destinataires_explication' => 'Legen sie das Feld fest, das die Empfängeradresse enthält.',
+       'traiter_email_option_destinataires_label' => 'Empfänger',
+       'traiter_email_option_destinataires_plus_explication' => 'Eine kommagetrennte Empfängerliste.',
+       'traiter_email_option_destinataires_plus_label' => 'Weitere Empfänger',
+       'traiter_email_option_envoyeur_courriel_explication' => 'Legen sie das Feld fest, das die Absenderadresse enthält.',
+       'traiter_email_option_envoyeur_courriel_label' => 'Absenderadresse',
+       'traiter_email_option_envoyeur_nom_explication' => 'Definieren sie den Namen mit Hilf der @raccourcis@ (siehe Merkzettel). Wenn sie nichts eintragen, wird der Name der Website verwendet.',
+       'traiter_email_option_envoyeur_nom_label' => 'Name des Absenders',
+       'traiter_email_option_sujet_accuse_label' => 'Betreff der Empfangsbestätigung',
+       'traiter_email_option_sujet_explication' => 'Definieren sie den Betreff mit Hilf der @raccourcis@. Wenn sie das Feld freilassen, wird der Inhalt automatisch erstellt.',
+       'traiter_email_option_sujet_label' => 'Betreff der Nachricht',
+       'traiter_email_option_vrai_envoyeur_explication' => 'Certains serveurs SMTP ne permettent pas d\'utiliser un courriel arbitraire pour le champ "From". Pour cette raison Formidable insère par défaut le courriel de l\'envoyeur dans le champ "Reply-To". Cocher ici pour insèrer le courriel dans le champ "From".', # NEW
+       'traiter_email_option_vrai_envoyeur_label' => 'Insérer le courriel de l\'envoyeur dans le champ "From"', # NEW
+       'traiter_email_page' => '<a href="@url@">Aus der Seite</a>.',
+       'traiter_email_sujet' => '@nom@ hat ihnen geschrieben.',
+       'traiter_email_sujet_accuse' => 'Danke für ihre Antwort.',
+       'traiter_email_titre' => 'Per Mail senden',
+       'traiter_email_url_enregistrement' => 'Sie könen die Antworten <a href="@url@">auf dieser Seite verwalten</a>.',
+       'traiter_enregistrement_description' => 'Einträge in das Formular in der Datenbank speichern',
+       'traiter_enregistrement_erreur_base' => 'Beim Speichern in der Datenbank ist ein Fehler aufgetreten',
+       'traiter_enregistrement_erreur_deja_repondu' => 'Sie haben dieses Formular bereits ausgefüllt.',
+       'traiter_enregistrement_erreur_edition_reponse_inexistante' => 'La réponse à éditer est introuvable.', # NEW
+       'traiter_enregistrement_option_anonymiser_explication' => 'Stellen die Ergebnisse der anonymen Form (nicht halten Trace-Kennung der Befragten).', # MODIF
+       'traiter_enregistrement_option_anonymiser_label' => 'Anonymisierter Form',
+       'traiter_enregistrement_option_anonymiser_variable_explication' => 'Welches System Variable verwendet, um einen einzelnen Wert für jeden Autor ohne Offenlegung seiner Identität zu berechnen.',
+       'traiter_enregistrement_option_anonymiser_variable_label' => 'Variable aus dem anonymisierter Form.',
+       'traiter_enregistrement_option_auteur' => 'Utiliser les auteurs pour les formulaires', # NEW
+       'traiter_enregistrement_option_auteur_explication' => 'Attribuer un ou plusieurs auteurs à un formulaire. Si cette option est activée, seuls les auteurs d\'un formulaire pourront accéder à leurs données.', # NEW
+       'traiter_enregistrement_option_choix_select_label' => 'Wählen eine Variable von denen zur Verfügung.',
+       'traiter_enregistrement_option_identification_explication' => 'Si les réponses sont modifiables, quel procédé utiliser en priorité pour connaitre la réponse à modifier ?', # NEW
+       'traiter_enregistrement_option_identification_label' => 'Identification', # NEW
+       'traiter_enregistrement_option_moderation_label' => 'Moderation',
+       'traiter_enregistrement_option_modifiable_explication' => 'Sollen die Besucher ihre Antworten nachträglich &aauml;ndern können?',
+       'traiter_enregistrement_option_modifiable_label' => 'Antworten editierbar',
+       'traiter_enregistrement_option_multiple_explication' => 'Darf die gleiche Person das Formular mehrmals ausfüllen und absenden?',
+       'traiter_enregistrement_option_multiple_label' => 'Mehrfache Antworten',
+       'traiter_enregistrement_titre' => 'Ergebnisse speichern',
+
+       // V
+       'voir_exporter' => 'Formular exportieren',
+       'voir_numero' => 'Formular Nummer:',
+       'voir_reponses' => 'Antworten anzeigen',
+       'voir_traitements' => 'Verarbeitungsoptionen'
+);
+
+?>
diff --git a/www/plugins/formidable_1_0/lang/formidable_en.php b/www/plugins/formidable_1_0/lang/formidable_en.php
new file mode 100644 (file)
index 0000000..a2f393e
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/formidable?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'analyse_avec_reponse' => 'Non-empty answers',
+       'analyse_exporter' => 'Export analysis',
+       'analyse_longueur_moyenne' => 'Average number in words length',
+       'analyse_nb_reponses_total' => '@nb@ people responded to this form.',
+       'analyse_sans_reponse' => 'Stayed unanswered',
+       'analyse_une_reponse_total' => 'One person responded to this form.',
+       'analyse_zero_reponse_total' => 'No one responded to this form.',
+       'aucun_traitement' => 'No treatment',
+
+       // B
+       'bouton_formulaires' => 'Forms',
+
+       // C
+       'cfg_analyse_classe_explication' => 'You can specify CSS classes that will be added on the container of each graph, such as 
+<code>gray</code>,<code>blue</code>,
+               <code>orange</code>, <code>green</code> or whatever you like!',
+       'cfg_analyse_classe_label' => 'CSS class of the progress bar',
+       'cfg_titre_page_configurer_formidable' => 'Configure Formidable',
+       'cfg_titre_parametrages_analyse' => 'Settings in the answers analysis',
+       'champs' => 'Fields',
+
+       // E
+       'echanger_formulaire_forms_importer' => 'Forms & Tables (.xml)',
+       'echanger_formulaire_wcs_importer' => 'W.C.S. (.wcs)',
+       'echanger_formulaire_yaml_importer' => 'Formidable (.yaml)',
+       'editer_apres_choix_formulaire' => 'The form, again',
+       'editer_apres_choix_redirige' => 'Redirect to a new address',
+       'editer_apres_choix_rien' => 'Nothing',
+       'editer_apres_choix_stats' => 'Answers statistics',
+       'editer_apres_choix_valeurs' => 'The entered values',
+       'editer_apres_explication' => 'After validation, display instead of the form:',
+       'editer_apres_label' => 'Display then',
+       'editer_descriptif' => 'Description',
+       'editer_descriptif_explication' => 'An explanation of the form for the private area.',
+       'editer_identifiant' => 'Login',
+       'editer_identifiant_explication' => 'Give a single textual identifier that allows you to call the form more easily.',
+       'editer_menu_auteurs' => 'Configure authors',
+       'editer_menu_champs' => 'Configure the fields',
+       'editer_menu_formulaire' => 'Configure the form',
+       'editer_menu_traitements' => 'Configure the treatments',
+       'editer_message_ok' => 'Return message',
+       'editer_message_ok_explication' => 'You can customize the message that will be displayed to the user after submitting a valid form.',
+       'editer_modifier_formulaire' => 'Modify the form',
+       'editer_nouveau' => 'New form',
+       'editer_redirige_url' => 'Forwarding address after validation',
+       'editer_redirige_url_explication' => 'Leave blank if you want to stay on the same page',
+       'editer_titre' => 'Title',
+       'erreur_autorisation' => 'You do not have the right to edit the website forms',
+       'erreur_base' => 'An error occurred as the data was being saved.',
+       'erreur_generique' => 'There are errors in the fields below. Please check.',
+       'erreur_identifiant' => 'This login is already used.',
+       'erreur_importer_forms' => 'Error while importing the Forms&Tables form',
+       'erreur_importer_wcs' => 'Error while importing the W.C.S form',
+       'erreur_importer_yaml' => 'Error while importing the YAML file',
+       'erreur_inexistant' => 'This form doesn\'t exist.',
+
+       // F
+       'formulaire_anonyme_explication' => 'This form is anonymous; meaning that the user\'s identity won\'t be recorded.',
+       'formulaires_aucun' => 'There is no form for now',
+       'formulaires_dupliquer' => 'Duplicate the form',
+       'formulaires_dupliquer_copie' => '(copy)',
+       'formulaires_introduction' => 'Create and configure forms on your site here.',
+       'formulaires_nouveau' => 'Create a new form',
+       'formulaires_supprimer' => 'Delete the form',
+       'formulaires_supprimer_confirmation' => 'Beware, it will also remove all the results. Are you sure you want to delete this form?',
+       'formulaires_tous' => 'All forms',
+
+       // I
+       'identification_par_cookie' => 'By cookie',
+       'identification_par_id_auteur' => 'By login (id_auteur) of the authenticated person',
+       'importer_formulaire' => 'Import a form',
+       'importer_formulaire_fichier_label' => 'File to import',
+       'importer_formulaire_format_label' => 'File format',
+
+       // M
+       'modele_label_formulaire_formidable' => 'Which form ?',
+       'modele_nom_formulaire' => 'One form',
+
+       // N
+       'noisette_label_afficher_titre_formulaire' => 'Dispaly the title of the form ?',
+       'noisette_label_identifiant' => 'Form to display :',
+       'noisette_nom_noisette_formulaire' => 'Form',
+
+       // R
+       'reponse_aucune' => 'No answer',
+       'reponse_intro' => '@auteur@ answered to the form @formulaire@',
+       'reponse_numero' => 'Answer number :',
+       'reponse_statut' => 'This answer is :',
+       'reponse_supprimer' => 'Delete this reply',
+       'reponse_supprimer_confirmation' => 'Do you really wish to delete this reply?',
+       'reponse_une' => '1 reply',
+       'reponses_analyse' => 'Answer analysis',
+       'reponses_anonyme' => 'Anonymous',
+       'reponses_auteur' => 'User',
+       'reponses_exporter' => 'Export the answers',
+       'reponses_ip' => 'IP address',
+       'reponses_liste' => 'Answers list',
+       'reponses_liste_prop' => 'Answers pending for validation',
+       'reponses_liste_publie' => 'All validated answers',
+       'reponses_nb' => '@nb@ answers',
+       'reponses_voir_detail' => 'See the answer',
+       'retour_aucun_traitement' => 'Your reply was accepted. But as the function of the form has not yet been configured, nothing was done with your data!',
+
+       // S
+       'sans_reponses' => 'Unanswered',
+
+       // T
+       'titre_cadre_raccourcis' => 'Shortcuts',
+       'traitements_actives' => 'Activated treatments',
+       'traitements_aide_memoire' => 'List of shortcuts:',
+       'traitements_avertissement_creation' => 'Changes to the form fields have been successfully saved. You can now define which treatments will be performed when using the form.',
+       'traitements_avertissement_modification' => 'Changes to the form fields have been successfully saved. <strong>Some treatments may need to be reconfigured accordingly.</ strong>',
+       'traitements_champ_aucun' => 'None',
+       'traiter_email_description' => 'Post the form results by email to a list of recipients.',
+       'traiter_email_horodatage' => 'Form "@formulaire@" sent on @date@ at @heure@.',
+       'traiter_email_message_erreur' => 'An error occurred when sending the email.',
+       'traiter_email_message_ok' => 'Your message has been successfully sent by email.',
+       'traiter_email_option_activer_accuse_label' => 'Acknowledgement of receipt',
+       'traiter_email_option_activer_accuse_label_case' => 'Also send an email to the sender with a confirmation message.',
+       'traiter_email_option_destinataires_explication' => 'Choose the field that corresponds to the message recipients.',
+       'traiter_email_option_destinataires_label' => 'Recipients',
+       'traiter_email_option_destinataires_plus_explication' => 'A list of addresses separated by commas.',
+       'traiter_email_option_destinataires_plus_label' => 'Extra recipients',
+       'traiter_email_option_envoyeur_courriel_explication' => 'Select the field that will contain the email address of the sender.',
+       'traiter_email_option_envoyeur_courriel_label' => 'Sender Email',
+       'traiter_email_option_envoyeur_nom_explication' => 'Build this name using the @raccourcis@ (see the notes). If you enter nothing, it will be the name of the site.',
+       'traiter_email_option_envoyeur_nom_label' => 'Name of sender',
+       'traiter_email_option_sujet_accuse_label' => 'Subject of the acknowledgement of receipt',
+       'traiter_email_option_sujet_explication' => 'Build topic using @raccourcis@. If you enter nothing, the subject will be built automatically.',
+       'traiter_email_option_sujet_label' => 'Message subject',
+       'traiter_email_option_vrai_envoyeur_explication' => 'Some SMTP servers do not allow to use arbitrary email for the "From" field. For this reason Formidable inserts the default email sender in the "Reply-To". Tick here to insert the email in the "From" field.',
+       'traiter_email_option_vrai_envoyeur_label' => 'Insert email of the sender in the "From" field',
+       'traiter_email_page' => '<a href="@url@">From this page</a>.',
+       'traiter_email_sujet' => '@nom@ has written to you.',
+       'traiter_email_sujet_accuse' => 'Thank you for you reply.',
+       'traiter_email_titre' => 'Send by email',
+       'traiter_email_url_enregistrement' => 'You can manage the answers <a href="@url@">on this page</a>.',
+       'traiter_enregistrement_description' => 'Saves the form results in the database',
+       'traiter_enregistrement_erreur_base' => 'An error occurred while writing to the database',
+       'traiter_enregistrement_erreur_deja_repondu' => 'You have already filled in this form.',
+       'traiter_enregistrement_erreur_edition_reponse_inexistante' => 'The answer to edit can not be found.',
+       'traiter_enregistrement_option_anonymiser_explication' => 'Make the form results anonymous (don\'t keep any tracks of user who have answered).',
+       'traiter_enregistrement_option_anonymiser_label' => 'Anonymize form',
+       'traiter_enregistrement_option_anonymiser_variable_explication' => 'What system variable used to calculate a single value for each author without revealing his identity.',
+       'traiter_enregistrement_option_anonymiser_variable_label' => 'Variable from witch the form will be anonymized',
+       'traiter_enregistrement_option_auteur' => 'Link authors to the forms',
+       'traiter_enregistrement_option_auteur_explication' => 'Bind one or more authors to a form. If activated, this option prevents anyone except the author(s) to access form\'s configuration or results.',
+       'traiter_enregistrement_option_choix_select_label' => 'Select a variable from the available',
+       'traiter_enregistrement_option_identification_explication' => 'If the answers can be changed, which method is used first to know the answer to modify ?',
+       'traiter_enregistrement_option_identification_label' => 'Identification',
+       'traiter_enregistrement_option_moderation_label' => 'Moderation',
+       'traiter_enregistrement_option_modifiable_explication' => 'May visitors change their answers afterwards?',
+       'traiter_enregistrement_option_modifiable_label' => 'Answers can be modified',
+       'traiter_enregistrement_option_multiple_explication' => 'May a single person answer several times to the form?',
+       'traiter_enregistrement_option_multiple_label' => 'Multiple answers',
+       'traiter_enregistrement_titre' => 'Record the results',
+
+       // V
+       'voir_exporter' => 'Export the form',
+       'voir_numero' => 'Form number :',
+       'voir_reponses' => 'See the answers',
+       'voir_traitements' => 'Treatments'
+);
+
+?>
diff --git a/www/plugins/formidable_1_0/lang/formidable_es.php b/www/plugins/formidable_1_0/lang/formidable_es.php
new file mode 100644 (file)
index 0000000..9e3e336
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/formidable?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'analyse_avec_reponse' => 'Respuestas no vacías',
+       'analyse_exporter' => 'Exportar análisis',
+       'analyse_longueur_moyenne' => 'Longitud media de las palabras',
+       'analyse_nb_reponses_total' => '@nb@ personas han respondido a este formulario. ',
+       'analyse_sans_reponse' => 'Sin respuesta',
+       'analyse_une_reponse_total' => 'Una persona ha respondido a este formulario. ',
+       'analyse_zero_reponse_total' => 'Nadie ha respondido a este formulario.',
+       'aucun_traitement' => 'Ningún tratamiento',
+
+       // B
+       'bouton_formulaires' => 'Formularios',
+
+       // C
+       'cfg_analyse_classe_explication' => 'Puede especificar clases CSS que se añadirán en el envase de cada gráfico, tales como: <code>gray</code>,<code>blue</code>,
+               <code>orange</code>, <code>green</code> o las que quieras!',
+       'cfg_analyse_classe_label' => 'Clase CSS de la barra de progreso',
+       'cfg_titre_page_configurer_formidable' => 'Configurar Formidable',
+       'cfg_titre_parametrages_analyse' => 'Configuración en el análisis de respuestas',
+       'champs' => 'Campos',
+
+       // E
+       'echanger_formulaire_forms_importer' => 'Forms & Tables (.xml)',
+       'echanger_formulaire_wcs_importer' => 'W.C.S. (.wcs)',
+       'echanger_formulaire_yaml_importer' => 'Formidable (.yaml)',
+       'editer_apres_choix_formulaire' => 'El formulario, de nuevo',
+       'editer_apres_choix_redirige' => 'Redirigir a una nueva dirección',
+       'editer_apres_choix_rien' => 'Nada',
+       'editer_apres_choix_stats' => 'Estadísticas de respuesta',
+       'editer_apres_choix_valeurs' => 'Los valores ingresados',
+       'editer_apres_explication' => 'Después de la validación, mostrar en lugar del formulario:',
+       'editer_apres_label' => 'Mostrar a continuación',
+       'editer_descriptif' => 'Descripción',
+       'editer_descriptif_explication' => 'Una explicación del formulario para la zona privada.',
+       'editer_identifiant' => 'Nombre de usuario',
+       'editer_identifiant_explication' => 'Da un único identificador textual que permita llamar al formulario de manera más sencilla',
+       'editer_menu_auteurs' => 'Configurer les auteurs', # NEW
+       'editer_menu_champs' => 'Configurar los campos',
+       'editer_menu_formulaire' => 'Configurar el formulario',
+       'editer_menu_traitements' => 'Configurar los tratamientos',
+       'editer_message_ok' => 'Mensaje de respuesta',
+       'editer_message_ok_explication' => 'Puedes personalizar el mensaje que se mostrará al usuario después de enviar un formulario válido.',
+       'editer_modifier_formulaire' => 'Modificar el formulario',
+       'editer_nouveau' => 'Nuevo formulario',
+       'editer_redirige_url' => 'Dirección de reenvío después de la validación',
+       'editer_redirige_url_explication' => 'Dejar en blanco si quieres permanecer en la misma página',
+       'editer_titre' => 'Título',
+       'erreur_autorisation' => 'No tienes permisos para editar los formularios web',
+       'erreur_base' => 'Se ha producido un error técnico mientras se salvavan los datos.',
+       'erreur_generique' => 'Hay errores en los campos a continuación. Por favor, comprueba. ',
+       'erreur_identifiant' => 'El nombre de usuario ya está siendo utilizado.',
+       'erreur_importer_forms' => 'Error durante la importación de Forms&Tables',
+       'erreur_importer_wcs' => 'Error durante la importación del formulario W.C.S',
+       'erreur_importer_yaml' => 'Error durante la importación del archivo YAML',
+       'erreur_inexistant' => 'Este formulario no existe. ',
+
+       // F
+       'formulaire_anonyme_explication' => 'Este formulario es anónimo; significa que que la identidad del usuario no será guardada. ',
+       'formulaires_aucun' => 'Todavía no existe ningún formulario.',
+       'formulaires_dupliquer' => 'Duplicar el formulario',
+       'formulaires_dupliquer_copie' => '(copia)',
+       'formulaires_introduction' => 'Crea y configura los formularios de tu sitio aquí.',
+       'formulaires_nouveau' => 'Crea un nuevo formulario',
+       'formulaires_supprimer' => 'Eliminar el formulario. ',
+       'formulaires_supprimer_confirmation' => 'Atención, también se eliminarán todos los resultados. ¿Está seguro de que desea eliminar este formulario?',
+       'formulaires_tous' => 'Todos los formularios',
+
+       // I
+       'identification_par_cookie' => 'Por cookie',
+       'identification_par_id_auteur' => 'Por el identificador (id_auteur) de la persona autenticada',
+       'importer_formulaire' => 'Importar un formulario',
+       'importer_formulaire_fichier_label' => 'Archivo a importar',
+       'importer_formulaire_format_label' => 'Formato de archivo',
+
+       // M
+       'modele_label_formulaire_formidable' => '¿Cuál formulario?',
+       'modele_nom_formulaire' => 'un formulario',
+
+       // N
+       'noisette_label_afficher_titre_formulaire' => '¿Mostrar el título del formulario? ',
+       'noisette_label_identifiant' => 'Formulario a mostrar:',
+       'noisette_nom_noisette_formulaire' => 'Formulario',
+
+       // R
+       'reponse_aucune' => 'Ninguna respuesta',
+       'reponse_intro' => '@auteur@ respondió el formulario @formulaire@',
+       'reponse_numero' => 'Respuesta numéro:',
+       'reponse_statut' => 'Esta respuesta es:',
+       'reponse_supprimer' => 'Eliminar esta respuesta',
+       'reponse_supprimer_confirmation' => '¿Estás seguro de que deseas eliminar esta respuesta?',
+       'reponse_une' => '1 respuesta',
+       'reponses_analyse' => 'Analizar las respuestas',
+       'reponses_anonyme' => 'Anónimo',
+       'reponses_auteur' => 'Usuario',
+       'reponses_exporter' => 'Exportar las respuestas',
+       'reponses_ip' => 'Dirección IP',
+       'reponses_liste' => 'Lista de respuestas',
+       'reponses_liste_prop' => 'Respuestas pendientes de validación',
+       'reponses_liste_publie' => 'Todas las respuestas validadas',
+       'reponses_nb' => '@nb@ respuestas',
+       'reponses_voir_detail' => 'Ver la respuesta',
+       'retour_aucun_traitement' => 'Su respuesta ha sido enviada, pero ningún tratamiento ha sido definido para este formulario. ¡No se hizo nada con sus datos!',
+
+       // S
+       'sans_reponses' => 'Sin respuesta',
+
+       // T
+       'titre_cadre_raccourcis' => 'Accesos directos',
+       'traitements_actives' => 'Tratamientos activados',
+       'traitements_aide_memoire' => 'Ayuda memoria: ',
+       'traitements_avertissement_creation' => 'Los cambios en los campos del formulario se han guardado correctamente. Ahora puedes definir que tratamientos se llevarán a cabo cuando se utilice el formulario.',
+       'traitements_avertissement_modification' => 'Los cambios en los campos del formulario se han guardado correctamente. <strong>Algunos tratamientos pueden necesitar ser reconfigurados en consecuencia. </strong>',
+       'traitements_champ_aucun' => 'Ninguno',
+       'traiter_email_description' => 'Publicar los resultados del formulario por correo electrónico a una lista de destinatarios.',
+       'traiter_email_horodatage' => 'Formulario "@formulaire@" publicado el @date@ a las @heure@.',
+       'traiter_email_message_erreur' => 'Se ha producido un error al enviar el correo electrónico. ',
+       'traiter_email_message_ok' => 'Tu mensaje ha sido enviado por correo electrónico.',
+       'traiter_email_option_activer_accuse_label' => 'Acuse de recibo',
+       'traiter_email_option_activer_accuse_label_case' => 'También enviar un correo electrónico al remitente con un mensaje de confirmación.',
+       'traiter_email_option_destinataires_explication' => 'Elige el campo que corresponde a los destinatarios del mensaje.',
+       'traiter_email_option_destinataires_label' => 'Destinatarios',
+       'traiter_email_option_destinataires_plus_explication' => 'Una lista de direcciones separadas por coma',
+       'traiter_email_option_destinataires_plus_label' => 'Destinatarios extra',
+       'traiter_email_option_envoyeur_courriel_explication' => 'Selecciona el campo que contendrá la dirección de correo electrónico del remitente.',
+       'traiter_email_option_envoyeur_courriel_label' => 'Enviar email',
+       'traiter_email_option_envoyeur_nom_explication' => 'Construye este nombre usando los @raccourcis@ (usa la ayuda memoria). Si lo dejas en blanco se usará el nombre del sitio. ',
+       'traiter_email_option_envoyeur_nom_label' => 'Nombre del remitente',
+       'traiter_email_option_sujet_accuse_label' => 'Asunto del acuse de recibo. ',
+       'traiter_email_option_sujet_explication' => 'Construye este asunto usando los @raccourcis@ (usa la ayuda memoria). Si lo dejas en blanco se usará uno por defecto. ',
+       'traiter_email_option_sujet_label' => 'Asunto del mensaje',
+       'traiter_email_option_vrai_envoyeur_explication' => 'Algunos servidores SMTP no permiten el uso de un correo electrónico arbitrario para el campo "From". Por esta razón Formidable inserta  por defecto el correo del remitente en el campo "Reply-to". Marca aquí para insertarlo en el campo "From".',
+       'traiter_email_option_vrai_envoyeur_label' => 'Inserta el correo del remitente en el campo "From"',
+       'traiter_email_page' => '<a href="@url@">Desde esta página</a>.',
+       'traiter_email_sujet' => '@nom@ ha escrito a usted.',
+       'traiter_email_sujet_accuse' => 'Gracias por su respuesta. ',
+       'traiter_email_titre' => 'Enviar por correo electrónico',
+       'traiter_email_url_enregistrement' => 'Puede gestionar las respuestas <a href="@url@">desde esta página</a>.',
+       'traiter_enregistrement_description' => 'Salvar los resultados del formulario en una base de datos',
+       'traiter_enregistrement_erreur_base' => 'Se ha producido un error técnico mientras se escribía en la base de datos',
+       'traiter_enregistrement_erreur_deja_repondu' => 'Usted ya ha respondido a este formulario.',
+       'traiter_enregistrement_erreur_edition_reponse_inexistante' => 'La respuesta a editar no puso ser encontrada. ',
+       'traiter_enregistrement_option_anonymiser_explication' => 'Volver los resultados del formulario anónimos (no mantener ningún tipo de datos de los usuarios que han respondido).',
+       'traiter_enregistrement_option_anonymiser_label' => 'Anonimizar el formulario',
+       'traiter_enregistrement_option_anonymiser_variable_explication' => '¿Qué variable de sistema utilizará para calcular un valor único para cada autor sin revelar su identidad ?',
+       'traiter_enregistrement_option_anonymiser_variable_label' => 'Variable del formulario que anonimiza',
+       'traiter_enregistrement_option_auteur' => 'Utiliser les auteurs pour les formulaires', # NEW
+       'traiter_enregistrement_option_auteur_explication' => 'Attribuer un ou plusieurs auteurs à un formulaire. Si cette option est activée, seuls les auteurs d\'un formulaire pourront accéder à leurs données.', # NEW
+       'traiter_enregistrement_option_choix_select_label' => 'Seleccione una variable de las disponibles',
+       'traiter_enregistrement_option_identification_explication' => '¿Si las respuestas se pueden modificar, cuál es el método para usar en primer lugar para conocer la respuesta a modificar?',
+       'traiter_enregistrement_option_identification_label' => 'Identificación',
+       'traiter_enregistrement_option_moderation_label' => 'Moderación',
+       'traiter_enregistrement_option_modifiable_explication' => '¿Los visitantes pueden cambiar sus respuestas con posterioridad?',
+       'traiter_enregistrement_option_modifiable_label' => 'Respuestas modificables',
+       'traiter_enregistrement_option_multiple_explication' => '¿Una misma persona puede responder varias veces el formulario?',
+       'traiter_enregistrement_option_multiple_label' => 'Respuestas múltiples',
+       'traiter_enregistrement_titre' => 'Registra los resultados',
+
+       // V
+       'voir_exporter' => 'Exportar el formulario',
+       'voir_numero' => 'Formulario número:',
+       'voir_reponses' => 'Ver las respuesta',
+       'voir_traitements' => 'Tratamientos'
+);
+
+?>
diff --git a/www/plugins/formidable_1_0/lang/formidable_fr.php b/www/plugins/formidable_1_0/lang/formidable_fr.php
new file mode 100644 (file)
index 0000000..25b1f92
--- /dev/null
@@ -0,0 +1,173 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/formidable/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'analyse_avec_reponse' => 'Réponses non-vide',
+       'analyse_exporter' => 'Exporter l\'analyse',
+       'analyse_longueur_moyenne' => 'Longueur moyenne en nombre de mots',
+       'analyse_nb_reponses_total' => '@nb@ personnes ont répondu à ce formulaire.',
+       'analyse_sans_reponse' => 'Laissés blanc',
+       'analyse_une_reponse_total' => 'Une personne a répondu à ce formulaire.',
+       'analyse_zero_reponse_total' => 'Aucune personne n\'a répondu à ce formulaire.',
+       'aucun_traitement' => 'Aucun traitement',
+
+       // B
+       'bouton_formulaires' => 'Formulaires',
+
+       // C
+       'cfg_analyse_classe_explication' => 'Vous pouvez indiquer des classes CSS qui seront ajoutées
+               sur le conteneur de chaque graphique, tel que <code>gray</code>,<code>blue</code>,
+               <code>orange</code>, <code>green</code> ou tout ce qui vous plairait !',
+       'cfg_analyse_classe_label' => 'Classe CSS de la barre de progression',
+       'cfg_titre_page_configurer_formidable' => 'Configurer Formidable',
+       'cfg_titre_parametrages_analyse' => 'Paramétrages de l\'analyse des réponses',
+       'champs' => 'Champs',
+
+       // E
+       'echanger_formulaire_forms_importer' => 'Forms & Tables (.xml)',
+       'echanger_formulaire_wcs_importer' => 'W.C.S. (.wcs)',
+       'echanger_formulaire_yaml_importer' => 'Formidable (.yaml)',
+       'editer_apres_choix_formulaire' => 'Le formulaire, à nouveau',
+       'editer_apres_choix_redirige' => 'Rediriger vers une nouvelle adresse',
+       'editer_apres_choix_rien' => 'Rien du tout',
+       'editer_apres_choix_stats' => 'Les statistiques des réponses',
+       'editer_apres_choix_valeurs' => 'Les valeurs saisies',
+       'editer_apres_explication' => 'Après validation, afficher à la place du formulaire :',
+       'editer_apres_label' => 'Afficher ensuite',
+       'editer_descriptif' => 'Descriptif',
+       'editer_descriptif_explication' => 'Une explication du formulaire destinée à l\'espace privé.',
+       'editer_identifiant' => 'Identifiant',
+       'editer_identifiant_explication' => 'Donnez un identifiant textuel unique qui vous permettra d\'appeler plus facilement le formulaire.',
+       'editer_menu_auteurs' => 'Configurer les auteurs',
+       'editer_menu_champs' => 'Configurer les champs',
+       'editer_menu_formulaire' => 'Configurer le formulaire',
+       'editer_menu_traitements' => 'Configurer les traitements',
+       'editer_message_ok' => 'Message de retour',
+       'editer_message_ok_explication' => 'Vous pouvez personnaliser le message qui sera affiché à l\'utilisateur après l\'envoi d\'un formulaire valide.',
+       'editer_modifier_formulaire' => 'Modifier le formulaire',
+       'editer_nouveau' => 'Nouveau formulaire',
+       'editer_redirige_url' => 'Adresse de redirection après validation',
+       'editer_redirige_url_explication' => 'Laissez vide si vous souhaitez rester sur la même page',
+       'editer_titre' => 'Titre',
+       'erreur_autorisation' => 'Vous n\'avez pas le droit d\'éditer les formulaires du site.',
+       'erreur_base' => 'Une erreur technique est survenue durant l\'enregistrement.',
+       'erreur_generique' => 'Il y a des erreurs dans les champs ci-dessous, veuillez vérifier votre envoi.',
+       'erreur_identifiant' => 'Cet identifiant est déjà utilisé.',
+       'erreur_importer_forms' => 'Erreur durant l\'importation du formulaire Forms&Tables',
+       'erreur_importer_wcs' => 'Erreur durant l\'importation du formulaire W.C.S',
+       'erreur_importer_yaml' => 'Erreur durant l\'importation du fichier YAML',
+       'erreur_inexistant' => 'Le formulaire n\'existe pas.',
+
+       // F
+       'formulaire_anonyme_explication' => 'Ce formulaire est anonyme, c\'est à dire que l\'identité de l\'utilisateur n\'est pas enregistrée.',
+       'formulaires_aucun' => 'Il n\'y a pour l\'instant aucun formulaire.',
+       'formulaires_dupliquer' => 'Dupliquer le formulaire',
+       'formulaires_dupliquer_copie' => '(copie)',
+       'formulaires_introduction' => 'Créez et configurez ici les formulaires de votre site.',
+       'formulaires_nouveau' => 'Créer un nouveau formulaire',
+       'formulaires_supprimer' => 'Supprimer le formulaire',
+       'formulaires_supprimer_confirmation' => 'Attention, cela supprimera aussi tous les résultats. Êtes-vous sûr de vouloir supprimer ce formulaire ?',
+       'formulaires_tous' => 'Tous les formulaires',
+
+       // I
+       'identification_par_cookie' => 'Par cookie',
+       'identification_par_id_auteur' => 'Par l\'identifiant (id_auteur) de la personne authentifiée',
+       'importer_formulaire' => 'Importer un formulaire',
+       'importer_formulaire_fichier_label' => 'Fichier à importer',
+       'importer_formulaire_format_label' => 'Format du fichier',
+
+       // M
+       'modele_label_formulaire_formidable' => 'Quel formulaire ?',
+       'modele_nom_formulaire' => 'un formulaire',
+
+       // N
+       'noisette_label_afficher_titre_formulaire' => 'Afficher le titre du formulaire ?',
+       'noisette_label_identifiant' => 'Formulaire à afficher :',
+       'noisette_nom_noisette_formulaire' => 'Formulaire',
+
+       // R
+       'reponse_aucune' => 'Aucune réponse',
+       'reponse_intro' => '@auteur@ a répondu au formulaire @formulaire@',
+       'reponse_numero' => 'Réponse numéro :',
+       'reponse_statut' => 'Cette réponse est :',
+       'reponse_supprimer' => 'Supprimer cette réponse',
+       'reponse_supprimer_confirmation' => 'Êtes-vous sûr de vouloir supprimer cette réponse ?',
+       'reponse_une' => '1 réponse',
+       'reponses_analyse' => 'Analyse des réponses',
+       'reponses_anonyme' => 'Anonyme',
+       'reponses_auteur' => 'Utilisateur',
+       'reponses_exporter' => 'Exporter les réponses',
+       'reponses_ip' => 'Adresse IP',
+       'reponses_liste' => 'Liste des réponses',
+       'reponses_liste_prop' => 'Réponses en attente de validation',
+       'reponses_liste_publie' => 'Toutes les réponses validées',
+       'reponses_nb' => '@nb@ réponses',
+       'reponses_voir_detail' => 'Voir la réponse',
+       'retour_aucun_traitement' => 'Votre réponse a bien été envoyée, mais aucun traitement n\'a été défini pour ce formulaire. Il ne fait donc rien. :)',
+
+       // S
+       'sans_reponses' => 'Sans réponse',
+
+       // T
+       'titre_cadre_raccourcis' => 'Raccourcis',
+       'traitements_actives' => 'Traitements activés',
+       'traitements_aide_memoire' => 'Aide mémoire :',
+       'traitements_avertissement_creation' => 'Les modifications sur les champs du formulaire ont été enregistrées avec succès. Vous pouvez maintenant définir quels traitements seront effectués lors de l\'utilisation du formulaire.',
+       'traitements_avertissement_modification' => 'Les modifications sur les champs du formulaire ont été enregistrées avec succès. <strong>Certains traitements doivent peut-être être reconfigurés en conséquence.</strong>',
+       'traitements_champ_aucun' => 'Aucun',
+       'traiter_email_description' => 'Poste le résultat du formulaire par courriel à une liste de destinataires.',
+       'traiter_email_horodatage' => 'Formulaire "@formulaire@" posté le @date@ à @heure@.',
+       'traiter_email_message_erreur' => 'Une erreur est survenue lors de l\'envoi du courriel.',
+       'traiter_email_message_ok' => 'Votre message a bien été envoyé par courriel.',
+       'traiter_email_option_activer_accuse_label' => 'Accusé de réception',
+       'traiter_email_option_activer_accuse_label_case' => 'Envoyer aussi un courriel à l\'adresse de l\'envoyeur avec un message de confirmation.',
+       'traiter_email_option_destinataires_explication' => 'Choisissez le champ qui correspondra aux destinataires du message.',
+       'traiter_email_option_destinataires_label' => 'Destinataires',
+       'traiter_email_option_destinataires_plus_explication' => 'Une liste d\'adresses séparées par des virgules.',
+       'traiter_email_option_destinataires_plus_label' => 'Destinataires supplémentaires',
+       'traiter_email_option_envoyeur_courriel_explication' => 'Choisissez le champ qui contiendra le courriel de l\'envoyeur.',
+       'traiter_email_option_envoyeur_courriel_label' => 'Courriel de l\'envoyeur',
+       'traiter_email_option_envoyeur_nom_explication' => 'Construisez ce nom à l\'aide des @raccourcis@ (cf. l\'aide mémoire). Si vous ne mettez rien, ce sera le nom du site.',
+       'traiter_email_option_envoyeur_nom_label' => 'Nom de l\'envoyeur',
+       'traiter_email_option_sujet_accuse_label' => 'Sujet de l\'accusé de réception',
+       'traiter_email_option_sujet_explication' => 'Construisez le sujet à l\'aide des @raccourcis@. Si vous ne mettez rien, le sujet sera construit automatiquement.',
+       'traiter_email_option_sujet_label' => 'Sujet du message',
+       'traiter_email_option_vrai_envoyeur_explication' => 'Certains serveurs SMTP ne permettent pas d\'utiliser un courriel arbitraire pour le champ "From". Pour cette raison Formidable insère par défaut le courriel de l\'envoyeur dans le champ "Reply-To". Cocher ici pour insèrer le courriel dans le champ "From".',
+       'traiter_email_option_vrai_envoyeur_label' => 'Insérer le courriel de l\'envoyeur dans le champ "From"',
+       'traiter_email_page' => '<a href="@url@">Depuis cette page</a>.',
+       'traiter_email_sujet' => '@nom@ vous a écrit.',
+       'traiter_email_sujet_accuse' => 'Merci de votre réponse.',
+       'traiter_email_titre' => 'Envoyer par courriel',
+       'traiter_email_url_enregistrement' => 'Vous pouvez gérer les réponses <a href="@url@">sur cette page</a>.',
+       'traiter_enregistrement_description' => 'Enregistre les résultats du formulaire dans la base de données',
+       'traiter_enregistrement_erreur_base' => 'Une erreur technique est survenue durant l\'enregistrement en base de données',
+       'traiter_enregistrement_erreur_deja_repondu' => 'Vous avez déjà répondu à ce formulaire.',
+       'traiter_enregistrement_erreur_edition_reponse_inexistante' => 'La réponse à éditer est introuvable.',
+       'traiter_enregistrement_option_anonymiser_explication' => 'Rendre les résultats du formulaire anonymes (ne pas garder de traces de l\'identifiant des personnes ayant répondu).',
+       'traiter_enregistrement_option_anonymiser_label' => 'Anonymiser le formulaire',
+       'traiter_enregistrement_option_anonymiser_variable_explication' => 'Quelle variable système utiliser pour calculer une valeur unique pour chaque auteur sans pour autant révéler son identité.',
+       'traiter_enregistrement_option_anonymiser_variable_label' => 'Variable à partir de laquelle anonymiser le formulaire',
+       'traiter_enregistrement_option_auteur' => 'Utiliser les auteurs pour les formulaires',
+       'traiter_enregistrement_option_auteur_explication' => 'Attribuer un ou plusieurs auteurs à un formulaire. Si cette option est activée, seuls les auteurs d\'un formulaire pourront accéder à leurs données.',
+       'traiter_enregistrement_option_choix_select_label' => 'Choisir une variable parmi celles proposées',
+       'traiter_enregistrement_option_identification_explication' => 'Si les réponses sont modifiables, quel procédé utiliser en priorité pour connaitre la réponse à modifier ?',
+       'traiter_enregistrement_option_identification_label' => 'Identification',
+       'traiter_enregistrement_option_moderation_label' => 'Modération',
+       'traiter_enregistrement_option_modifiable_explication' => 'Les visiteurs pourront-ils modifier leurs réponses après coup ?',
+       'traiter_enregistrement_option_modifiable_label' => 'Réponses modifiables',
+       'traiter_enregistrement_option_multiple_explication' => 'Une même personne peut-elle répondre plusieurs fois au formulaire ?',
+       'traiter_enregistrement_option_multiple_label' => 'Réponses multiples',
+       'traiter_enregistrement_titre' => 'Enregistrer les résultats',
+
+       // V
+       'voir_exporter' => 'Exporter le formulaire',
+       'voir_numero' => 'Formulaire numéro :',
+       'voir_reponses' => 'Voir les réponses',
+       'voir_traitements' => 'Traitements'
+);
+
+?>
diff --git a/www/plugins/formidable_1_0/lang/formidable_it.php b/www/plugins/formidable_1_0/lang/formidable_it.php
new file mode 100644 (file)
index 0000000..476b826
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/formidable?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'analyse_avec_reponse' => 'Risposte non vuote',
+       'analyse_exporter' => 'Esporta l\'analisi',
+       'analyse_longueur_moyenne' => 'Lunghezza media in numero di parole',
+       'analyse_nb_reponses_total' => '@nb@ personnes ont répondu à ce formulaire.', # NEW
+       'analyse_sans_reponse' => 'Risposte vuote',
+       'analyse_une_reponse_total' => 'Une personne a répondu à ce formulaire.', # NEW
+       'analyse_zero_reponse_total' => 'Aucune personne n\'a répondu à ce formulaire.', # NEW
+       'aucun_traitement' => 'Aucun traitement', # NEW
+
+       // B
+       'bouton_formulaires' => 'Moduli',
+
+       // C
+       'cfg_analyse_classe_explication' => 'Vous pouvez indiquer des classes CSS qui seront ajoutées
+               sur le conteneur de chaque graphique, tel que <code>gray</code>,<code>blue</code>,
+               <code>orange</code>, <code>green</code> ou tout ce qui vous plairait !', # NEW
+       'cfg_analyse_classe_label' => 'Classe CSS de la barre de progression', # NEW
+       'cfg_titre_page_configurer_formidable' => 'Configurer Formidable', # NEW
+       'cfg_titre_parametrages_analyse' => 'Paramétrages de l\'analyse des réponses', # NEW
+       'champs' => 'Campi',
+
+       // E
+       'echanger_formulaire_forms_importer' => 'Forms & Tables (.xml)',
+       'echanger_formulaire_wcs_importer' => 'W.C.S. (.wcs)',
+       'echanger_formulaire_yaml_importer' => 'Formidable (.yaml)',
+       'editer_apres_choix_formulaire' => 'Il modulo, nuovamente',
+       'editer_apres_choix_redirige' => 'Redirigi verso un nuovo indirizzo',
+       'editer_apres_choix_rien' => 'Assolutamente niente',
+       'editer_apres_choix_stats' => 'Les statistiques des réponses', # NEW
+       'editer_apres_choix_valeurs' => 'I valori immessi',
+       'editer_apres_explication' => 'Dopo la validazione, mostra al posto del modulo:',
+       'editer_apres_label' => 'Mostra di seguito',
+       'editer_descriptif' => 'Descrizione',
+       'editer_descriptif_explication' => 'Una spiegazione del modulo destinata allo spazio redazionale.',
+       'editer_identifiant' => 'Identificativo',
+       'editer_identifiant_explication' => 'Fornisci un identificativo testuale unico che ti permetterà di richiamare più facilmente il modulo.',
+       'editer_menu_auteurs' => 'Configurer les auteurs', # NEW
+       'editer_menu_champs' => 'Configura i campi',
+       'editer_menu_formulaire' => 'Configura il modulo',
+       'editer_menu_traitements' => 'Configura i trattamenti',
+       'editer_message_ok' => 'Messaggio di risposta',
+       'editer_message_ok_explication' => 'Puoi personalizzare il messaggio che sarà mostrato all\'utente dopo l\'invio di un modulo valido.',
+       'editer_modifier_formulaire' => 'Modifica il modulo',
+       'editer_nouveau' => 'Nuovo modulo',
+       'editer_redirige_url' => 'Indirizzo di redirezione dopo la validazione',
+       'editer_redirige_url_explication' => 'Lascia vuoto se desideri restare sulla stessa pagina',
+       'editer_titre' => 'Titolo',
+       'erreur_autorisation' => 'Non hai i permessi per la modifica dei moduli del sito.',
+       'erreur_base' => 'Un problema tecnico si è verificato rurante il salvataggio.',
+       'erreur_generique' => 'Ci sono degli errori nei campi di seguito, si prega di verificare i dati.',
+       'erreur_identifiant' => 'Questo identificativo è già utilizzato.',
+       'erreur_importer_forms' => 'Errore durante l\'importazione del modulo Forms&Tables',
+       'erreur_importer_wcs' => 'Errore durante l\'importazione del modulo W.C.S',
+       'erreur_importer_yaml' => 'Errore durante l\'importazione del modulo YAML',
+       'erreur_inexistant' => 'Il modulo non esiste.',
+
+       // F
+       'formulaire_anonyme_explication' => 'Ce formulaire est anonyme ; c\'est à dire que l\'identité de l\'utilisateur n\'est pas enregistrée.', # NEW
+       'formulaires_aucun' => 'Al momento non è presente alcun modulo.',
+       'formulaires_dupliquer' => 'Duplica il modulo',
+       'formulaires_dupliquer_copie' => '(copia)',
+       'formulaires_introduction' => 'Crea e configura qui i moduli del tuo sito.',
+       'formulaires_nouveau' => 'Crea un nuovo modulo',
+       'formulaires_supprimer' => 'Elimina il modulo',
+       'formulaires_supprimer_confirmation' => 'Attenzione, si sta per eliminare anche tutte le risposte. Sei sicuro di voler eliminare il modulo?',
+       'formulaires_tous' => 'Tutti i moduli',
+
+       // I
+       'identification_par_cookie' => 'Con i cookie',
+       'identification_par_id_auteur' => 'con l\'identificativo (id_auteur) dell\'utente autentificato',
+       'importer_formulaire' => 'Importa un modulo',
+       'importer_formulaire_fichier_label' => 'File da importare',
+       'importer_formulaire_format_label' => 'Formato del file',
+
+       // M
+       'modele_label_formulaire_formidable' => 'Quale modulo?',
+       'modele_nom_formulaire' => 'un modulo',
+
+       // N
+       'noisette_label_afficher_titre_formulaire' => 'Mostro il titolo del modulo?',
+       'noisette_label_identifiant' => 'Modulo da mostrare:',
+       'noisette_nom_noisette_formulaire' => 'Modulo',
+
+       // R
+       'reponse_aucune' => 'Aucune réponse', # NEW
+       'reponse_intro' => '@auteur@ ha risposto al modulo @formulaire@',
+       'reponse_numero' => 'Risposta numero:',
+       'reponse_statut' => 'Questa risposta è:',
+       'reponse_supprimer' => 'Elimina questa risposta',
+       'reponse_supprimer_confirmation' => 'Sei sicuro di voler eliminare questa risposta?',
+       'reponse_une' => '1 réponse', # NEW
+       'reponses_analyse' => 'Analisi delle risposte',
+       'reponses_anonyme' => 'Anonimo',
+       'reponses_auteur' => 'Utente',
+       'reponses_exporter' => 'Esporta le risposte',
+       'reponses_ip' => 'Indirizzo IP',
+       'reponses_liste' => 'Elenco delle risposte',
+       'reponses_liste_prop' => 'Risposte in attesa di validazione',
+       'reponses_liste_publie' => 'Tutte le risposte valide',
+       'reponses_nb' => '@nb@ réponses', # NEW
+       'reponses_voir_detail' => 'Vedi la risposta',
+       'retour_aucun_traitement' => 'La risposta è stata correttamente inviata. Grazie :)',
+
+       // S
+       'sans_reponses' => 'Senza risposta',
+
+       // T
+       'titre_cadre_raccourcis' => 'Raccourcis', # NEW
+       'traitements_actives' => 'Traitements activés', # NEW
+       'traitements_aide_memoire' => 'Promemoria:',
+       'traitements_avertissement_creation' => 'Le modifiche ai campi del modulo sono state registrate con successo. Ora puoi definire quali trattamenti saranno effettuati all\'atto dell\'invio del modulo.',
+       'traitements_avertissement_modification' => 'La modifiche ai campi del modulo sono state registrate con successo. <strong>Alcuni trattamenti devono forse essere riconfigurati di conseguenza.</strong>',
+       'traitements_champ_aucun' => 'Nessuno',
+       'traiter_email_description' => 'Invia il risultato del modulo per posta a un elenco di destinatari.',
+       'traiter_email_horodatage' => 'Modulo "@formulaire@" inviato il @date@ alle @heure@.',
+       'traiter_email_message_erreur' => 'Si è verificato un errore all\'atto dell\'invio dell\'email.',
+       'traiter_email_message_ok' => 'Il tuo messaggio è stato inviato per posta elettronica.',
+       'traiter_email_option_activer_accuse_label' => 'Conferma di ricezione',
+       'traiter_email_option_activer_accuse_label_case' => 'Invia anche una email all\'indirizzo del mittente con un messaggio di conferma.',
+       'traiter_email_option_destinataires_explication' => 'Scegli il campo che corrisponde al destinatario del messaggio.',
+       'traiter_email_option_destinataires_label' => 'Destinatari',
+       'traiter_email_option_destinataires_plus_explication' => 'Un elenco di indirizzi separati da virgole.',
+       'traiter_email_option_destinataires_plus_label' => 'Destinatari supplementari',
+       'traiter_email_option_envoyeur_courriel_explication' => 'Scegli il campo che contiene l\'indirizzo dell\'utente.',
+       'traiter_email_option_envoyeur_courriel_label' => 'Indirizzo del mittente',
+       'traiter_email_option_envoyeur_nom_explication' => 'Costruisci questo nome grazie all\'aiuto dei @segnaposto@ (vedi il promemoria). Se non inserisci nulla, verrà inserito il nome del sito.',
+       'traiter_email_option_envoyeur_nom_label' => 'Nome del mittente',
+       'traiter_email_option_sujet_accuse_label' => 'Oggetto della conferma di ricezione',
+       'traiter_email_option_sujet_explication' => 'Costruisci l\'oggetto grazie all\'aiuto dei @segnaposto@. Se non inserisci nulla, l\'oggetto verrà generato automaticamente.',
+       'traiter_email_option_sujet_label' => 'Oggetto del messaggio',
+       'traiter_email_option_vrai_envoyeur_explication' => 'Certains serveurs SMTP ne permettent pas d\'utiliser un courriel arbitraire pour le champ "From". Pour cette raison Formidable insère par défaut le courriel de l\'envoyeur dans le champ "Reply-To". Cocher ici pour insèrer le courriel dans le champ "From".', # NEW
+       'traiter_email_option_vrai_envoyeur_label' => 'Insérer le courriel de l\'envoyeur dans le champ "From"', # NEW
+       'traiter_email_page' => '<a href="@url@">Da questa pagina</a>.',
+       'traiter_email_sujet' => '@nom@ ti ha scritto.',
+       'traiter_email_sujet_accuse' => 'Grazie per aver risposto.',
+       'traiter_email_titre' => 'Invia per posta',
+       'traiter_email_url_enregistrement' => 'Puoi gestire le risposte <a href="@url@">su questa pagina</a>.',
+       'traiter_enregistrement_description' => 'Salva i risultati del modulo nella base dati',
+       'traiter_enregistrement_erreur_base' => 'Si è verificato un errore tecnico durante il salvataggio in database',
+       'traiter_enregistrement_erreur_deja_repondu' => 'Hai già risposto a questo modulo.',
+       'traiter_enregistrement_erreur_edition_reponse_inexistante' => 'La risposta da modificare non esiste.',
+       'traiter_enregistrement_option_anonymiser_explication' => 'Fare i risultati di forma anonima (non conservare traccia di identificazione degli intervistati).', # MODIF
+       'traiter_enregistrement_option_anonymiser_label' => 'Modo anonimo',
+       'traiter_enregistrement_option_anonymiser_variable_explication' => 'Quale variabile di sistema utilizzato per calcolare un singolo valore per ogni autore, senza rivelare la propria identità.',
+       'traiter_enregistrement_option_anonymiser_variable_label' => 'Variabile da cui la forma anonima',
+       'traiter_enregistrement_option_auteur' => 'Utiliser les auteurs pour les formulaires', # NEW
+       'traiter_enregistrement_option_auteur_explication' => 'Attribuer un ou plusieurs auteurs à un formulaire. Si cette option est activée, seuls les auteurs d\'un formulaire pourront accéder à leurs données.', # NEW
+       'traiter_enregistrement_option_choix_select_label' => 'Choisir une variable parmi celles proposées', # NEW
+       'traiter_enregistrement_option_identification_explication' => 'Se le risposte sono modificabili, quale procedura si dovrà utilizzare in priorità per individuare la risposta da modificare?',
+       'traiter_enregistrement_option_identification_label' => 'Identificazione',
+       'traiter_enregistrement_option_moderation_label' => 'Moderazione',
+       'traiter_enregistrement_option_modifiable_explication' => 'Gli utenti possono modificare le loro risposte dopo aver inviato il modulo?',
+       'traiter_enregistrement_option_modifiable_label' => 'Risposte modificabili',
+       'traiter_enregistrement_option_multiple_explication' => 'Un utente può risposndere più al modulo?',
+       'traiter_enregistrement_option_multiple_label' => 'Risposte multiple',
+       'traiter_enregistrement_titre' => 'Registra i risultati',
+
+       // V
+       'voir_exporter' => 'Esporta il modulo',
+       'voir_numero' => 'Modulo numero:',
+       'voir_reponses' => 'Vedi le risposte',
+       'voir_traitements' => 'Trattamenti'
+);
+
+?>
diff --git a/www/plugins/formidable_1_0/lang/formidable_sk.php b/www/plugins/formidable_1_0/lang/formidable_sk.php
new file mode 100644 (file)
index 0000000..e7997a7
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/formidable?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'analyse_avec_reponse' => 'Neprázdne odpovede',
+       'analyse_exporter' => 'Exportovať analýzu',
+       'analyse_longueur_moyenne' => 'Priemerná dĺžka vyjadrená počtom slov',
+       'analyse_nb_reponses_total' => '@nb@ ľudia odpovedali na tento formulár.',
+       'analyse_sans_reponse' => 'Nevyplnené',
+       'analyse_une_reponse_total' => 'Na tento formulár odpovedal jeden človek.',
+       'analyse_zero_reponse_total' => 'Na tento formulár neodpovedal žiaden človek.',
+       'aucun_traitement' => 'Žiadne spracovanie',
+
+       // B
+       'bouton_formulaires' => 'Formuláre',
+
+       // C
+       'cfg_analyse_classe_explication' => 'Môžete zadať triedy CSS, ktoré budú pridané 
+               na každý graf ako <code>sivý,</code> <code>modrý,</code>
+               <code>oranžový,</code> <code>zelený</code> alebo akýkoľvek iný stĺpec!',
+       'cfg_analyse_classe_label' => 'Trieda CSS stĺpca dokončenia úkonu',
+       'cfg_titre_page_configurer_formidable' => 'Nastaviť Formidable',
+       'cfg_titre_parametrages_analyse' => 'Nastavenia analýzy odpovedí',
+       'champs' => 'Pol\'a',
+
+       // E
+       'echanger_formulaire_forms_importer' => 'formuláre Forms & Tables (.xml)',
+       'echanger_formulaire_wcs_importer' => 'W.C.S. (.wcs)',
+       'echanger_formulaire_yaml_importer' => 'Formidable (.yaml)',
+       'editer_apres_choix_formulaire' => 'Formulár, znova',
+       'editer_apres_choix_redirige' => 'Presmerovať na novú adresu',
+       'editer_apres_choix_rien' => 'Vôbec nič',
+       'editer_apres_choix_stats' => 'Štatistiky odpovedí',
+       'editer_apres_choix_valeurs' => 'Zadané hodnoty',
+       'editer_apres_explication' => 'Po potvrdení namiesto formulára zobraziť:',
+       'editer_apres_label' => 'Zobraziť potom',
+       'editer_descriptif' => 'Popis',
+       'editer_descriptif_explication' => 'Vysvetlivka formulára pre súkromnú zónu.',
+       'editer_identifiant' => 'Identifikátor',
+       'editer_identifiant_explication' => 'Zadajte jedinečný textový identifikátor, ktorý vám umožní rýchlo vyvolať formulár.',
+       'editer_menu_auteurs' => 'Configurer les auteurs', # NEW
+       'editer_menu_champs' => 'Nastaviť polia',
+       'editer_menu_formulaire' => 'Nastaviť formulár',
+       'editer_menu_traitements' => 'Nastaviť funkcie',
+       'editer_message_ok' => 'Správa spätnej väzby',
+       'editer_message_ok_explication' => 'Môžete upraviť správu, ktorá sa používateľovi zobrazí po odoslaní platného formulára.',
+       'editer_modifier_formulaire' => 'Upraviť formulár',
+       'editer_nouveau' => 'Nový formulár',
+       'editer_redirige_url' => 'Adresa presmerovania po potvrdení',
+       'editer_redirige_url_explication' => 'Nevypĺňajte, ak chcete zostať na rovnakej stránke',
+       'editer_titre' => 'Názov',
+       'erreur_autorisation' => 'Na úpravu formulárov na tejto stránke nemáte dostatočné práva.',
+       'erreur_base' => 'Počas ukladania sa vyskytla technická chyba.',
+       'erreur_generique' => 'V týchto poliach sú chyby, prosím, skontrolujte ich pred odoslaním.',
+       'erreur_identifiant' => 'Tento identifikátor sa už používa.',
+       'erreur_importer_forms' => 'Chyba počas nahrávania formulára Forms&Tables',
+       'erreur_importer_wcs' => 'Chyba počas nahrávania formulára W.C.S',
+       'erreur_importer_yaml' => 'Chyba počas nahrávania súboru YAML',
+       'erreur_inexistant' => 'Formulár neexistuje.',
+
+       // F
+       'formulaire_anonyme_explication' => 'Ce formulaire est anonyme ; c\'est à dire que l\'identité de l\'utilisateur n\'est pas enregistrée.', # NEW
+       'formulaires_aucun' => 'Momentálne tu nie je žiaden formulár.',
+       'formulaires_dupliquer' => 'Skopírovať formulár',
+       'formulaires_dupliquer_copie' => '(kópia)',
+       'formulaires_introduction' => 'Tu vytvoríte a nastavíte formuláre pre svoju stránku.',
+       'formulaires_nouveau' => 'Vytvoriť nový formulár',
+       'formulaires_supprimer' => 'Odstrániť formulár',
+       'formulaires_supprimer_confirmation' => 'Pozor, takto vymažete všetky výsledky. Určite chcete odstrániť tento formulár?',
+       'formulaires_tous' => 'Všetky formuláre',
+
+       // I
+       'identification_par_cookie' => 'Podľa cookie',
+       'identification_par_id_auteur' => 'Podľa identifikátora (id_auteur) prihláseného človeka',
+       'importer_formulaire' => 'Nahrať formulár',
+       'importer_formulaire_fichier_label' => 'Súbor, ktorý sa má nahrať',
+       'importer_formulaire_format_label' => 'Formát súboru',
+
+       // M
+       'modele_label_formulaire_formidable' => 'Aký formulár?',
+       'modele_nom_formulaire' => 'jeden formulár',
+
+       // N
+       'noisette_label_afficher_titre_formulaire' => 'Zobraziť nadpis formulára?',
+       'noisette_label_identifiant' => 'Formulár, ktorý sa má zobraziť:',
+       'noisette_nom_noisette_formulaire' => 'Formulár',
+
+       // R
+       'reponse_aucune' => 'Žiadna odpoveď',
+       'reponse_intro' => '@auteur@ vyplnil(a) formulár @formulaire@',
+       'reponse_numero' => 'Odpoveď číslo:',
+       'reponse_statut' => 'Táto odpoveď je:',
+       'reponse_supprimer' => 'Odstrániť túto odpoveď',
+       'reponse_supprimer_confirmation' => 'Určite chcete vymazať túto odpoveď?',
+       'reponse_une' => '1 odpoveď',
+       'reponses_analyse' => 'Analýza odpovedí',
+       'reponses_anonyme' => 'Anonym',
+       'reponses_auteur' => 'Používateľ',
+       'reponses_exporter' => 'Exportovať odpovede',
+       'reponses_ip' => 'IP adresa',
+       'reponses_liste' => 'Zoznam odpovedí',
+       'reponses_liste_prop' => 'Odpovede čakajúce na potvrdenie',
+       'reponses_liste_publie' => 'Všetky platné odpovede',
+       'reponses_nb' => '@nb@ odpovedí',
+       'reponses_voir_detail' => 'Zobraziť odpoveď',
+       'retour_aucun_traitement' => 'Vaša odpoveď bola odoslaná, ale k tomuto formuláru nebola definovaná žiadna funkcia. Nič neurobí. :-)',
+
+       // S
+       'sans_reponses' => 'Neriešiteľný',
+
+       // T
+       'titre_cadre_raccourcis' => 'Skratky',
+       'traitements_actives' => 'Aktívne spracovanie',
+       'traitements_aide_memoire' => 'Pomocná pamäť:',
+       'traitements_avertissement_creation' => 'Zmeny polí formulára boli úspešne uložené. Teraz môžete určiť, aké funkcie sa použijú pri spracúvaní formulára.',
+       'traitements_avertissement_modification' => 'Zmeny v poliach formulára boli úspešne uložené. <strong>Niektoré funkcie možno budú musieť byť kvôli ním prestavené.</strong>',
+       'traitements_champ_aucun' => 'Žiadne',
+       'traiter_email_description' => 'Výstup z formulára odošle na e-mailové adresy príjemcov.',
+       'traiter_email_horodatage' => 'Formulár "@formulaire@" odoslaný @date@ o @heure@.',
+       'traiter_email_message_erreur' => 'Pri odosielaní e-mailu sa vyskytla chyba.',
+       'traiter_email_message_ok' => 'Vaša správa bola odoslaná.',
+       'traiter_email_option_activer_accuse_label' => 'Potvrdenie o prijatí správy',
+       'traiter_email_option_activer_accuse_label_case' => 'Poslať e-mail aj na adresu odosielateľa so žiadosťou o potvrdenie.',
+       'traiter_email_option_destinataires_explication' => 'Vyberte si pole, v ktorom budú príjemcovia správy.',
+       'traiter_email_option_destinataires_label' => 'Príjemcovia',
+       'traiter_email_option_destinataires_plus_explication' => 'Zoznam adries oddelený čiarkami.',
+       'traiter_email_option_destinataires_plus_label' => 'Ďalší príjemcovia',
+       'traiter_email_option_envoyeur_courriel_explication' => 'Vyberte si pole, ktoré bude obsahovať e-mailovú adresu odosielateľa.',
+       'traiter_email_option_envoyeur_courriel_label' => 'E-mail odosielateľa',
+       'traiter_email_option_envoyeur_nom_explication' => 'Vytvorte názov pomocou @raccourcis@ (prečítajte si pomocníka). Ak neurobíte nič, bude tým názvom názov stránky.',
+       'traiter_email_option_envoyeur_nom_label' => 'Meno odosielateľa',
+       'traiter_email_option_sujet_accuse_label' => 'Predmet potvrdenia o prijatí',
+       'traiter_email_option_sujet_explication' => 'Vytvorte predmet pomocou @raccourcis@. Ak neurobíte nič, predmet bude vytvorený automaticky.',
+       'traiter_email_option_sujet_label' => 'Predmet správy',
+       'traiter_email_option_vrai_envoyeur_explication' => 'Niektoré servery SMTP neumožňujú používať ľubovoľný e-mail pre pole "From" (Od koho). Z tohto dôvodu Formidable podľa predvolených nastavení vkladá e-mail odosielateľa do poľa "Reply-To". Ak chcete, aby bol vložený do poľa "From", zaškrtnite túto možnosť tu.',
+       'traiter_email_option_vrai_envoyeur_label' => 'Vložiť e-mail odosielateľa do poľa "From" (= "Od koho")',
+       'traiter_email_page' => '<a href="@url@">Z tejto stránky.</a>',
+       'traiter_email_sujet' => '@nom@ vám napísal(a).',
+       'traiter_email_sujet_accuse' => 'Ďakujeme vám za odpoveď.',
+       'traiter_email_titre' => 'Poslať e-mailom',
+       'traiter_email_url_enregistrement' => 'Riadiť odpovede môžete <a href="@url@">na tejto stránke.</a>',
+       'traiter_enregistrement_description' => 'Uloží výsledky z formulára do databázy',
+       'traiter_enregistrement_erreur_base' => 'Počas ukladania do databázy sa vyskytla technická chyba',
+       'traiter_enregistrement_erreur_deja_repondu' => 'Tento formulár ste už vyplnili.',
+       'traiter_enregistrement_erreur_edition_reponse_inexistante' => 'Odpoveď, ktorú chcete upraviť, sa nedá nájsť.',
+       'traiter_enregistrement_option_anonymiser_explication' => 'Urobte výsledky anonymnej forme (nevedú trasovanie identifikátor respondentov).', # MODIF
+       'traiter_enregistrement_option_anonymiser_label' => 'Anonymizované podobe',
+       'traiter_enregistrement_option_anonymiser_variable_explication' => 'Čo systémová premenná slúži na výpočet jednej hodnoty pre každého autora, bez toho, aby odhalil svoju identitu.',
+       'traiter_enregistrement_option_anonymiser_variable_label' => 'Premenná, z ktorých anonymizujú formulár',
+       'traiter_enregistrement_option_auteur' => 'Utiliser les auteurs pour les formulaires', # NEW
+       'traiter_enregistrement_option_auteur_explication' => 'Attribuer un ou plusieurs auteurs à un formulaire. Si cette option est activée, seuls les auteurs d\'un formulaire pourront accéder à leurs données.', # NEW
+       'traiter_enregistrement_option_choix_select_label' => 'Vyberte premennú, ktorá z dostupnej',
+       'traiter_enregistrement_option_identification_explication' => 'Ak sa odpovede dajú upraviť, aký spôsob sa použije ako prvý, aby sa zistilo, či sa odpoveď menila?',
+       'traiter_enregistrement_option_identification_label' => 'Identifikácia',
+       'traiter_enregistrement_option_moderation_label' => 'Kontrola',
+       'traiter_enregistrement_option_modifiable_explication' => 'Môžu návštevníci potom upraviť svoje odpovede?',
+       'traiter_enregistrement_option_modifiable_label' => 'Odpovede, ktoré sa dajú upraviť',
+       'traiter_enregistrement_option_multiple_explication' => 'Môže ten istý človek odpovedať na formulár viackrát?',
+       'traiter_enregistrement_option_multiple_label' => 'Duplicitné odpovede',
+       'traiter_enregistrement_titre' => 'Uložiť výsledky',
+
+       // V
+       'voir_exporter' => 'Exportovať formulár',
+       'voir_numero' => 'Formulár číslo:',
+       'voir_reponses' => 'Zobraziť odpovede',
+       'voir_traitements' => 'Funkcie'
+);
+
+?>
diff --git a/www/plugins/formidable_1_0/lang/formulaire_fr.php b/www/plugins/formidable_1_0/lang/formulaire_fr.php
new file mode 100644 (file)
index 0000000..f6663cd
--- /dev/null
@@ -0,0 +1,18 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/formidable/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+       // I
+       'icone_creer_formulaire' => 'Créer un nouveau formulaire',
+
+       // M
+       'modifier_formulaire' => 'Modifier ce formulaire',
+
+       // T
+       'titre_formulaires' => 'Formulaires',
+       'titre_logo_formulaire' => 'Logo de ce formulaire',
+       'titre_formulaire' => 'Formulaire',
+
+);
diff --git a/www/plugins/formidable_1_0/lang/formulaires_reponse_fr.php b/www/plugins/formidable_1_0/lang/formulaires_reponse_fr.php
new file mode 100644 (file)
index 0000000..108f4e2
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/formidable/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+       // I
+       'icone_creer_formulaire' => 'Créer une nouvelle réponse de formulaire',
+
+       // M
+       'modifier_formulaire' => 'Modifier cette réponse de formulaire',
+
+       'changer_statut' => 'Cette réponse de formulaire est :',
+
+       // F
+       'formulaires_reponse_numero' => 'Réponse de formulaire n°@nb@',
+
+       // R
+       'reponses_donnees' => 'Réponses données :',
+
+       // T
+       'titre_formulaires_reponses' => 'Réponses de formulaire',
+       'titre_logo_formulaires_reponse' => 'Logo de cette réponse de formulaire',
+       'titre_formulaires_reponse' => 'Réponse de formulaire',
+
+
+);
diff --git a/www/plugins/formidable_1_0/lang/paquet-formidable_fr.php b/www/plugins/formidable_1_0/lang/paquet-formidable_fr.php
new file mode 100644 (file)
index 0000000..9728239
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+// Ceci est un fichier langue de SPIP -- This is a SPIP language file
+
+///  Fichier produit par PlugOnet
+// Module: paquet-formidable
+// Langue: fr
+// Date: 05-09-2012 18:51:15
+// Items: 2
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+// F
+       'formidable_description' => 'Création de formulaires avec une interface graphique et configuration des traitements associés (envoyer par courriel, enregistrer les réponses, etc).',
+       'formidable_slogan' => 'Générateur de formulaires',
+);
+?>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/modeles/formulaire_aide_memoire.html b/www/plugins/formidable_1_0/modeles/formulaire_aide_memoire.html
new file mode 100644 (file)
index 0000000..c1747f7
--- /dev/null
@@ -0,0 +1,17 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+       <strong><:formidable:traitements_aide_memoire:></strong>
+       <dl>
+               <dt>@nom_site_spip@</dt>
+               <dd><:info_nom_site:></dd>
+       </dl>
+       
+       <BOUCLE_champs(POUR){tableau #SAISIES*|unserialize|saisies_lister_par_nom{0}}>
+       [(#SET{label, [(#VALEUR|table_valeur{options}|table_valeur{label})]})]
+       [(#SET{label_case, [(#VALEUR|table_valeur{options}|table_valeur{label_case})]})]
+       
+       <dl>
+               <dt>@#CLE@</dt>
+               [<dd>(#GET{label}|sinon{#GET{label_case}})</dd>]
+       </dl>
+       </BOUCLE_champs>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/modeles/formulaire_analyse.html b/www/plugins/formidable_1_0/modeles/formulaire_analyse.html
new file mode 100644 (file)
index 0000000..fb8050e
--- /dev/null
@@ -0,0 +1,65 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<div class='formidable_analyse'>
+[(#REM) On fait un tableau qui contient toutes les réponses, classées par champ ]
+#SET{valeurs,#ARRAY}
+#SET{reponses_total,0}
+<BOUCLE_reponses(FORMULAIRES_REPONSES){id_formulaire}>
+<BOUCLE_champs(FORMULAIRES_REPONSES_CHAMPS){id_formulaires_reponse}{nom ?= #ENV{nom}}>
+#SET_MERGE{liste_valeurs, #GET{valeurs}|table_valeur{#NOM}|sinon{#ARRAY}, #ARRAY{0,#VALEUR|tenter_unserialize}}
+#SET_MERGE{valeurs, #ARRAY{#NOM,#GET{liste_valeurs}}}
+</BOUCLE_champs>
+</BOUCLE_reponses>
+#SET{reponses_total,#TOTAL_BOUCLE}
+<strong class='nombre_reponse'>
+       [(#TOTAL_BOUCLE|singulier_ou_pluriel{formidable:reponse_une,formidable:reponses_nb})]
+</strong>
+</B_reponses>
+       <strong class='nombre_reponse'><:formidable:reponse_aucune:></strong>
+<//B_reponses>
+
+<BOUCLE_saisies(POUR){tableau #SAISIES|unserialize|saisies_lister_par_nom}>
+[(#VAL{saisie}|array_key_exists{#VALEUR}|oui)
+  [(#CLE|=={#ENV{nom,#CLE}}|oui)
+       [(#VALEUR|formidable_analyser_saisie{#GET{valeurs}, #GET{reponses_total}})]
+  ]
+]
+</BOUCLE_saisies>
+
+</div><!-- formidable_analyse -->
+<script type='text/javascript'>
+(function($){
+$(document).ready(function(){
+       /* Récupérer tous les tableaux d'analyse non décorés */
+       $('.formidable_analyse table:not(.stat_done)').each(function() {
+               $(this).addClass('stat_done');
+               /* Le tableau contient le nombre total d'élément. On parcours chaque valeur */
+               $nbtotal = $(this).data('nombre');
+               $(this).find('td.stat').each(function(){
+                       $val = $(this).html();
+                       /* Certaines valeurs sont a ignorer (les moyennes) */
+                       $ignore = $(this).is('.ignore');
+                       if (!$ignore) {
+                               /* Calcul du pourcentage */
+                               $taux = Math.round($val/$nbtotal*100);
+                               /* On affiche le nombre de réponses */
+                               $reponses = $(this).attr('title');
+                               if (!parseInt($val) || ($reponses === undefined)) {
+                                       $reponses = '';
+                               } else {
+                                       $reponses = "<small> - " + $reponses + "</small>";
+                               }
+                               $text = "\
+                               <div class='[(#CONFIG{formidable/analyse/classe}) ]progress-bar'>\
+                                       <span></span><strong>" + $taux + "%" + $reponses + "</strong>\
+                               </div>";
+                               $(this).html($text).find('span').width($taux + '%');
+                       }
+               });
+       });
+});
+})(jQuery);
+</script>
+<style type='text/css'>
+<INCLURE{fond=css/formidable_analyse.css} />
+</style>
+</BOUCLE_formulaire>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/modeles/formulaire_formidable.yaml b/www/plugins/formidable_1_0/modeles/formulaire_formidable.yaml
new file mode 100644 (file)
index 0000000..79dc4e9
--- /dev/null
@@ -0,0 +1,20 @@
+nom: '<:formidable:modele_nom_formulaire:>'
+logo: 'images/formulaire-24.png'
+icone_barre: 'formulaire.png'
+parametres:
+  -
+    saisie: 'hidden'
+    options:
+      nom: 'modele'
+      defaut: 'formulaire'
+  -
+    saisie: 'hidden'
+    options:
+      nom: 'variante'
+      defaut: 'formidable'
+  -
+    saisie: 'formulaire_formidable'
+    options:
+      nom: 'id'
+      label: '<:formidable:modele_label_formulaire_formidable:>'
+      cacher_option_intro: 'oui'
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/modeles/formulaires_reponse.html b/www/plugins/formidable_1_0/modeles/formulaires_reponse.html
new file mode 100644 (file)
index 0000000..02d78a0
--- /dev/null
@@ -0,0 +1,12 @@
+<BOUCLE_reponse(FORMULAIRES_REPONSES){tout}{id_formulaires_reponse}>
+
+#SET{valeurs,#ARRAY}
+<BOUCLE_champs(FORMULAIRES_REPONSES_CHAMPS){id_formulaires_reponse}>
+#SET_MERGE{valeurs,#ARRAY{#NOM,#VALEUR|tenter_unserialize}}
+</BOUCLE_champs>
+
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+#VOIR_SAISIES{(#SAISIES|unserialize), #GET{valeurs}}
+</BOUCLE_formulaire>
+
+</BOUCLE_reponse>
diff --git a/www/plugins/formidable_1_0/noisettes/formulaire_formidable.html b/www/plugins/formidable_1_0/noisettes/formulaire_formidable.html
new file mode 100644 (file)
index 0000000..95f7a4c
--- /dev/null
@@ -0,0 +1,2 @@
+<BOUCLE_formulaire(FORMULAIRES){identifiant}{0,1}>[(#ENV{afficher_titre_formulaire}|oui)[<h2 class="h2">(#TITRE|typo)</h2>]]</BOUCLE_formulaire>\r
+<div class="ajax">#FORMULAIRE_FORMIDABLE{#ENV{identifiant}}</div>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/noisettes/formulaire_formidable.yaml b/www/plugins/formidable_1_0/noisettes/formulaire_formidable.yaml
new file mode 100644 (file)
index 0000000..dd6679c
--- /dev/null
@@ -0,0 +1,15 @@
+nom: '<:formidable:noisette_nom_noisette_formulaire:>'\r
+icon: 'images/formulaire-24.png'\r
+parametres:\r
+  -\r
+    saisie: 'formulaire_formidable'\r
+    options:\r
+      nom: 'identifiant'\r
+      label: '<:formidable:noisette_label_identifiant:>'\r
+      cacher_option_intro: 'oui'\r
+  -\r
+    saisie: 'oui_non'\r
+    options:\r
+      nom: 'afficher_titre_formulaire'\r
+      label: '<:formidable:noisette_label_afficher_titre_formulaire:>'\r
+      defaut: ''
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/notifications/formulaire_accuse.html b/www/plugins/formidable_1_0/notifications/formulaire_accuse.html
new file mode 100644 (file)
index 0000000..559a130
--- /dev/null
@@ -0,0 +1,7 @@
+
+[(#ENV*{message_retour}|propre)]
+
+#VOIR_SAISIES{#ENV*{saisies}, #ENV*{valeurs}}
+
+---
+<p><:envoi_via_le_site:> <a href="#URL_SITE_SPIP">#NOM_SITE_SPIP</a></p>
diff --git a/www/plugins/formidable_1_0/notifications/formulaire_email.html b/www/plugins/formidable_1_0/notifications/formulaire_email.html
new file mode 100644 (file)
index 0000000..9f3b5e9
--- /dev/null
@@ -0,0 +1,18 @@
+
+<p>
+       #SET{date, #VAL{d/m/Y}|date}
+       #SET{heure, #VAL{H:i:s}|date}
+       <:formidable:traiter_email_horodatage{formulaire=#ENV*{titre}, date=#GET{date}, heure=#GET{heure}}:>
+       <br/>
+       #SET{url, #SELF{&,true}|url_absolue}
+       <:formidable:traiter_email_page{url=#GET{url}}:>
+</p>
+
+#VOIR_SAISIES{#ENV*{saisies}, #ENV*{valeurs}}
+
+---
+<p><:envoi_via_le_site:> <a href="#URL_SITE_SPIP">#NOM_SITE_SPIP</a></p>
+[(#ENV*{traitements}|table_valeur{enregistrement}|oui)
+#SET{url, #URL_ECRIRE{formulaires_reponses}|parametre_url{id_formulaire, #ENV{id_formulaire}}|url_absolue}
+<p><:formidable:traiter_email_url_enregistrement{url=#GET{url}}:></p>
+]
diff --git a/www/plugins/formidable_1_0/paquet.xml b/www/plugins/formidable_1_0/paquet.xml
new file mode 100644 (file)
index 0000000..9dabcf1
--- /dev/null
@@ -0,0 +1,35 @@
+<paquet
+       prefix="formidable"
+       categorie="communication"
+       version="1.3.6"
+       etat="dev"
+       compatibilite="[3.0.0-dev;3.0.99]"
+       logo="images/formidable-64.png"
+       schema="0.5.1"
+       documentation="http://www.spip-contrib.net/Formidable-le-generateur-de"
+>
+
+       <nom>Formidable</nom>
+       <!-- Générateur de formulaires -->
+
+       <auteur>RastaPopoulos</auteur>
+       <auteur lien="http://www.ldd.fr">Les Développements Durables</auteur>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>
+
+       <pipeline nom="autoriser" inclure="formidable_autorisations.php" />
+       <pipeline nom="declarer_tables_objets_sql" inclure="base/formidable_tables.php" />
+       <pipeline nom="declarer_tables_principales" inclure="base/formidable_tables.php" />
+       <pipeline nom="declarer_tables_auxiliaires" inclure="base/formidable_tables.php" />
+       <pipeline nom="declarer_tables_interfaces" inclure="base/formidable_tables.php" />
+
+       <pipeline nom="optimiser_base_disparus" inclure="formidable_pipelines.php" />
+
+       <necessite nom="spip_bonux" compatibilite="[1.9.3;[" />
+       <necessite nom="saisies" compatibilite="[1.10.1;[" />
+       <necessite nom="verifier" compatibilite="[0.1;[" />
+       <necessite nom="yaml" compatibilite="[1.1;[" />
+       <necessite nom="facteur" compatibilite="[1.5.3;[" />
+
+       <menu nom="formulaires" titre="formidable:bouton_formulaires" parent="menu_edition" icone="images/formulaire-16.png" />
+</paquet>
diff --git a/www/plugins/formidable_1_0/prive/objets/contenu/formulaire.html b/www/plugins/formidable_1_0/prive/objets/contenu/formulaire.html
new file mode 100644 (file)
index 0000000..e22434c
--- /dev/null
@@ -0,0 +1,6 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<div class="champ contenu_descriptif[ (#DESCRIPTIF*|strlen|?{'',vide})]">
+       <div class='label'><:info_descriptif:></div>
+       <div dir='#LANG_DIR' class='#EDIT{descriptif} descriptif'>[(#DESCRIPTIF|image_reduire{500,0})]</div>
+</div>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/objets/contenu/formulaires_reponse.html b/www/plugins/formidable_1_0/prive/objets/contenu/formulaires_reponse.html
new file mode 100644 (file)
index 0000000..30bccf4
--- /dev/null
@@ -0,0 +1,27 @@
+<BOUCLE_formulaires_reponse(FORMULAIRES_REPONSES){tout}{id_formulaires_reponse}>
+<div class="champ contenu_auteur[ (#ID_AUTEUR*|strlen|?{'',vide})]">
+       <div class='label'><:auteur:></div>
+       <div dir='#LANG_DIR'>
+               [(#ID_AUTEUR|>{0}|oui)
+                       <a href="[(#INFO_URL{auteur,#ID_AUTEUR})]">[(#INFO_TITRE{auteur,#ID_AUTEUR})]</a>
+               ]
+               [(#ID_AUTEUR|>{0}|non)
+                       <:formidable:reponses_anonyme:>
+               ]
+       </div>
+</div>
+<div class="champ contenu_formulaire[ (#ID_FORMULAIRE*|strlen|?{'',vide})]">
+       <div class='label'><:formulaire:titre_formulaire:></div>
+       <div dir='#LANG_DIR'>
+               <a href="[(#URL_ECRIRE{formulaire,id_formulaire=#ID_FORMULAIRE})]">
+                       [(#INFO_TITRE{formulaire,#ID_FORMULAIRE})]
+               </a>
+       </div>
+</div>
+<div class="champ contenu_date[ (#DATE*|strlen|?{'',vide})]">
+       <div class='label'><:date:></div>
+       <div dir='#LANG_DIR'>
+               [(#DATE|affdate_jourcourt|concat{#DATE|affdate{", H:i"}})]
+       </div>
+</div>
+</BOUCLE_formulaires_reponse>
diff --git a/www/plugins/formidable_1_0/prive/objets/infos/formulaire.html b/www/plugins/formidable_1_0/prive/objets/infos/formulaire.html
new file mode 100644 (file)
index 0000000..59afec0
--- /dev/null
@@ -0,0 +1,6 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire=#ENV{id}}{statut?}>
+<div class='infos'>
+<div class='numero'><:formidable:voir_numero:><p>#ID_FORMULAIRE</p></div>
+
+</div>
+</BOUCLE_formulaire>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/prive/objets/infos/formulaires_reponse.html b/www/plugins/formidable_1_0/prive/objets/infos/formulaires_reponse.html
new file mode 100644 (file)
index 0000000..0490842
--- /dev/null
@@ -0,0 +1,8 @@
+<BOUCLE_formulaires_reponse(FORMULAIRES_REPONSES){id_formulaires_reponse=#ENV{id}}{statut?}>
+<div class='infos'>
+<div class='numero'><:formidable:reponse_numero:><p>#ID_FORMULAIRES_REPONSE</p></div>
+
+[(#FORMULAIRE_INSTITUER_OBJET{formulaires_reponses,#ID_FORMULAIRES_REPONSE})]
+
+</div>
+</BOUCLE_formulaires_reponse>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/prive/objets/liste/formulaires.html b/www/plugins/formidable_1_0/prive/objets/liste/formulaires.html
new file mode 100644 (file)
index 0000000..f2a8098
--- /dev/null
@@ -0,0 +1,45 @@
+[(#SET{defaut_tri,#ARRAY{
+       date,-1,
+       titre,1,
+       id_formulaire,1
+}})
+]<B_formulaires>
+#ANCRE_PAGINATION
+<div class="liste-objets formulaires">
+<table class="spip liste">
+[<caption><strong class="caption">(#ENV*{titre})</strong></caption>]
+       <thead>
+               <tr class="first_row">
+                       <th class="id_formulaire id" scope='col'>[(#TRI{id_formulaire,<span>#</span>,ajax})]</th>
+                       <th class="titre" scope='col'>[(#TRI{titre,<:formidable:editer_titre:>,ajax})]</th>
+                       <th class="identifiant" scope='col'>[(#TRI{identifiant,<:formidable:editer_identifiant:>,ajax})]</th>
+                       <th class="action" scope='col'></th>
+               </tr>
+       </thead>
+       <tbody>
+       <BOUCLE_formulaires(FORMULAIRES){statut?}{tri #ENV{order,titre},#GET{defaut_tri}}{pagination #ENV{nb,10}}>
+               <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})][ (#EXPOSE|unique)]">
+                       <td class="id_formulaire"><:info_numero_abbreviation:>#ID_FORMULAIRE</td>
+                       <td class="titre"><a href="[(#ID_FORMULAIRE|generer_url_entite{formulaire})]">#TITRE</a></td>
+                       <td class="identifiant">#IDENTIFIANT</td>
+                       <td class="action">
+                               [(#AUTORISER{editer, formulaire}|oui)
+                                       [(#BOUTON_ACTION{[(#CHEMIN_IMAGE{formulaire-dupliquer-24.png}
+                                               |balise_img{<:formidable:formulaires_dupliquer:>})],
+                                               #URL_ACTION_AUTEUR{dupliquer_formulaire, #ID_FORMULAIRE},link})]
+                               ]
+                               [(#AUTORISER{editer, formulaire, #ID_FORMULAIRE}|oui)
+                                       [(#BOUTON_ACTION{[(#CHEMIN_IMAGE{formulaire-supprimer-24.png}
+                                               |balise_img{<:formidable:formulaires_supprimer:>})],
+                                               #URL_ACTION_AUTEUR{supprimer_formulaire, #ID_FORMULAIRE},link,<:formidable:formulaires_supprimer_confirmation:>})]
+                               ]
+                       </td>
+               </tr>
+       </BOUCLE_formulaires>
+       </tbody>
+</table>
+[<p class="pagination">(#PAGINATION{prive})</p>]
+</div>
+</B_formulaires>[
+<div class="liste-objets formulaires"><strong class="caption">(#ENV*{sinon,<:formidable:formulaires_aucun:>})</strong></div>
+]<//B_formulaires>
diff --git a/www/plugins/formidable_1_0/prive/objets/liste/formulaires_reponses.html b/www/plugins/formidable_1_0/prive/objets/liste/formulaires_reponses.html
new file mode 100644 (file)
index 0000000..9d310c0
--- /dev/null
@@ -0,0 +1,48 @@
+[(#SET{defaut_tri,#ARRAY{
+       date,-1,
+       titre,1,
+       id_formulaires_reponse,1
+}})
+]<B_reponses>
+[(#BOITE_OUVRIR{'','simple'})]
+#ANCRE_PAGINATION
+<div class="liste-objets formulaires_reponses">
+<table class="liste spip">
+[<caption><strong class="caption">(#ENV*{titre})</strong></caption>]
+       <thead>
+               <tr class="first_row">
+                       <th class="statut" scope='col'>[(#TRI{statut,<span>#</span>,ajax})]</th>
+                       <th class="date" scope='col'>[(#TRI{date,<:date:>,ajax})]</th>
+                       <th class="auteur" scope='col'>[(#TRI{id_auteur,<:formidable:reponses_auteur:>,ajax})]</th>
+                       <th class="ip" scope='col'>[(#TRI{ip,<:formidable:reponses_ip:>,ajax})]</th>
+                       <th class="action" scope='col'></th>
+               </tr>
+       </thead>
+       <tbody>
+       <BOUCLE_reponses(FORMULAIRES_REPONSES){id_formulaire}{id_auteur?}{statut?}{tri #ENV{order,date},#GET{defaut_tri}}{pagination #ENV{nb,10}}>
+               <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
+                       <td class="statut">[(#ID_FORMULAIRES_REPONSE|puce_changement_statut{#STATUT, #ID_FORMULAIRE, formulaires_reponse})]</td>
+                       <td class="date">[(#DATE|affdate_jourcourt|concat{#DATE|affdate{", H:i"}})]</td>
+                       <td class="auteur">
+                               <BOUCLE_auteur(AUTEURS){id_auteur}{tout}>
+                               <a href="[(#ID_AUTEUR|generer_url_entite{auteur})]">#NOM</a>
+                               </BOUCLE_auteur>
+                               <:formidable:reponses_anonyme:>
+                               <//B_auteur>
+                       </td>
+                       <td class="ip">#IP</td>
+                       <td class="action">
+                               <a href="[(#URL_ECRIRE{formulaires_reponse}|parametre_url{id_formulaires_reponse,#ID_FORMULAIRES_REPONSE})]" title="<:formidable:reponses_voir_detail:>">
+                                       <img src="#CHEMIN{images/formulaire-reponse-24.png}" alt="<:formidable:reponses_voir_detail:>" />
+                               </a>
+                       </td>
+               </tr>
+       </BOUCLE_reponses>
+       </tbody>
+</table>
+[<p class="pagination">(#PAGINATION{prive})</p>]
+</div>
+#BOITE_FERMER
+</B_reponses>[
+<div class="liste-objets formulaires_reponses"><strong class="caption">(#ENV*{sinon,''})</strong></div>
+]<//B_reponses>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/contenu/configurer_formidable.html b/www/plugins/formidable_1_0/prive/squelettes/contenu/configurer_formidable.html
new file mode 100644 (file)
index 0000000..df8aa01
--- /dev/null
@@ -0,0 +1,7 @@
+[(#AUTORISER{configurer,_fsondage}|sinon_interdire_acces)]
+
+<h1 class="grostitre"><:formidable:cfg_titre_page_configurer_formidable:></h1>
+
+<div class="ajax">
+       #FORMULAIRE_CONFIGURER_FORMIDABLE_ANALYSE
+</div>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaire.html b/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaire.html
new file mode 100644 (file)
index 0000000..6a19dc7
--- /dev/null
@@ -0,0 +1,35 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>\r
+[(#BOITE_OUVRIR{\r
+       [(#AUTORISER{editer, formulaire, #ID_FORMULAIRE}|oui)\r
+               [(#URL_ECRIRE{formulaire_edit,id_formulaire=#ID_FORMULAIRE}\r
+                       |icone_verticale{<:formidable:editer_modifier_formulaire:>,formulaire,formulaire-editer-24,right})]\r
+       ]\r
+       [<h1>(#TITRE|sinon{<:info_sans_titre:>})[(#CHEMIN_IMAGE{formulaire-24.png}|balise_img{formulaire,cadre-icone})]</h1>]\r
+,simple fiche_objet})]\r
+\r
+\r
+<!--affiche_milieu-->\r
+\r
+<div id="wysiwyg">\r
+<INCLURE{fond=prive/objets/contenu/formulaire,id=#ID_FORMULAIRE,id_formulaire=#ID_FORMULAIRE,virtuel=oui,ajax=wysiwyg,wysiwyg=1}>\r
+</div>\r
+\r
+       #SET{traitements_disponibles, #VAL|traitements_lister_disponibles}\r
+       [(#BOITE_OUVRIR{#CHEMIN_IMAGE{formulaire-config-traitements-24.png}\r
+               |balise_img{'',cadre-icone}\r
+               |concat{<:formidable:traitements_actives:>},'simple traitements'})]\r
+       <B_traitements>\r
+               <ul class='spip'>\r
+                       <BOUCLE_traitements(POUR){tableau #TRAITEMENTS|unserialize|sinon{#ARRAY}}>\r
+                               <li>[(#GET{traitements_disponibles}|table_valeur{#CLE}|table_valeur{titre})]</li>\r
+                       </BOUCLE_traitements>\r
+               </ul>\r
+       </B_traitements>\r
+               <p><:formidable:aucun_traitement:></p>\r
+       <//B_traitements>\r
+       #BOITE_FERMER\r
+\r
+       #FORMULAIRE_FORMIDABLE{#ID_FORMULAIRE}\r
+\r
+#BOITE_FERMER\r
+</BOUCLE_formulaire>\r
diff --git a/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaire_edit.html b/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaire_edit.html
new file mode 100644 (file)
index 0000000..75a6ddb
--- /dev/null
@@ -0,0 +1,41 @@
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{editer, formulaire, #VAL{id_formulaire}|_request|sinon{0}}}>
+[(#BOITE_OUVRIR{'','info'})]
+<script type="text/javascript">/*<![CDATA[*/
+if (window.jQuery){
+function debloquer_prive(){ jQuery('input[required], textarea[required], select[required]').removeAttr('required'); }
+jQuery('document').ready(debloquer_prive);
+onAjaxLoad(debloquer_prive);
+}
+/*]]>*/</script>
+               <BOUCLE_formulaire(FORMULAIRES){id_formulaire=#VAL{id_formulaire}|_request}>
+                       [(#URL_ECRIRE{formulaire}|parametre_url{id_formulaire,#ID_FORMULAIRE}|icone_verticale{<:retour:>,formulaire,formulaire-24,left})]
+
+                       <h4><:formidable:editer_modifier_formulaire:></h4>
+                       <h1>#TITRE</h1>
+                       
+                       #SET{configurer,#ENV{configurer}|in_array{#ARRAY{0,formulaire,1,champs,2,traitements,3,auteurs}}|?{#ENV{configurer},champs}}
+               </BOUCLE_formulaire>
+               [(#URL_ECRIRE{formulaires}|icone_verticale{<:retour:>,formulaire,formulaire-24,left})]
+                       
+                       <:formidable:editer_modifier_formulaire:>
+                       <h1>
+                               [(#ENV{nouveau}|=={oui}|?{<:formidable:editer_nouveau:>,#VAL{id_menu}|_request})]
+                       </h1>
+                       
+                       #SET{configurer,formulaire}
+               <//B_formulaire>
+       
+       [(#GET{configurer}|=={formulaire}|oui)
+               #FORMULAIRE_EDITER_FORMULAIRE{#VAL{id_formulaire}|_request|sinon{0}, #VAL{nouveau}|_request|sinon{''}}
+       ]
+       [(#GET{configurer}|=={auteurs}|oui)
+               #FORMULAIRE_EDITER_LIENS{formulaires,#VAL{id_formulaire}|_request|sinon{0},auteurs}
+       ]
+       [(#GET{configurer}|=={champs}|oui)
+               #FORMULAIRE_EDITER_FORMULAIRE_CHAMPS{#ENV{id_formulaire}}
+       ]
+       [(#GET{configurer}|=={traitements}|oui)
+               #FORMULAIRE_EDITER_FORMULAIRE_TRAITEMENTS{#ENV{id_formulaire}}
+       ]
+#BOITE_FERMER
+</BOUCLE_autoriser>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires.html b/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires.html
new file mode 100644 (file)
index 0000000..f655ed3
--- /dev/null
@@ -0,0 +1,13 @@
+[(#BOITE_OUVRIR{
+       <h1><:formidable:bouton_formulaires:></h1>
+       <p><:formidable:formulaires_introduction:></p>
+})]
+#BOITE_FERMER
+
+<INCLURE{fond=prive/objets/liste/formulaires, titre=<:formulaire:titre_formulaires:>, ajax} />
+
+[(#AUTORISER{editer, formulaire}|oui)
+[(#URL_ECRIRE{formulaire_edit}
+       |parametre_url{nouveau,oui}
+       |icone_verticale{<:formulaire:icone_creer_formulaire:>,formulaire,formulaire-nouveau-48,center})]
+]
diff --git a/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_analyse.html b/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_analyse.html
new file mode 100644 (file)
index 0000000..bf48ec5
--- /dev/null
@@ -0,0 +1,24 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse, #ID_FORMULAIRE}}>
+[(#BOITE_OUVRIR{'','simple'})]
+        [(#URL_ECRIRE{formulaire}|parametre_url{id_formulaire,#ID_FORMULAIRE}|icone_verticale{<:retour:>,formulaire,formulaire-24,left})]
+
+       [<h4><:formidable:reponses_analyse:></h4>
+       <h1>(#TITRE|sinon{<:info_sans_titre:>})</h1>]
+
+       [(#BOITE_OUVRIR{'','simple'})]  
+       <BOUCLE_reponses(FORMULAIRES_REPONSES){id_formulaire}>
+       </BOUCLE_reponses>
+       <strong>[(#_reponses:TOTAL_BOUCLE
+               |singulier_ou_pluriel{formidable:analyse_une_reponse_total,formidable:analyse_nb_reponses_total})]</strong>
+       </B_reponses>
+       <strong><:formidable:analyse_zero_reponse_total:></strong>
+       <//B_reponses>
+       #BOITE_FERMER
+#BOITE_FERMER
+
+[(#BOITE_OUVRIR{'','simple'})]
+#INCLURE{fond=modeles/formulaire_analyse,id_formulaire}
+#BOITE_FERMER
+</BOUCLE_autoriser>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_reponse.html b/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_reponse.html
new file mode 100644 (file)
index 0000000..0f8441b
--- /dev/null
@@ -0,0 +1,24 @@
+<BOUCLE_formulaires_reponse(FORMULAIRES_REPONSES){tout}{id_formulaires_reponse}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse, #ID_FORMULAIRE}}>
+[(#BOITE_OUVRIR{
+       <h1><:formulaires_reponse:formulaires_reponse_numero{nb=#ID_FORMULAIRES_REPONSE}:></h1>
+,simple fiche_objet})]
+
+
+<!--affiche_milieu-->
+
+<div id="wysiwyg">
+<INCLURE{fond=prive/objets/contenu/formulaires_reponse,
+       id=#ID_FORMULAIRES_REPONSE,
+       id_formulaires_reponse=#ID_FORMULAIRES_REPONSE,
+       virtuel=oui,ajax=wysiwyg,wysiwyg=1} />
+</div>
+
+<div class='nettoyeur'></div>
+[(#BOITE_OUVRIR{<h3><:formulaires_reponse:reponses_donnees:></h3>,reponses})]
+#INCLURE{fond=modeles/formulaires_reponse,id_formulaires_reponse}
+#BOITE_FERMER
+
+#BOITE_FERMER
+</BOUCLE_autoriser>
+</BOUCLE_formulaires_reponse>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_reponses.html b/www/plugins/formidable_1_0/prive/squelettes/contenu/formulaires_reponses.html
new file mode 100644 (file)
index 0000000..78210d5
--- /dev/null
@@ -0,0 +1,15 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse, #ID_FORMULAIRE}}>
+[(#BOITE_OUVRIR{'','simple'})]
+       [(#URL_ECRIRE{formulaire}|parametre_url{id_formulaire,#ID_FORMULAIRE}|icone_verticale{<:retour:>,formulaire,formulaire-24,left})]
+       
+       <h4><:formidable:voir_reponses:></h4>
+       <h1>#TITRE</h1>
+#BOITE_FERMER
+
+<INCLURE{fond=prive/objets/liste/formulaires_reponses}{id_formulaire}{statut=prop}{titre=<:formidable:reponses_liste_prop:>}{ajax}>
+
+<INCLURE{fond=prive/objets/liste/formulaires_reponses}{id_formulaire}{statut=publie}{titre=<:formidable:reponses_liste_publie:>}{ajax}>
+
+</BOUCLE_autoriser>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/extra/formulaire.html b/www/plugins/formidable_1_0/prive/squelettes/extra/formulaire.html
new file mode 100644 (file)
index 0000000..4407c02
--- /dev/null
@@ -0,0 +1,19 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<!--#extra-->
+[(#BOITE_OUVRIR{<:formidable:titre_cadre_raccourcis:>,'simple','section'})]
+       [(#AUTORISER{editer, formulaire}|oui)
+       [(#URL_ACTION_AUTEUR{dupliquer_formulaire, #ID_FORMULAIRE}|icone_horizontale{<:formidable:formulaires_dupliquer:>,formulaire,formulaire-dupliquer-24})]
+       ]
+       [(#AUTORISER{editer, formulaire, #ID_FORMULAIRE}|oui)
+       [(#URL_ACTION_AUTEUR{supprimer_formulaire, #ID_FORMULAIRE}|inserer_attribut{'onclick','return confirm("<:formidable:formulaires_supprimer_confirmation:>");'}
+       |icone_horizontale{<:formidable:formulaires_supprimer:>,formulaire,formulaire-supprimer-24})]
+       ]
+#BOITE_FERMER
+
+[(#BOITE_OUVRIR{<:formidable:voir_exporter:>,'simple','section'})]
+       <BOUCLE_exports(POUR){tableau #VAL|echanges_formulaire_lister_disponibles|table_valeur{exporter}}>
+       [(#URL_ACTION_AUTEUR{exporter_formulaire,#ID_FORMULAIRE-#CLE}|icone_horizontale{#CLE,formulaire,formulaire-exporter-24})]
+       </BOUCLE_exports>
+#BOITE_FERMER
+<!--/#extra-->
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/extra/formulaire_edit.html b/www/plugins/formidable_1_0/prive/squelettes/extra/formulaire_edit.html
new file mode 100644 (file)
index 0000000..959b0eb
--- /dev/null
@@ -0,0 +1,9 @@
+<BOUCLE_formulaire(FORMULAIRES) {id_formulaire}>
+<!--#extra-->
+[(#ENV{configurer}|=={traitements}|oui)
+[(#BOITE_OUVRIR{'','info'})]
+       #INCLURE{fond=modeles/formulaire_aide_memoire, id_formulaire=#ID_FORMULAIRE}
+#BOITE_FERMER
+]
+<!--/#extra-->
+</BOUCLE_formulaire>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/prive/squelettes/extra/formulaires_analyse.html b/www/plugins/formidable_1_0/prive/squelettes/extra/formulaires_analyse.html
new file mode 100755 (executable)
index 0000000..9810f75
--- /dev/null
@@ -0,0 +1,8 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_analyse}}>
+[(#BOITE_OUVRIR{<:formidable:titre_cadre_raccourcis:>,'info'})]
+[(#URL_ACTION_AUTEUR{exporter_analyse_reponses,#ID_FORMULAIRE}
+    |icone_horizontale{<:formidable:analyse_exporter:>,formulaire,formulaire-analyse-exporter-24,center})]
+#BOITE_FERMER
+</BOUCLE_autoriser>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/extra/formulaires_reponses.html b/www/plugins/formidable_1_0/prive/squelettes/extra/formulaires_reponses.html
new file mode 100644 (file)
index 0000000..eece13c
--- /dev/null
@@ -0,0 +1,8 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse}}>
+[(#BOITE_OUVRIR{<:formidable:titre_cadre_raccourcis:>,'info'})]
+[(#URL_ACTION_AUTEUR{exporter_formulaires_reponses,#ID_FORMULAIRE}
+       |icone_horizontale{<:formidable:reponses_exporter:>,formulaire,formulaire-reponses-exporter-24,center})]
+#BOITE_FERMER
+</BOUCLE_autoriser>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaire.html b/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaire.html
new file mode 100644 (file)
index 0000000..2b7798d
--- /dev/null
@@ -0,0 +1,5 @@
+<!-- hierarchie -->
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<a href="#URL_ECRIRE{formulaires}"><:formulaire:titre_formulaires:></a> &gt;
+<strong class="on">#TITRE</strong>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaire_edit.html b/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaire_edit.html
new file mode 100644 (file)
index 0000000..a41dfd9
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<a href="#URL_ECRIRE{formulaires}"><:formulaire:titre_formulaires:></a> &gt;
+<a href="[(#URL_ECRIRE{formulaire}|parametre_url{id_formulaire,#ID_FORMULAIRE})]">#TITRE</a> &gt;
+<strong class="on"><:formulaire:modifier_formulaire:></strong>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires.html b/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires.html
new file mode 100644 (file)
index 0000000..7fd040a
--- /dev/null
@@ -0,0 +1,2 @@
+<!-- hierarchie -->
+<strong class="on"><:formulaire:titre_formulaires:></strong>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_analyse.html b/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_analyse.html
new file mode 100644 (file)
index 0000000..2b19ac6
--- /dev/null
@@ -0,0 +1,7 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse,#ID_FORMULAIRE}}>
+<a href="#URL_ECRIRE{formulaires}"><:formulaire:titre_formulaires:></a> &gt;
+<a href="[(#URL_ECRIRE{formulaire}|parametre_url{id_formulaire,#ID_FORMULAIRE})]">#TITRE</a> &gt;
+<strong class="on"><:formidable:reponses_analyse:></strong>
+</BOUCLE_autoriser>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_reponse.html b/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_reponse.html
new file mode 100644 (file)
index 0000000..a4ebff6
--- /dev/null
@@ -0,0 +1,6 @@
+<BOUCLE_formulaire(FORMULAIRES_REPONSES){id_formulaires_reponse}>
+<a href="#URL_ECRIRE{formulaires}"><:formulaire:titre_formulaires:></a> &gt;
+<a href="[(#URL_ECRIRE{formulaire}|parametre_url{id_formulaire,#ID_FORMULAIRE})]">#INFO_TITRE{formulaire,#ID_FORMULAIRE}</a> &gt;
+<a class="on" href="[(#URL_ECRIRE{formulaires_reponses}|parametre_url{id_formulaire,#ID_FORMULAIRE})]"><:formidable:voir_reponses:></a> &gt;
+<strong class="on"><:formulaires_reponse:titre_formulaires_reponse:></strong>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_reponses.html b/www/plugins/formidable_1_0/prive/squelettes/hierarchie/formulaires_reponses.html
new file mode 100644 (file)
index 0000000..bfe3559
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<a href="#URL_ECRIRE{formulaires}"><:formulaire:titre_formulaires:></a> &gt;
+<a href="[(#URL_ECRIRE{formulaire}|parametre_url{id_formulaire,#ID_FORMULAIRE})]">#INFO_TITRE{formulaire,#ID_FORMULAIRE}</a> &gt;
+<strong class="on"><:formidable:voir_reponses:></strong>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaire.html b/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaire.html
new file mode 100644 (file)
index 0000000..f629fc3
--- /dev/null
@@ -0,0 +1,50 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+#BOITE_OUVRIR{'','info'}
+#PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{'type','formulaire','id',#ENV{id_formulaire}}}}
+
+[(#AUTORISER{editer, formulaire, #ID_FORMULAIRE}|oui)
+
+[(#URL_ECRIRE{formulaire_edit}
+       |parametre_url{id_formulaire, #ID_FORMULAIRE}
+       |parametre_url{configurer,formulaire}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_formulaire:>,formulaire,formulaire-editer-24,center})]
+
+[(#CONFIG{formidable/analyse/auteur}|=={on}|oui)[(#URL_ECRIRE{formulaire_edit}
+       |parametre_url{id_formulaire, #ID_FORMULAIRE}
+       |parametre_url{configurer,auteurs}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_auteurs:>,formulaire,formulaire-config-auteurs-24,center})]
+]
+
+[(#URL_ECRIRE{formulaire_edit}
+       |parametre_url{id_formulaire, #ID_FORMULAIRE}
+       |parametre_url{configurer,champs}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_champs:>,formulaire,formulaire-config-champs-24,center})]
+
+[(#URL_ECRIRE{formulaire_edit}
+       |parametre_url{id_formulaire, #ID_FORMULAIRE}
+       |parametre_url{configurer,traitements}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_traitements:>,formulaire,formulaire-config-traitements-24,center})]
+
+]
+
+<BOUCLE_resultats(FORMULAIRES_REPONSES){id_formulaire}{tous}>
+</BOUCLE_resultats>
+
+[(#AUTORISER{voir,formulaires_reponse,#ID_FORMULAIRE}|oui)
+<div class='navigation_resultats'>
+[(#URL_ECRIRE{formulaires_reponses}
+       |parametre_url{id_formulaire, #ID_FORMULAIRE}
+       |icone_horizontale{<:formidable:voir_reponses:> &#40;#TOTAL_BOUCLE&#41;,formulaire,formulaire-reponses-24,center})]
+[(#URL_ECRIRE{formulaires_analyse}
+       |parametre_url{id_formulaire, #ID_FORMULAIRE}
+       |icone_horizontale{<:formidable:reponses_analyse:>,formulaire,formulaire-analyse-24,center})]
+</div>]
+
+</B_resultats>
+
+#BOITE_FERMER
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaire_edit.html b/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaire_edit.html
new file mode 100644 (file)
index 0000000..fbc11c3
--- /dev/null
@@ -0,0 +1,28 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+#BOITE_OUVRIR{'','info'}
+#PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{'type','formulaire','id',#ENV{id_formulaire}}}}
+
+[(#SELF
+       |parametre_url{configurer,formulaire}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_formulaire:>,formulaire,formulaire-editer-24,center})]
+
+[(#CONFIG{formidable/analyse/auteur}|=={on}|oui)[(#SELF
+       |parametre_url{configurer,auteurs}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_auteurs:>,formulaire,formulaire-config-auteurs-24,center})]
+]
+
+[(#SELF
+       |parametre_url{configurer,champs}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_champs:>,formulaire,formulaire-config-champs-24,center})]
+
+[(#SELF
+       |parametre_url{configurer,traitements}
+       |parametre_url{avertissement,''}
+       |icone_horizontale{<:formidable:editer_menu_traitements:>,formulaire,formulaire-config-traitements-24,center})]
+
+#BOITE_FERMER
+
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires.html b/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires.html
new file mode 100644 (file)
index 0000000..0ccb362
--- /dev/null
@@ -0,0 +1,5 @@
+[(#AUTORISER{editer, formulaire}|oui)
+[(#BOITE_OUVRIR{<:formidable:importer_formulaire:>,'info'})]
+       #FORMULAIRE_IMPORTER_FORMULAIRE
+#BOITE_FERMER
+]
diff --git a/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_analyse.html b/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_analyse.html
new file mode 100644 (file)
index 0000000..d588f7e
--- /dev/null
@@ -0,0 +1,12 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse, #ENV{id_formulaire}}}>
+#BOITE_OUVRIR{'','info'}
+#PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{'type','formulaire','id',#ENV{id_formulaire}}}}
+
+[(#URL_ECRIRE{formulaires_reponses}|parametre_url{id_formulaire,#ID_FORMULAIRE}|icone_horizontale{<:formidable:reponses_liste:>,formulaire,formulaire-reponses-24,left})]
+
+[(#SELF|icone_horizontale{<:formidable:reponses_analyse:>,formulaire,formulaire-analyse-24,left})]
+
+#BOITE_FERMER
+</BOUCLE_autoriser>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_reponse.html b/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_reponse.html
new file mode 100644 (file)
index 0000000..bc6188b
--- /dev/null
@@ -0,0 +1,15 @@
+<BOUCLE_formulaires_reponse(FORMULAIRES_REPONSES){tout}{id_formulaires_reponse}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse, #ID_FORMULAIRE}}>
+[(#BOITE_OUVRIR{'','info'})]
+
+       [(#PIPELINE{boite_infos,#ARRAY{data,'',
+               args,#ARRAY{'type','formulaires_reponse','id',#ENV{id_formulaires_reponse}}}})]
+
+       [(#URL_ECRIRE{formulaires_analyse}
+               |parametre_url{id_formulaire,#ID_FORMULAIRE}
+               |icone_horizontale{<:formidable:reponses_analyse:>,formulaire,formulaire-analyse-24,center})]
+
+#BOITE_FERMER
+
+</BOUCLE_autoriser>
+</BOUCLE_formulaires_reponse>
diff --git a/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_reponses.html b/www/plugins/formidable_1_0/prive/squelettes/navigation/formulaires_reponses.html
new file mode 100644 (file)
index 0000000..001ac20
--- /dev/null
@@ -0,0 +1,12 @@
+<BOUCLE_formulaire(FORMULAIRES){id_formulaire}>
+<BOUCLE_autoriser(CONDITION){si #AUTORISER{voir, formulaires_reponse, #ID_FORMULAIRE}}>
+#BOITE_OUVRIR{'','info'}
+#PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{'type','formulaire','id',#ENV{id_formulaire}}}}
+
+[(#SELF|icone_horizontale{<:formidable:reponses_liste:>,formulaire,formulaire-reponses-24,left})]
+
+[(#URL_ECRIRE{formulaires_analyse}|parametre_url{id_formulaire,#ID_FORMULAIRE}|icone_horizontale{<:formidable:reponses_analyse:>,formulaire,formulaire-analyse-24,left})]
+
+#BOITE_FERMER
+</BOUCLE_autoriser>
+</BOUCLE_formulaire>
diff --git a/www/plugins/formidable_1_0/prive/style_prive_plugin_formidable.html b/www/plugins/formidable_1_0/prive/style_prive_plugin_formidable.html
new file mode 100644 (file)
index 0000000..cbd1cf9
--- /dev/null
@@ -0,0 +1,32 @@
+#SET{claire,#ENV{couleur_claire,edf3fe}}
+#SET{foncee,#ENV{couleur_foncee,3874b0}}
+
+body .formidable_analyse .progress-bar span {
+       background-color: ##GET{claire};
+         background-image: -webkit-gradient(linear, left top, left bottom, from(##GET{claire}), to(##GET{foncee}));
+         background-image: -webkit-linear-gradient(top, ##GET{claire}, ##GET{foncee});
+         background-image: -moz-linear-gradient(top, ##GET{claire}, ##GET{foncee});
+         background-image: -ms-linear-gradient(top, ##GET{claire}, ##GET{foncee});
+         background-image: -o-linear-gradient(top, ##GET{claire}, ##GET{foncee});
+         background-image: linear-gradient(top, ##GET{claire}, ##GET{foncee}); 
+}
+
+#navigation .navigation_resultats {
+       margin-top:1em;
+       padding-top:1em;
+       border-top:1px solid #eee;
+}
+
+#contenu .box.traitements ul.spip {margin-bottom:0;}
+
+#contenu .liste-objets.formulaires_reponses tr > .date {width:auto;}
+#contenu .liste-objets.formulaires_reponses tr > .auteur {width:auto;}
+
+.formulaires_reponse #contenu #wysiwyg {margin-top:1em;}
+.formulaires_reponse #contenu #wysiwyg .label {
+       width:140px; float:left; display:block;
+}
+.formulaires_reponse #contenu .fiche_objet .reponses .inner { border:none; }
+.formulaires_reponse #contenu .fiche_objet .reponses .hd {
+    padding-bottom: 3px; margin-bottom:10px; border-bottom:1px solid #ccc;
+}
diff --git a/www/plugins/formidable_1_0/prive/themes/basic/images/formulaire-16.png b/www/plugins/formidable_1_0/prive/themes/basic/images/formulaire-16.png
new file mode 100644 (file)
index 0000000..8ca21ea
Binary files /dev/null and b/www/plugins/formidable_1_0/prive/themes/basic/images/formulaire-16.png differ
diff --git a/www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-16.png b/www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-16.png
new file mode 100644 (file)
index 0000000..8ca21ea
Binary files /dev/null and b/www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-16.png differ
diff --git a/www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-24.png b/www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-24.png
new file mode 100644 (file)
index 0000000..ff847d0
Binary files /dev/null and b/www/plugins/formidable_1_0/prive/themes/spip/images/formulaire-24.png differ
diff --git a/www/plugins/formidable_1_0/prive/themes/spip/images/formulaires_reponse-24.png b/www/plugins/formidable_1_0/prive/themes/spip/images/formulaires_reponse-24.png
new file mode 100644 (file)
index 0000000..ec0a2b0
Binary files /dev/null and b/www/plugins/formidable_1_0/prive/themes/spip/images/formulaires_reponse-24.png differ
diff --git a/www/plugins/formidable_1_0/public/formidable_criteres.php b/www/plugins/formidable_1_0/public/formidable_criteres.php
new file mode 100644 (file)
index 0000000..ef2147a
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+       // {tri_donnee champ}
+/**
+ * Depuis la boucle FORMULAIRES_REPONSES, trier les résulats en fonction d'un champ
+ * de la table FORMULAIRES_REPONSES_CHAMPS
+ * {tri_selon_donnee} 
+ *
+ * @global array $exceptions_des_tables
+ * @param string $idb
+ * @param array $boucles
+ * @param <type> $crit
+ * 
+ * Auteurs :
+ * Antoine Pitrou
+ * Cedric Morin
+ * Renato
+ * @ 2005,2006 - Distribue sous licence GNU/GPL
+ */
+
+function critere_tri_selon_donnee_dist($idb, &$boucles, $crit) { // Garder cette fontion pour compatibilité
+       critere_tri_selon_reponse_dist($idb, $boucles, $crit) ;
+}
+function critere_tri_selon_reponse_dist($idb, &$boucles, $crit) {
+
+       $boucle = &$boucles[$idb];
+       $t = $boucle->id_table;
+       
+       if ($t=='formulaires_reponses'){
+               $not = $crit->not;
+               $_quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
+               $k = count($boucle->join)+1;
+               $boucle->join[$k]= array($t,'id_formulaires_reponse');
+               $boucle->from["L$k"]= 'spip_formulaires_reponses_champs';
+               $op = array("'='", "'L$k.nom'", "_q(".$_quoi.")");
+               $boucle->where[]= array("'?'","!in_array($_quoi,array('date','id_formulaires_reponse'))",$op,"''");
+               $boucle->order[]= "(in_array($_quoi,array('date','id_formulaires_reponse'))?'$t.'.$_quoi:(strncmp($_quoi,'date_',5)==0?'STR_TO_DATE(L$k.valeur,\'%d/%m/%Y\')':'L$k.valeur'))".($not?".' DESC'":"");
+       }
+}
+
+// {recherche_donnee} ou {recherche_donnee susan}
+// Intégralement pompé et adapté de Forms&Tables
+function critere_recherche_reponse_dist($idb, &$boucles, $crit) {
+       global $table_des_tables;
+       $boucle = &$boucles[$idb];
+       $t = $boucle->id_table;
+       if ($t=='formulaires_reponses'){
+               if (isset($crit->param[0]))
+                       $_quoi = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
+               else
+                       $_quoi = '@$Pile[0]["recherche"]';
+
+               $k = count($boucle->join)+1;
+               $boucle->join[$k]= array($t,'id_formulaires_reponse');
+               $boucle->from["L$k"]= 'spip_formulaires_reponses_champs';
+               $op = array("'LIKE'","'L$k.valeur'","_q(strpos($_quoi,'%')===false?'%'.".$_quoi.".'%':$_quoi)");
+               $boucle->where[]= array("'?'",$_quoi,$op,"''");
+       }
+}
+
+
+?>
diff --git a/www/plugins/formidable_1_0/puce_statut/formulaires_reponse.php b/www/plugins/formidable_1_0/puce_statut/formulaires_reponse.php
new file mode 100644 (file)
index 0000000..0efc6f9
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * Gestion des puces d'action rapide de formulaires
+ *
+ * @package SPIP\Formidable\Puce_statut
+**/
+
+/**
+ * Gestion des puces statuts des formulaires
+ * 
+ * Retourne le contenu d'une puce avec changement de statut possible
+ * si on en a l'autorisation, sinon simplement l'image de la puce
+ *
+ * @param int $id
+ *     Identifiant de l'objet
+ * @param string $statut
+ *     Statut actuel de l'objet
+ * @param int $id_parent
+ *     Identifiant du parent, un formulaire
+ * @param string $type
+ *     Type d'objet
+ * @param bool $ajax
+ *     Indique s'il ne faut renvoyer que le coeur du menu car on est
+ *     dans une requete ajax suite à un post de changement rapide
+ * @param bool $menu_rapide
+ *     Indique si l'on peut changer le statut, ou si on l'affiche simplement
+ * @return string
+ *     Code HTML de l'image de puce de statut à insérer (et du menu de changement si présent)
+**/
+function puce_statut_formulaires_reponse_dist($id, $statut, $id_parent, $type='article', $ajax = false, $menu_rapide=_ACTIVER_PUCE_RAPIDE) {
+
+       $src = statut_image($type, $statut);
+       if (!$src)
+               return $src;
+
+       if (!$id
+         OR !_SPIP_AJAX
+         OR !$menu_rapide
+         OR !autoriser('instituer', $type, $id)) {
+         $ajax_node ='';
+       }
+       else
+               $ajax_node = " class='imgstatut$type$id'";
+
+       $inser_puce = http_img_pack($src,statut_titre($type, $statut),$ajax_node);
+
+       if (!$ajax_node)
+               return $inser_puce;
+
+       $table = table_objet_sql($type);
+       $desc = lister_tables_objets_sql($table);
+       if (!isset($desc['statut_textes_instituer']))
+               return $inser_puce;
+
+       $coord = array_flip(array_keys($desc['statut_textes_instituer']));
+       if (!isset($coord[$statut]))
+               return $inser_puce;
+
+       $unit = 8/*widh de img*/+4/*padding*/;
+       $margin = 4; /* marge a gauche + droite */
+       $zero = 1 /*border*/ + $margin/2 + 2 /*padding*/;
+       $clip = $zero+ ($unit*$coord[$statut]);
+       if ($ajax){
+
+               $width = $unit*count($desc['statut_textes_instituer'])+$margin;
+               $out = "<span class='puce_objet_fixe $type'>"
+               . $inser_puce
+               . "</span>"
+               . "<span class='puce_objet_popup $type statutdecal$type$id' style='width:{$width}px;margin-left:-{$clip}px;'>";
+               $i=0;
+               foreach($desc['statut_textes_instituer'] as $s=>$t){
+                       $out .= afficher_script_statut($id, $type, -$zero-$i++*$unit, statut_image($type,$s), $s, _T($t));
+               }
+               $out .= "</span>";
+               return $out;
+       }
+       else {
+
+               $nom = "puce_statut_";
+         $action = generer_url_ecrire('puce_statut_formulaires',"",true);
+         $action = "if (!this.puce_loaded) { this.puce_loaded = true; prepare_selec_statut(this, '$nom', '$type', '$id', '$action'); }";
+         $over = " onmouseover=\"$action\"";
+
+               $lang_dir = lang_dir(isset($GLOBALS['lang_objet']) ? $GLOBALS['lang_objet'] : "");
+               return  "<span class='puce_objet $type' id='$nom$type$id' dir='$lang_dir'$over>"
+               . $inser_puce
+               . '</span>';
+       }
+}
+
+
diff --git a/www/plugins/formidable_1_0/saisies-analyses/_base.html b/www/plugins/formidable_1_0/saisies-analyses/_base.html
new file mode 100644 (file)
index 0000000..7c9a8ab
--- /dev/null
@@ -0,0 +1,32 @@
+<div class="cadre cadre-liste analyser analyser_#ENV{nom} saisie_#ENV{type_saisie}">
+<table class="liste" cellspacing="0" cellpadding="2" border="0" style="width:100%;" data-nombre="#ENV{reponses_total}">
+[<caption class="titrem"><strong class="caption">(#ENV{label_case,#ENV{label,#ENV{nom}}})</strong></caption>]
+       <tbody>
+       [(#CHEMIN{saisies-analyses/#ENV{type_saisie}.html}|oui)
+               #INCLURE{fond=saisies-analyses/#ENV{type_saisie},env}
+       ]
+       [(#CHEMIN{saisies-analyses/#ENV{type_saisie}.html}|non)
+               #SET{plein,#ENV{valeurs}|array_filter}
+               #SET{vide,#ENV{valeurs}|array_diff_key{#GET{plein}}}
+               [(#GET{plein}|count|>{0}|oui)
+                       #SET{moyenne,#VAL{str_word_count}|array_map{#GET{plein}}|array_sum|div{#GET{plein}|count}}
+               ]
+               [(#GET{plein}|count|>{0}|non)
+                       #SET{moyenne,0}
+               ]
+               <tr class="tr_liste row_odd vide">
+                       <td class="choix"><:formidable:analyse_sans_reponse:></td>
+                       <td class="stat"[ title="(#GET{vide}|count|titre_nb_reponses|attribut_html)"]>[(#GET{vide}|count)]</td>
+               </tr>
+               <tr class="tr_liste row_even plein">
+                       <td class="choix"><:formidable:analyse_avec_reponse:></td>
+                       <td class="stat"[ title="(#GET{plein}|count|titre_nb_reponses|attribut_html)"]>[(#GET{plein}|count)]</td>
+               </tr>
+               <tr class="tr_liste row_odd moyenne">
+                       <td class="choix"><:formidable:analyse_longueur_moyenne:></td>
+                       <td class="stat ignore">#GET{moyenne}</td>
+               </tr>
+       ]
+       </tbody>
+</table>
+</div>
diff --git a/www/plugins/formidable_1_0/saisies-analyses/case.html b/www/plugins/formidable_1_0/saisies-analyses/case.html
new file mode 100644 (file)
index 0000000..51a9faf
--- /dev/null
@@ -0,0 +1,27 @@
+#SET{oui,0}
+#SET{non,0}
+<BOUCLE_reponses(POUR){tableau #ENV{valeurs}}>
+       [(#VALEUR|oui)
+               #SET{oui,#GET{oui}|plus{1}}
+       ]
+       [(#VALEUR|non)
+               #SET{non,#GET{non}|plus{1}}
+       ]
+</BOUCLE_reponses>
+
+<tr class="tr_liste">
+       <td class="choix"><:item_oui:></td>
+       <td class="stat"[ title="(#GET{oui}|titre_nb_reponses|attribut_html)"]>#GET{oui}</td>
+</tr>
+<tr class="tr_liste">
+       <td class="choix"><:item_non:></td>
+       <td class="stat"[ title="(#GET{non}|titre_nb_reponses|attribut_html)"]>#GET{non}</td>
+</tr>
+
+#SET{diff, #ENV{reponses_total}|moins{#ENV{valeurs}|count}}
+[(#GET{diff}|>{0}|oui)
+<tr class="tr_liste">
+       <td class="choix"><:saisies:vue_sans_reponse:></td>
+       <td class="stat"[ title="(#GET{diff}|titre_nb_reponses|attribut_html)"]>#GET{diff}</td>
+</tr>
+]
diff --git a/www/plugins/formidable_1_0/saisies-analyses/checkbox.html b/www/plugins/formidable_1_0/saisies-analyses/checkbox.html
new file mode 100644 (file)
index 0000000..ad682ae
--- /dev/null
@@ -0,0 +1,26 @@
+#SET{stats,#ARRAY}
+<BOUCLE_reponses(POUR){tableau #ENV{valeurs}}>
+       <BOUCLE_choix(POUR){tableau #VALEUR}>
+       #SET_MERGE{stats, #ARRAY{choix-#VALEUR, #GET{stats}|table_valeur{choix-#VALEUR}|sinon{0}|plus{1}}}
+       </BOUCLE_choix>
+</BOUCLE_reponses>
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV*{datas}}
+#SET{datas, #GET{datas}|is_string|?{(#GET{datas}|saisies_chaine2tableau), #GET{datas}}}
+
+<BOUCLE_datas(POUR){tableau #GET{datas}}>
+[(#SET{nb,[(#GET{stats}|table_valeur{choix-#CLE}|sinon{0})]})]
+<tr class="tr_liste">
+       <td class="choix">#VALEUR</td>
+       <td class="stat"[ title="(#GET{nb}|titre_nb_reponses|attribut_html)"]>#GET{nb}</td>
+</tr>
+</BOUCLE_datas>
+
+#SET{diff, #ENV{reponses_total}|moins{#ENV{valeurs}|count}}
+[(#GET{diff}|>{0}|oui)
+<tr class="tr_liste">
+       <td class="choix"><:saisies:vue_sans_reponse:></td>
+       <td class="stat"[ title="(#GET{diff}|titre_nb_reponses|attribut_html)"]>#GET{diff}</td>
+</tr>
+]
diff --git a/www/plugins/formidable_1_0/saisies-analyses/destinataires.html b/www/plugins/formidable_1_0/saisies-analyses/destinataires.html
new file mode 100644 (file)
index 0000000..9692d03
--- /dev/null
@@ -0,0 +1,14 @@
+#SET{stats,#ARRAY}
+<BOUCLE_reponses(POUR){tableau #ENV{valeurs}}>
+       <BOUCLE_choix(POUR){tableau #VALEUR}>
+       #SET_MERGE{stats, #ARRAY{auteur-#VALEUR, #GET{stats}|table_valeur{auteur-#VALEUR}|sinon{0}|plus{1}}}
+       </BOUCLE_choix>
+</BOUCLE_reponses>
+
+<BOUCLE_stats(POUR){tableau #GET{stats}}>
+#SET{id_auteur, #CLE|replace{'auteur-', ''}}
+<tr class="tr_liste">
+       <td class="choix"><a href="#INFO_URL{auteur, #GET{id_auteur}}">#INFO_TITRE{auteur, #GET{id_auteur}}</a></td>
+       <td class="stat"[ title="(#VALEUR|titre_nb_reponses|attribut_html)"]>#VALEUR</td>
+</tr>
+</BOUCLE_stats>
diff --git a/www/plugins/formidable_1_0/saisies-analyses/explication.html b/www/plugins/formidable_1_0/saisies-analyses/explication.html
new file mode 100644 (file)
index 0000000..703e6c0
--- /dev/null
@@ -0,0 +1,4 @@
+<tr class="tr_liste">
+       <td class='choix' colspan='2'>[<p class='explication'>(#ENV{texte})</p>]</td>
+</tr>
+
diff --git a/www/plugins/formidable_1_0/saisies-analyses/oui_non.html b/www/plugins/formidable_1_0/saisies-analyses/oui_non.html
new file mode 100644 (file)
index 0000000..51a9faf
--- /dev/null
@@ -0,0 +1,27 @@
+#SET{oui,0}
+#SET{non,0}
+<BOUCLE_reponses(POUR){tableau #ENV{valeurs}}>
+       [(#VALEUR|oui)
+               #SET{oui,#GET{oui}|plus{1}}
+       ]
+       [(#VALEUR|non)
+               #SET{non,#GET{non}|plus{1}}
+       ]
+</BOUCLE_reponses>
+
+<tr class="tr_liste">
+       <td class="choix"><:item_oui:></td>
+       <td class="stat"[ title="(#GET{oui}|titre_nb_reponses|attribut_html)"]>#GET{oui}</td>
+</tr>
+<tr class="tr_liste">
+       <td class="choix"><:item_non:></td>
+       <td class="stat"[ title="(#GET{non}|titre_nb_reponses|attribut_html)"]>#GET{non}</td>
+</tr>
+
+#SET{diff, #ENV{reponses_total}|moins{#ENV{valeurs}|count}}
+[(#GET{diff}|>{0}|oui)
+<tr class="tr_liste">
+       <td class="choix"><:saisies:vue_sans_reponse:></td>
+       <td class="stat"[ title="(#GET{diff}|titre_nb_reponses|attribut_html)"]>#GET{diff}</td>
+</tr>
+]
diff --git a/www/plugins/formidable_1_0/saisies-analyses/radio.html b/www/plugins/formidable_1_0/saisies-analyses/radio.html
new file mode 100644 (file)
index 0000000..88627d0
--- /dev/null
@@ -0,0 +1,26 @@
+#SET{stats,#ARRAY}
+<BOUCLE_reponses(POUR){tableau #ENV{valeurs}}>
+       [(#VALEUR|oui)
+               #SET_MERGE{stats, #ARRAY{choix-#VALEUR, #GET{stats}|table_valeur{choix-#VALEUR}|sinon{0}|plus{1}}}
+       ]
+</BOUCLE_reponses>
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV*{datas}}
+#SET{datas, #GET{datas}|is_string|?{(#GET{datas}|saisies_chaine2tableau), #GET{datas}}}
+
+<BOUCLE_datas(POUR){tableau #GET{datas}}>
+[(#SET{nb,[(#GET{stats}|table_valeur{choix-#CLE}|sinon{0})]})]
+<tr class="tr_liste">
+       <td class="choix">#VALEUR</td>
+       <td class="stat"[ title="(#GET{nb}|titre_nb_reponses|attribut_html)"]>#GET{nb}</td>
+</tr>
+</BOUCLE_datas>
+
+#SET{diff, #ENV{reponses_total}|moins{#ENV{valeurs}|count}}
+[(#GET{diff}|>{0}|oui)
+<tr class="tr_liste">
+       <td class="choix"><:saisies:vue_sans_reponse:></td>
+       <td class="stat"[ title="(#GET{diff}|titre_nb_reponses|attribut_html)"]>#GET{diff}</td>
+</tr>
+]
diff --git a/www/plugins/formidable_1_0/saisies-analyses/selecteur_article.html b/www/plugins/formidable_1_0/saisies-analyses/selecteur_article.html
new file mode 100644 (file)
index 0000000..35f08b4
--- /dev/null
@@ -0,0 +1,13 @@
+[(#REM) Attention, saisie multiple non testee ]\r
+\r
+#SET{plein,#ENV{valeurs}|array_filter}\r
+#SET{vide,#ENV{valeurs}|array_diff_key{#GET{plein}}}\r
+\r
+<tr class="tr_liste row_odd vide">\r
+   <td class="choix"><:formidable:analyse_sans_reponse:></td>\r
+   <td class="stat">[(#GET{vide}|count)]</td>\r
+</tr>\r
+<tr class="tr_liste row_even plein">\r
+   <td class="choix"><:formidable:analyse_avec_reponse:></td>\r
+   <td class="stat">[(#GET{plein}|count)]</td>\r
+</tr>\r
diff --git a/www/plugins/formidable_1_0/saisies-analyses/selecteur_rubrique.html b/www/plugins/formidable_1_0/saisies-analyses/selecteur_rubrique.html
new file mode 100644 (file)
index 0000000..35f08b4
--- /dev/null
@@ -0,0 +1,13 @@
+[(#REM) Attention, saisie multiple non testee ]\r
+\r
+#SET{plein,#ENV{valeurs}|array_filter}\r
+#SET{vide,#ENV{valeurs}|array_diff_key{#GET{plein}}}\r
+\r
+<tr class="tr_liste row_odd vide">\r
+   <td class="choix"><:formidable:analyse_sans_reponse:></td>\r
+   <td class="stat">[(#GET{vide}|count)]</td>\r
+</tr>\r
+<tr class="tr_liste row_even plein">\r
+   <td class="choix"><:formidable:analyse_avec_reponse:></td>\r
+   <td class="stat">[(#GET{plein}|count)]</td>\r
+</tr>\r
diff --git a/www/plugins/formidable_1_0/saisies-analyses/selecteur_rubrique_article.html b/www/plugins/formidable_1_0/saisies-analyses/selecteur_rubrique_article.html
new file mode 100644 (file)
index 0000000..a8ef6ae
--- /dev/null
@@ -0,0 +1,14 @@
+[(#REM) Peut etre ameliore en comptant par exemple le nombre d'article / rubriques \r
+Attention, saisie multiple non testee ]\r
+\r
+#SET{plein,#ENV{valeurs}|array_filter}\r
+#SET{vide,#ENV{valeurs}|array_diff_key{#GET{plein}}}\r
+\r
+<tr class="tr_liste row_odd vide">\r
+   <td class="choix"><:formidable:analyse_sans_reponse:></td>\r
+   <td class="stat">[(#GET{vide}|count)]</td>\r
+</tr>\r
+<tr class="tr_liste row_even plein">\r
+   <td class="choix"><:formidable:analyse_avec_reponse:></td>\r
+   <td class="stat">[(#GET{plein}|count)]</td>\r
+</tr>\r
diff --git a/www/plugins/formidable_1_0/saisies-analyses/selection.html b/www/plugins/formidable_1_0/saisies-analyses/selection.html
new file mode 100644 (file)
index 0000000..54589d3
--- /dev/null
@@ -0,0 +1,25 @@
+#SET{stats,#ARRAY}
+<BOUCLE_reponses(POUR){tableau #ENV{valeurs}}>
+       [(#VALEUR|oui)
+               #SET_MERGE{stats, #ARRAY{choix-#VALEUR, #GET{stats}|table_valeur{choix-#VALEUR}|sinon{0}|plus{1}}}
+       ]
+</BOUCLE_reponses>
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV{datas}}
+#SET{datas, #GET{datas}|is_string|?{(#GET{datas}|saisies_chaine2tableau), #GET{datas}}}
+
+<BOUCLE_datas(POUR){tableau #GET{datas}}>
+<tr class="tr_liste">
+       <td class="choix">#VALEUR</td>
+       <td class="stat">[(#GET{stats}|table_valeur{choix-#CLE}|sinon{0})]</td>
+</tr>
+</BOUCLE_datas>
+
+#SET{diff, #ENV{valeurs}|count|moins{#GET{stats}|array_sum}}
+[(#GET{diff}|>{0}|oui)
+<tr class="tr_liste">
+       <td class="choix"><:saisies:vue_sans_reponse:></td>
+       <td class="stat">#GET{diff}</td>
+</tr>
+]
diff --git a/www/plugins/formidable_1_0/saisies-analyses/selection_multiple.html b/www/plugins/formidable_1_0/saisies-analyses/selection_multiple.html
new file mode 100644 (file)
index 0000000..0f1212a
--- /dev/null
@@ -0,0 +1,25 @@
+#SET{stats,#ARRAY}
+<BOUCLE_reponses(POUR){tableau #ENV{valeurs}}>
+       <BOUCLE_choix(POUR){tableau #VALEUR}>
+       #SET_MERGE{stats, #ARRAY{choix-#VALEUR, #GET{stats}|table_valeur{choix-#VALEUR}|sinon{0}|plus{1}}}
+       </BOUCLE_choix>
+</BOUCLE_reponses>
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV{datas}}
+#SET{datas, #GET{datas}|is_string|?{(#GET{datas}|saisies_chaine2tableau), #GET{datas}}}
+
+<BOUCLE_datas(POUR){tableau #GET{datas}}>
+<tr class="tr_liste">
+       <td class="choix">#VALEUR</td>
+       <td class="stat">[(#GET{stats}|table_valeur{choix-#CLE}|sinon{0})]</td>
+</tr>
+</BOUCLE_datas>
+
+#SET{diff, #ENV{reponses_total}|moins{#ENV{valeurs}|count}}
+[(#GET{diff}|>{0}|oui)
+<tr class="tr_liste">
+       <td class="choix"><:saisies:vue_sans_reponse:></td>
+       <td class="stat">#GET{diff}</td>
+</tr>
+]
diff --git a/www/plugins/formidable_1_0/saisies-vues/formulaire_formidable.html b/www/plugins/formidable_1_0/saisies-vues/formulaire_formidable.html
new file mode 100644 (file)
index 0000000..a9692f8
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_formulaire(FORMULAIRES){identifiant=#ENV{valeur}}>
+<p>[(#TITRE|typo)] (#IDENTIFIANT)</p>
+</BOUCLE_formulaire>
+<p><:saisies:vue_sans_reponse:></p>
+<//B_formulaire>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/saisies-vues/formulaire_formidable_multiple.html b/www/plugins/formidable_1_0/saisies-vues/formulaire_formidable_multiple.html
new file mode 100644 (file)
index 0000000..9b75a57
--- /dev/null
@@ -0,0 +1,9 @@
+<B_formulaire>
+<ul>
+       <BOUCLE_formulaire(FORMULAIRES){identifiant IN #ENV**{valeur}}>
+       <li class="choix">[(#TITRE|typo)] (#IDENTIFIANT)</li>
+       </BOUCLE_formulaire>
+</ul>
+</B_formulaire>
+<p><:saisies:vue_sans_reponse:></p>
+<//B_formulaire>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/saisies/champ.html b/www/plugins/formidable_1_0/saisies/champ.html
new file mode 100644 (file)
index 0000000..d2ad8d8
--- /dev/null
@@ -0,0 +1,28 @@
+
+<select name="#ENV{nom}" id="champ_#ENV{nom}">
+       <option value=""><:formidable:traitements_champ_aucun:></option>
+       [(#ENV{forcer_type}|non)
+               #SET{tab,#ENV{formulaire}}
+       ]
+       [(#ENV{forcer_type}|oui)
+               [(#SET{tab,[(#ENV{formulaire}|saisies_lister_par_nom{0})]})]
+       ]
+       #SET{padding,0}
+       <BOUCLE_parcours(POUR){tableau #GET{tab}}>
+               #SET{saisie,#VALEUR}
+               <BOUCLE_test_enfants(CONDITION){si #GET{saisie}|table_valeur{saisies}|is_array}>
+               <optgroup style="padding-left:#GET{padding}px" label="[(#GET{saisie}|table_valeur{options}|table_valeur{label}|sinon{#GET{saisie}|table_valeur{options}|table_valeur{nom}})]">
+                               #SET{tab,#GET{saisie}|table_valeur{saisies}}
+                               #SET{padding,#GET{padding}|plus{20}}
+                               <BOUCLE_parcours_recursif(BOUCLE_parcours)/>
+                               #SET{padding,#GET{padding}|moins{20}}
+               </optgroup>
+               </BOUCLE_test_enfants>
+                       <BOUCLE_test_type(CONDITION){si #ENV{forcer_type}|non|ou{#GET{saisie}|table_valeur{saisie}|in_array{#ENV{forcer_type}}}}>
+                       <option value="[(#GET{saisie}|table_valeur{options}|table_valeur{nom})]" style="padding-left:#GET{padding}px" [(#ENV{valeur,#ENV{saisie_a_positionner}}|=={#GET{saisie}|table_valeur{options}|table_valeur{nom}}|oui)selected="selected"]>
+                               [(#GET{saisie}|table_valeur{options}|table_valeur{label}|sinon{#GET{saisie}|table_valeur{options}|table_valeur{nom}})]
+                       </option>
+                       </BOUCLE_test_type>
+               <//B_test_enfants>
+       </BOUCLE_parcours>
+</select>
diff --git a/www/plugins/formidable_1_0/saisies/formulaire_formidable.html b/www/plugins/formidable_1_0/saisies/formulaire_formidable.html
new file mode 100644 (file)
index 0000000..e8d8bb4
--- /dev/null
@@ -0,0 +1,22 @@
+[(#REM) 
+  Saisie permettant de sélectionner un formulaire par son identifiant
+  
+  ### /!\ boucle POUR (spip Bonux) ###
+       
+  Parametres :
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - class : classe(s) css ajoutes au select
+  
+  Exemple d'appel :
+       [(#SAISIE{formulaire_formidable,nom,
+               label=<:plugin:label:>,
+       })] 
+]
+
+<select name="#ENV{nom}" id="champ_#ENV{nom}"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_selection(FORMULAIRES){par titre}>
+       <option value="#IDENTIFIANT" [(#IDENTIFIANT|=={#ENV{valeur,#ENV{defaut}}}|oui) selected="selected"]>[(#TITRE|typo)] (#IDENTIFIANT)</option>
+</BOUCLE_selection>
+</select>
diff --git a/www/plugins/formidable_1_0/saisies/formulaire_formidable_multiple.html b/www/plugins/formidable_1_0/saisies/formulaire_formidable_multiple.html
new file mode 100644 (file)
index 0000000..b8ef7aa
--- /dev/null
@@ -0,0 +1,26 @@
+[(#REM) 
+  Saisie permettant de sélectionner plusieurs formulaires par leur identifiant
+  
+  ### /!\ boucle POUR (spip Bonux) ###
+       
+  Parametres :
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - class : classe(s) css ajoutes au select
+  
+  Exemple d'appel :
+       [(#SAISIE{formulaire_formidable_multiple,nom,
+               label=<:plugin:label:>,
+       })] 
+]
+
+[(#REM) defaut peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
+#SET{defaut, #ENV{defaut}}
+#SET{defaut, #GET{defaut}|is_string|?{(#GET{defaut}|saisies_chaine2tableau), (#GET{defaut}|sinon{#ARRAY})}}
+
+<select name="#ENV{nom}[]" id="champ_#ENV{nom}" multiple="multiple"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_selection(FORMULAIRES){par titre}>
+       <option value="#IDENTIFIANT" [(#IDENTIFIANT|in_array{#ENV{valeur,#GET{defaut}}}|oui) selected="selected"]>[(#TITRE|typo)] (#IDENTIFIANT)</option>
+</BOUCLE_selection>
+</select>
diff --git a/www/plugins/formidable_1_0/svn.revision b/www/plugins/formidable_1_0/svn.revision
new file mode 100644 (file)
index 0000000..b2c9bab
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/formidable/trunk
+Revision: 73827
+Dernier commit: 2013-06-24 13:00:08 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/formidable/trunk</origine>
+<revision>73827</revision>
+<commit>2013-06-24 13:00:08 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/formidable_1_0/todo.txt b/www/plugins/formidable_1_0/todo.txt
new file mode 100644 (file)
index 0000000..c857bbe
--- /dev/null
@@ -0,0 +1,19 @@
+
+À faire :
+---------
++ Ajouter des liens "réponse précédente/suivante" dans la visualisation d'une réponse
++ Afficher une boite listant les formulaires disponibles dans l'édition d'un article
++ Afficher des saisies en javascript suivant des conditions
++ Utiliser le plugin CVT multi-pages de Cédric
++ Afficher des pages suivant des conditions (scénarios)
++ Pouvoir attacher des fichiers (et donc les envoyer par mail et les enregistrer en base comme document)
++ Déplacer les saisies en drag-n-drop
++ Ajouter une saisie directement au bon endroit en drag-n-drop
++ Améliorer le texte brut généré à partir du HTML
+
+Idées :
+-------
++ Permettre des messages différents lors de la réédition d'un formulaire (avant et après modification)
++ Permettre de prévisualiser avant soumission le formulaire
++ Premettre d'afficher un formulaire en fonction du statut du visiteur
++ Avoir lors de l'édition des champs du formulaire un bouton «Enregistrer et continuer d'éditer»
diff --git a/www/plugins/formidable_1_0/traiter/email.php b/www/plugins/formidable_1_0/traiter/email.php
new file mode 100644 (file)
index 0000000..c7a60e4
--- /dev/null
@@ -0,0 +1,193 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function traiter_email_dist($args, $retours){
+       $formulaire = $args['formulaire'];
+       $options = $args['options'];
+       $saisies = unserialize($formulaire['saisies']);
+       $traitements = unserialize($formulaire['traitements']);
+       $champs = saisies_lister_champs($saisies);
+       
+       // On récupère les destinataires
+       if ($options['champ_destinataires']){
+               $destinataires = _request($options['champ_destinataires']);
+               if (!is_array($destinataires) and intval($destinataires)){
+                       $destinataires = array($destinataires);
+               }
+               if (is_array($destinataires)){
+                       // On récupère les mails des destinataires
+                       $destinataires = array_map('intval', $destinataires);
+                       $destinataires = sql_allfetsel(
+                               'email',
+                               'spip_auteurs',
+                               sql_in('id_auteur', $destinataires)
+                       );
+                       $destinataires = array_map('reset', $destinataires);
+               }
+       }
+       if (!$destinataires)
+               $destinataires = array();
+       
+       // On ajoute les destinataires en plus
+       if ($options['destinataires_plus']){
+               $destinataires_plus = explode(',', $options['destinataires_plus']);
+               $destinataires_plus = array_map('trim', $destinataires_plus);
+               $destinataires = array_merge($destinataires, $destinataires_plus);
+               $destinataires = array_unique($destinataires);
+       }
+       
+       // On récupère le courriel de l'envoyeur s'il existe
+       if ($options['champ_courriel']){
+               $courriel_envoyeur = _request($options['champ_courriel']);
+       }
+       if (!$courriel_envoyeur) $courriel_envoyeur = '';
+       
+       // Si on a bien des destinataires, on peut continuer
+       if ($destinataires or ($courriel_envoyeur and $options['activer_accuse'])){
+               include_spip('inc/filtres');
+               include_spip('inc/texte');
+               
+               $nom_site_spip = supprimer_tags(typo($GLOBALS['meta']['nom_site']));
+               
+               // On parcourt les champs pour générer le tableau des valeurs
+               $valeurs = array();
+               foreach ($champs as $champ){
+                       $valeurs[$champ] = _request($champ);
+               }
+               
+               // On récupère le nom de l'envoyeur
+               if ($options['champ_nom']){
+                       $a_remplacer = array();
+                       if (preg_match_all('/@[\w]+@/', $options['champ_nom'], $a_remplacer)){
+                               $a_remplacer = $a_remplacer[0];
+                               foreach ($a_remplacer as $cle=>$val) $a_remplacer[$cle] = trim($val, '@');
+                               $a_remplacer = array_flip($a_remplacer);
+                               $a_remplacer = array_intersect_key($valeurs, $a_remplacer);
+                               $a_remplacer = array_merge($a_remplacer, array('nom_site_spip' => $nom_site_spip));
+                       }
+                       $nom_envoyeur = trim(_L($options['champ_nom'], $a_remplacer));
+               }
+               if (!$nom_envoyeur) $nom_envoyeur = $GLOBALS['meta']['nom_site'];
+               
+               // On récupère le sujet s'il existe sinon on le construit
+               if ($options['champ_sujet']){
+                       $a_remplacer = array();
+                       if (preg_match_all('/@[\w]+@/', $options['champ_sujet'], $a_remplacer)){
+                               $a_remplacer = $a_remplacer[0];
+                               foreach ($a_remplacer as $cle=>$val) $a_remplacer[$cle] = trim($val, '@');
+                               $a_remplacer = array_flip($a_remplacer);
+                               $a_remplacer = array_intersect_key($valeurs, $a_remplacer);
+                               $a_remplacer = array_merge($a_remplacer, array('nom_site_spip' => $nom_site_spip));
+                       }
+                       $sujet = trim(_L($options['champ_sujet'], $a_remplacer));
+               }
+               if (!$sujet) $sujet = _T('formidable:traiter_email_sujet', array('nom'=>$nom_envoyeur));
+               $sujet = filtrer_entites($sujet);
+               
+               // Mais quel va donc être le fond ?
+               if (find_in_path('notifications/formulaire_'.$formulaire['identifiant'].'_email.html'))
+                       $notification = 'notifications/formulaire_'.$formulaire['identifiant'].'_email';
+               else
+                       $notification = 'notifications/formulaire_email';
+               
+               // On génère le mail avec le fond
+               $html = recuperer_fond(
+                       $notification,
+                       array(
+                               'id_formulaire' => $formulaire['id_formulaire'],
+                               'titre' => _T_ou_typo($formulaire['titre']),
+                               'traitements' => $traitements,
+                               'saisies' => $saisies,
+                               'valeurs' => $valeurs
+                       )
+               );
+               
+               // On génère le texte brut
+               include_spip('classes/facteur');
+               $texte = Facteur::html2text($html);
+               
+               // On utilise la forme avancé de Facteur
+               $corps = array(
+                       'html' => $html,
+                       'texte' => $texte,
+                       'nom_envoyeur' => $nom_envoyeur
+               );
+               // Si l'utilisateur n'a pas indiqué autrement, on met le courriel de l'envoyeur dans
+               // Reply-To et on laisse le from par defaut de Facteur car sinon ca bloque sur les
+               // SMTP un peu restrictifs.
+               $courriel_from = "";
+               if ($courriel_envoyeur && $options['activer_vrai_envoyeur']){
+                       $courriel_from = $courriel_envoyeur;
+               } else if ($courriel_envoyeur) {
+                       $corps['repondre_a'] = $courriel_envoyeur;
+               }
+               
+               // On envoie enfin le message
+               $envoyer_mail = charger_fonction('envoyer_mail','inc');
+               
+               // On envoie aux destinataires
+               if ($destinataires)
+                       $ok = $envoyer_mail($destinataires, $sujet, $corps, $courriel_from, "X-Originating-IP: ".$GLOBALS['ip']);
+               
+               // Si c'est bon, on envoie l'accusé de réception
+               if ($ok and $courriel_envoyeur and $options['activer_accuse']){
+                       // On récupère le sujet s'il existe sinon on le construit
+                       if ($options['sujet_accuse']){
+                               $a_remplacer = array();
+                               if (preg_match_all('/@[\w]+@/', $options['sujet_accuse'], $a_remplacer)){
+                                       $a_remplacer = $a_remplacer[0];
+                                       foreach ($a_remplacer as $cle=>$val) $a_remplacer[$cle] = trim($val, '@');
+                                       $a_remplacer = array_flip($a_remplacer);
+                                       $a_remplacer = array_intersect_key($valeurs, $a_remplacer);
+                                       $a_remplacer = array_merge($a_remplacer, array('nom_site_spip' => $nom_site_spip));
+                               }
+                               $sujet_accuse = trim(_L($options['sujet_accuse'], $a_remplacer));
+                       }
+                       if (!$sujet_accuse) $sujet_accuse = _T('formidable:traiter_email_sujet_accuse');
+                       $sujet_accuse = filtrer_entites($sujet_accuse);
+                       
+                       // Mais quel va donc être le fond ?
+                       if (find_in_path('notifications/formulaire_'.$formulaire['identifiant'].'_accuse.html'))
+                               $accuse = 'notifications/formulaire_'.$formulaire['identifiant'].'_accuse';
+                       else
+                               $accuse = 'notifications/formulaire_accuse';
+                               
+                       // On génère l'accusé de réception
+                       $html_accuse = recuperer_fond(
+                               $accuse,
+                               array(
+                                       'id_formulaire' => $formulaire['id_formulaire'],
+                                       'titre' => _T_ou_typo($formulaire['titre']),
+                                       'message_retour' => $formulaire['message_retour'],
+                                       'traitements' => $traitements,
+                                       'saisies' => $saisies,
+                                       'valeurs' => $valeurs
+                               )
+                       );
+                       
+                       // On génère le texte brut
+                       $texte = Facteur::html2text($html_accuse);
+                       
+                       $corps = array(
+                               'html' => $html_accuse,
+                               'texte' => $texte,
+                               'nom_envoyeur' => $nom_site_spip
+                       );
+
+                       $ok = $envoyer_mail($courriel_envoyeur, $sujet_accuse, $corps, $courriel_from, "X-Originating-IP: ".$GLOBALS['ip']);
+               }
+               
+               if ($ok){
+                       $retours['message_ok'] .= "\n<br/>"._T('formidable:traiter_email_message_ok');
+               }
+               else{
+                       $retours['message_erreur'] .= "\n<br/>"._T('formidable:traiter_email_message_erreur');
+               }
+       }
+       
+       return $retours;
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/traiter/email.yaml b/www/plugins/formidable_1_0/traiter/email.yaml
new file mode 100644 (file)
index 0000000..4f5b4d7
--- /dev/null
@@ -0,0 +1,57 @@
+
+titre: '<:formidable:traiter_email_titre:>'
+description: '<:formidable:traiter_email_description:>'
+options:
+  -
+    saisie: 'champ'
+    options:
+      nom: 'champ_destinataires'
+      label: '<:formidable:traiter_email_option_destinataires_label:>'
+      explication: '<:formidable:traiter_email_option_destinataires_explication:>'
+      forcer_type: [destinataires,hidden]
+      env: true
+  -
+    saisie: 'input'
+    options:
+      nom: 'destinataires_plus'
+      label: '<:formidable:traiter_email_option_destinataires_plus_label:>'
+      explication: '<:formidable:traiter_email_option_destinataires_plus_explication:>'
+    verifier:
+      type: 'email'
+  -
+    saisie: 'champ'
+    options:
+      nom: 'champ_courriel'
+      label: '<:formidable:traiter_email_option_envoyeur_courriel_label:>'
+      explication: '<:formidable:traiter_email_option_envoyeur_courriel_explication:>'
+      env: true
+  -
+    saisie: 'case'
+    options:
+      nom: 'activer_vrai_envoyeur'
+      label: '<:formidable:traiter_email_option_vrai_envoyeur_label:>'
+      explication: '<:formidable:traiter_email_option_vrai_envoyeur_explication:>'
+  -
+    saisie: 'input'
+    options:
+      nom: 'champ_nom'
+      label: '<:formidable:traiter_email_option_envoyeur_nom_label:>'
+      explication: '<:formidable:traiter_email_option_envoyeur_nom_explication:>'
+  -
+    saisie: 'input'
+    options:
+      nom: 'champ_sujet'
+      label: '<:formidable:traiter_email_option_sujet_label:>'
+      explication: '<:formidable:traiter_email_option_sujet_explication:>'
+  -
+    saisie: 'case'
+    options:
+      nom: 'activer_accuse'
+      label: '<:formidable:traiter_email_option_activer_accuse_label:>'
+      label_case: '<:formidable:traiter_email_option_activer_accuse_label_case:>'
+  -
+    saisie: 'input'
+    options:
+      nom: 'sujet_accuse'
+      label: '<:formidable:traiter_email_option_sujet_accuse_label:>'
+      explication: '<:formidable:traiter_email_option_sujet_explication:>'
diff --git a/www/plugins/formidable_1_0/traiter/enregistrement.php b/www/plugins/formidable_1_0/traiter/enregistrement.php
new file mode 100644 (file)
index 0000000..8277067
--- /dev/null
@@ -0,0 +1,137 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function traiter_enregistrement_dist($args, $retours){
+    include_spip('inc/formidable');
+    include_spip('base/abstract_sql');
+    $options = $args['options'];
+    $formulaire = $args['formulaire'];
+    $id_formulaire = intval($formulaire['id_formulaire']);
+    $saisies = unserialize($formulaire['saisies']);
+    $saisies = saisies_lister_par_nom($saisies);
+
+    // La personne a-t-elle un compte ?
+    global $auteur_session;
+    $id_auteur = $auteur_session ? intval($auteur_session['id_auteur']) : 0;
+
+    // traitement de l'anonymisation
+    if ($options['anonymiser'] == 'on') {
+        // mod de l'id_auteur
+        $variables_anonymisation =
+            $GLOBALS['formulaires']['variables_anonymisation'][$options['anonymiser_variable']];
+        $id = eval("return $variables_anonymisation;");
+        $id_auteur = formidable_scramble($id);
+    }
+    // On cherche le cookie et sinon on le crée
+    $nom_cookie = formidable_generer_nom_cookie($id_formulaire);
+    if (isset($_COOKIE[$nom_cookie]))
+        $cookie = $_COOKIE[$nom_cookie];
+    else {
+        include_spip("inc/acces");
+        $cookie = creer_uniqid();
+    }
+
+    // On regarde si c'est une modif d'une réponse existante
+    $id_formulaires_reponse = intval(_request('deja_enregistre_'.$id_formulaire));
+
+    // Si la moderation est a posteriori ou que la personne est un boss, on publie direct
+    if ($options['moderation'] == 'posteriori' or autoriser('instituer', 'formulaires_reponse', $id_formulaires_reponse, null, array('id_formulaire'=>$id_formulaire, 'nouveau_statut'=>'publie')))
+        $statut='publie';
+    else
+        $statut = 'prop';
+
+    // Si ce n'est pas une modif d'une réponse existante, on crée d'abord la réponse
+    if (!$id_formulaires_reponse){
+        $id_formulaires_reponse = sql_insertq(
+            'spip_formulaires_reponses',
+            array(
+                'id_formulaire' => $id_formulaire,
+                'id_auteur' => $id_auteur,
+                'cookie' => $cookie,
+                'ip' => $GLOBALS['ip'],
+                'date' => 'NOW()',
+                'statut' => $statut
+            )
+        );
+        // Si on a pas le droit de répondre plusieurs fois ou que les réponses seront modifiables, il faut poser un cookie
+        if (!$options['multiple'] or $options['modifiable']){
+            include_spip("inc/cookie");
+            // Expiration dans 30 jours
+            spip_setcookie($nom_cookie, $_COOKIE[$nom_cookie] = $cookie, time() + 30 * 24 * 3600);
+        }
+    }
+
+    // Si l'id n'a pas été créé correctement alors erreur
+    if (!($id_formulaires_reponse > 0)){
+        $retours['message_erreur'] .= "\n<br/>"._T('formidable:traiter_enregistrement_erreur_base');
+    }
+    // Sinon on continue à mettre à jour
+    else{
+        $champs = array();
+        $insertions = array();
+        foreach($saisies as $nom => $saisie){
+            // On ne prend que les champs qui ont effectivement été envoyés par le formulaire
+            if (($valeur = _request($nom)) !== null){
+                $champs[] = $nom;
+                $insertions[] = array(
+                    'id_formulaires_reponse' => $id_formulaires_reponse,
+                    'nom' => $nom,
+                    'valeur' => is_array($valeur) ? serialize($valeur) : $valeur
+                );
+            }
+        }
+
+        // S'il y a bien des choses à modifier
+        if ($champs){
+            // On supprime d'abord les champs
+            sql_delete(
+                'spip_formulaires_reponses_champs',
+                array(
+                    'id_formulaires_reponse = '.$id_formulaires_reponse,
+                    sql_in('nom', $champs)
+                )
+            );
+
+            // Puis on insère les nouvelles valeurs
+            sql_insertq_multi(
+                'spip_formulaires_reponses_champs',
+                $insertions
+            );
+        }
+    }
+
+    return $retours;
+}
+
+function traiter_enregistrement_update_dist($id_formulaire, $traitement, $saisies_anciennes, $saisies_nouvelles){
+    include_spip('inc/saisies');
+    include_spip('base/abstract_sql');
+    $comparaison = saisies_comparer($saisies_anciennes, $saisies_nouvelles);
+
+    // Si des champs ont été supprimés, il faut supprimer les réponses à ces champs
+    if ($comparaison['supprimees']){
+        // On récupère les réponses du formulaire
+        $reponses = sql_allfetsel(
+            'id_formulaires_reponse',
+            'spip_formulaires_reponses',
+            'id_formulaire = '.$id_formulaire
+        );
+        $reponses = array_map('reset', $reponses);
+
+        // Tous les noms de champs à supprimer
+        $noms = array_keys($comparaison['supprimees']);
+
+        // On supprime
+        sql_delete(
+            'spip_formulaires_reponses_champs',
+            array(
+                sql_in('id_formulaires_reponse', $reponses),
+                sql_in('nom', $noms)
+            )
+        );
+    }
+}
+
+?>
diff --git a/www/plugins/formidable_1_0/traiter/enregistrement.yaml b/www/plugins/formidable_1_0/traiter/enregistrement.yaml
new file mode 100644 (file)
index 0000000..41c9ced
--- /dev/null
@@ -0,0 +1,55 @@
+
+titre: '<:formidable:traiter_enregistrement_titre:>'
+description: '<:formidable:traiter_enregistrement_description:>'
+options:
+  -
+    saisie: 'oui_non'
+    options:
+      nom: 'multiple'
+      label: '<:formidable:traiter_enregistrement_option_multiple_label:>'
+      explication: '<:formidable:traiter_enregistrement_option_multiple_explication:>'
+      defaut: 'on'
+  -
+    saisie: 'oui_non'
+    options:
+      nom: 'modifiable'
+      label: '<:formidable:traiter_enregistrement_option_modifiable_label:>'
+      explication: '<:formidable:traiter_enregistrement_option_modifiable_explication:>'
+      defaut: ''
+  -
+    saisie: 'radio'
+    options:
+      nom: 'identification'
+      label: '<:formidable:traiter_enregistrement_option_identification_label:>'
+      explication: '<:formidable:traiter_enregistrement_option_identification_explication:>'
+      datas:
+        cookie: '<:formidable:identification_par_cookie:>'
+        id_auteur: '<:formidable:identification_par_id_auteur:>'
+      defaut: 'cookie'
+  -
+    saisie: 'oui_non'
+    options:
+      nom: 'anonymiser'
+      label: '<:formidable:traiter_enregistrement_option_anonymiser_label:>'
+      explication: '<:formidable:traiter_enregistrement_option_anonymiser_explication:>'
+      defaut: ''
+  -
+    saisie: 'selection'
+    options:
+      option_intro: '<:formidable:traiter_enregistrement_option_choix_select_label:>'
+      nom: 'anonymiser_variable'
+      label: '<:formidable:traiter_enregistrement_option_anonymiser_variable_label:>'
+      explication: '<:formidable:traiter_enregistrement_option_anonymiser_variable_explication:>'
+      datas:
+        remote_user: "Variable serveur : REMOTE_USER"
+        php_auth_user: "Variable serveur : PHP_AUTH_USER"
+      defaut: ''
+  -
+    saisie: 'radio'
+    options:
+      nom: 'moderation'
+      label: '<:formidable:traiter_enregistrement_option_moderation_label:>'
+      datas:
+        posteriori: '<:forum:bouton_radio_modere_posteriori:>'
+        priori: '<:forum:bouton_radio_modere_priori:>'
+      defaut: 'posteriori'
diff --git a/www/plugins/gis/TODO.txt b/www/plugins/gis/TODO.txt
new file mode 100644 (file)
index 0000000..b51cd70
--- /dev/null
@@ -0,0 +1,14 @@
+peut être utiliser cette lib php pour le geocoder ? : https://github.com/willdurand/Geocoder
+
+des couches à pomper :
+- http://earthquake.usgs.gov/template/js/classes/usgs/leaflet/layer/
+
+une barre de zoom bien faite à passer en plugin ici : https://github.com/CloudMade/Leaflet/pull/689
+
+Avoir un crayon de modification de point depuis le public
+
+Interface de recherche de point :
+- textuelle (recherche dans le titre + descriptif + pays + bla bla bla)
+- par carte : Ouvre une carte + on clique le point avec un bouton choisir dedans + joint le point en question à un objet
+(utilisation via mediabox possible)
+- Une simple liste des points paginés par date de modif/ d'ajout 
\ No newline at end of file
diff --git a/www/plugins/gis/action/editer_gis.php b/www/plugins/gis/action/editer_gis.php
new file mode 100644 (file)
index 0000000..3eb3486
--- /dev/null
@@ -0,0 +1,207 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/autoriser');
+
+function action_editer_gis_dist($arg=null) {
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+       
+       // si id_gis n'est pas un nombre, c'est une creation
+       if (!$id_gis = intval($arg)) {
+               if (!autoriser('creer','gis') or !$id_gis = gis_inserer())
+                       return array(false,_L('echec'));
+       }
+       $err = gis_modifier($id_gis);
+       return array($id_gis,$err);
+}
+
+/**
+ * Fonction d'insertion d'un gis vide
+ * 
+ * @return int/false $id_gis : l'identifiant numérique du point ou false en cas de non création
+ */
+function gis_inserer() {
+       $champs = array();
+       
+       // Envoyer aux plugins
+       $champs = pipeline('pre_insertion', array(
+               'args' => array(
+                       'table' => 'spip_gis',
+               ),
+               'data' => $champs
+       ));
+       
+       $id_gis = sql_insertq("spip_gis", $champs);
+       
+       pipeline('post_insertion',
+               array(
+                       'args' => array(
+                               'table' => 'spip_gis',
+                               'id_objet' => $id_gis
+                       ),
+                       'data' => $champs
+               )
+       );
+       return $id_gis;
+}
+
+/**
+ *  Enregistrer certaines modifications d'un gis
+ * 
+ * @param int $id_gis : l'identifiant numérique du point
+ * @param array $c : un array des valeurs à mettre en base (par défaut false, on récupère les valeurs passées en dans le POST)
+ */
+/**
+ * Appelle toutes les fonctions de modification d'un point gis
+ * $err est de la forme chaine de langue ou vide si pas d'erreur
+ * http://doc.spip.org/@articles_set
+ *
+ * @param  $id_gis
+ * @param null $set
+ * @return string
+ */
+function gis_modifier($id_gis, $set=null) {
+       include_spip('inc/modifier');
+       include_spip('inc/filtres');
+       $c = collecter_requests(
+               // white list
+               objet_info('gis','champs_editables'),
+               // black list
+               array('id_objet','objet'),
+               // donnees eventuellement fournies
+               $set
+       );
+
+       if ($err = objet_modifier_champs('gis', $id_gis,
+               array(
+                       //'nonvide' => array('nom' => _T('info_sans_titre')),
+                       'invalideur' => "id='gis/$id_gis'",
+               ),
+               $c))
+               return $err;
+
+       // lier a un parent ?
+       $c = collecter_requests(array('id_objet', 'objet'),array(),$set);
+       if (isset($c['id_objet']) AND intval($c['id_objet']) AND isset($c['objet']) AND $c['objet']) {
+               lier_gis($id_gis, $c['objet'], $c['id_objet']);
+       }
+
+       return $err;
+}
+
+
+/**
+ * Associer un point géolocalisé a des objets listes sous forme
+ * array($objet=>$id_objets,...)
+ * $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type
+ *
+ * on peut passer optionnellement une qualification du (des) lien(s) qui sera
+ * alors appliquee dans la foulee.
+ * En cas de lot de liens, c'est la meme qualification qui est appliquee a tous
+ *
+ * @param int $id_gis
+ * @param array $objets
+ * @param array $qualif
+ * @return string
+ */
+function gis_associer($id_gis,$objets, $qualif = null){
+       include_spip('action/editer_liens');
+       $res = objet_associer(array('gis'=>$id_gis), $objets, $qualif);
+       include_spip('inc/invalideur');
+       suivre_invalideur("id='gis/$id_gis'");
+       return $res;
+}
+
+/**
+ * Dossocier un point géolocalisé des objets listes sous forme
+ * array($objet=>$id_objets,...)
+ * $id_objets peut lui meme etre un scalaire ou un tableau pour une liste d'objets du meme type
+ *
+ * un * pour $id_auteur,$objet,$id_objet permet de traiter par lot
+ *
+ * @param int $id_gis
+ * @param array $objets
+ * @return string
+ */
+function gis_dissocier($id_gis,$objets){
+       include_spip('action/editer_liens');
+       $res = objet_dissocier(array('gis'=>$id_gis), $objets);
+       include_spip('inc/invalideur');
+       suivre_invalideur("id='gis/$id_gis'");
+       return $res;
+}
+
+
+
+/**
+ * Supprimer définitivement un point géolocalisé
+ * 
+ * @param int $id_gis identifiant numérique du point
+ * @return int|false 0 si réussite, false dans le cas ou le point n'existe pas
+ */
+function gis_supprimer($id_gis){
+       $valide = sql_getfetsel('id_gis','spip_gis','id_gis='.intval($id_gis));
+       if($valide && autoriser('supprimer','gis',$valide)){
+               sql_delete("spip_gis_liens", "id_gis=".intval($id_gis));
+               sql_delete("spip_gis", "id_gis=".intval($id_gis));
+               $id_gis = 0;
+               include_spip('inc/invalideur');
+               suivre_invalideur("id='id_gis/$id_gis'");
+               return $id_gis;
+       }
+       return false;
+}
+
+
+/**
+ * Délier un point géolocalisé d'un objet SPIP
+ *
+ * @param int $id_gis identifiant numérique du point
+ * @param string $objet Le type de l'objet à lier
+ * @param int $id_objet L'identifiant numérique de l'objet lié
+ *
+ * @return bool : true si la suppression de la liaison s'est bien passée, false à l'inverse
+ */
+function delier_gis($id_gis, $objet, $id_objet){
+       //$objet = objet_type($objet);
+       if ($id_objet AND $id_gis
+       AND preg_match('/^[a-z0-9_]+$/i', $objet) # securite
+       AND autoriser('delier','gis',$id_gis,$GLOBALS['visiteur_session'],array('objet' => $objet,'id_objet'=>$id_objet))
+       ) {
+               gis_dissocier($id_gis,array($objet=>$id_objet));
+               return true;
+       }
+       return false;
+}
+
+/**
+ * Lier un point géolocalisé à un objet SPIP
+ *
+ * @param int $id_gis identifiant numérique du point
+ * @param string $objet Le type de l'objet à lier
+ * @param int $id_objet L'identifiant numérique de l'objet lié
+ *
+ * @return bool : true si la liaison s'est bien passée, false à l'inverse
+ */
+function lier_gis($id_gis, $objet, $id_objet){
+       //$objet = objet_type($objet);
+       if ($id_objet AND $id_gis
+       AND preg_match('/^[a-z0-9_]+$/i', $objet) # securite
+       AND !sql_getfetsel("id_gis", "spip_gis_liens", "id_gis=$id_gis AND id_objet=$id_objet AND objet=".sql_quote($objet))
+       AND autoriser('lier','gis',$id_gis,$GLOBALS['visiteur_session'],array('objet' => $objet,'id_objet'=>$id_objet))
+       ) {
+               gis_associer($id_gis,array($objet=>$id_objet));
+               return true;
+       }
+       return false;
+}
+
+function insert_gis() {return gis_inserer();}
+function revisions_gis($id_gis, $c=false) {return gis_modifier($id_gis,$c);}
+function supprimer_gis($id_gis){return gis_supprimer($id_gis);}
+
+?>
diff --git a/www/plugins/gis/action/editer_lien_gis.php b/www/plugins/gis/action/editer_lien_gis.php
new file mode 100644 (file)
index 0000000..f5633d3
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+function action_editer_lien_gis_dist(){
+       $securiser_action = charger_fonction('securiser_action', 'inc');
+       $arg = $securiser_action();
+       list($action,$id_gis, $objet, $id_objet) = explode('/',$arg);
+       
+       include_spip('inc/autoriser');
+       if (intval($id_gis) AND autoriser('lier','gis',$id_gis,$GLOBALS['visiteur_session'],array('objet' => $objet,'id_objet'=>$id_objet))){
+               include_spip('action/editer_gis');
+               if ($action == 'lier')
+                       lier_gis($id_gis, $objet, $id_objet);
+               elseif ($action == 'delier')
+                       delier_gis($id_gis, $objet, $id_objet);
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/action/kml_infos.php b/www/plugins/gis/action/kml_infos.php
new file mode 100644 (file)
index 0000000..eda2049
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/charsets');  # pour le nom de fichier
+include_spip('inc/actions');
+
+function action_kml_infos_dist(){
+       global $redirect;
+
+       $securiser_action = charger_fonction('securiser_action', 'inc');
+       $arg = $securiser_action();
+
+       if (!preg_match(",^(-?)(\d+)\W(\w+)\W?(\d*)\W?(\d*)$,", $arg, $r)){
+               spip_log("action_kml_infos_dist incompris: " . $arg);
+               $redirect = urldecode(_request('redirect'));
+               return;
+       }
+       else{
+               action_kml_infos_post($r);
+       }
+}
+
+function action_kml_infos_post($r){
+       list(, $sign, $id_objet, $objet, $id_document, $suite) = $r;
+
+       if(intval($id_document)){
+               $recuperer_info = charger_fonction('kml_infos','inc');
+               $infos = $recuperer_info($id_document);
+               if($infos){
+                       include_spip('inc/documents');
+                       $fichier = sql_getfetsel('fichier','spip_documents','id_document='.intval($id_document));
+                       if(is_numeric($latitude = $infos['latitude']) && is_numeric($longitude = $infos['longitude'])){
+                               $c = array(
+                                       'titre' => $infos['titre'] ? $infos['titre'] : basename($fichier),
+                                       'lat'=> $latitude,
+                                       'lon' => $longitude,
+                                       'zoom' => $config['zoom'] ? $config['zoom'] :'4'
+                               );
+               
+                               include_spip('action/editer_gis');
+       
+                               if($id_gis = sql_getfetsel("G.id_gis","spip_gis AS G LEFT  JOIN spip_gis_liens AS T ON T.id_gis=G.id_gis ","T.id_objet=" . intval($id_document) . " AND T.objet='document'")){
+                                       // Des coordonnées sont déjà définies pour ce document => on les update
+                                       revisions_gis($id_gis,$c);
+                                       spip_log("GIS EXIFS : Update des coordonnées depuis EXIFS pour le document $id_document => id_gis = $id_gis","gis");
+                               }
+                               else{
+                                       // Aucune coordonnée n'est définie pour ce document  => on les crées
+                                       $id_gis = insert_gis();
+                                       revisions_gis($id_gis,$c);
+                                       lier_gis($id_gis, 'document', $id_document);
+                                       spip_log("GIS EXIFS : Création des coordonnées depuis EXIFS pour le document $id_document => id_gis = $id_gis","gis");
+                               }
+                       }
+                       unset($infos['longitude']);
+                       unset($infos['latitude']);
+                       if(count($infos) > 0){
+                               include_spip('action/editer_document');
+                               document_modifier($id_document, $infos);
+                       }
+               }
+       }
+       $redirect = urldecode(_request('redirect'));
+       return $redirect;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/action/supprimer_gis.php b/www/plugins/gis/action/supprimer_gis.php
new file mode 100644 (file)
index 0000000..6c838f2
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+function action_supprimer_gis_dist(){
+       
+       $securiser_action = charger_fonction('securiser_action', 'inc');
+       $arg = $securiser_action();
+       
+       list($id_gis) = preg_split(',[^0-9],',$arg);
+       include_spip('inc/autoriser');
+       if (intval($id_gis) AND autoriser('supprimer','gis',$id_gis)){
+               include_spip("action/editer_gis");
+               supprimer_gis($id_gis);
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/base/gis.php b/www/plugins/gis/base/gis.php
new file mode 100644 (file)
index 0000000..5117ea6
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function gis_declarer_tables_interfaces($interface){
+       $interface['tables_jointures']['spip_gis'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_gis_liens'][] = 'gis';
+       $interface['tables_jointures']['spip_articles'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_auteurs'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_breves'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_documents'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_groupes_mots'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_mots'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_rubriques'][] = 'gis_liens';
+       $interface['tables_jointures']['spip_syndic'][] = 'gis_liens';
+
+       $interface['table_des_tables']['gis'] = 'gis';
+       $interface['table_des_tables']['gis_liens'] = 'gis_liens';
+
+       // Traitements typo et raccourcis
+       $interface['table_des_traitements']['DESCRIPTIF_GIS'][] = _TRAITEMENT_RACCOURCIS;
+       $interface['table_des_traitements']['VILLE'][] = 'typo(extraire_multi(%s))';
+       $interface['table_des_traitements']['PAYS'][] = 'typo(extraire_multi(%s))';
+
+       return $interface;
+}
+
+function gis_declarer_tables_objets_sql($tables){
+       /* Declaration de la table de points gis */
+       $tables['spip_gis'] = array(
+               /* Declarations principales */
+               'table_objet' => 'gis',
+               'table_objet_surnoms' => array('gis'),
+               'type' => 'gis',
+               'type_surnoms' => array('gi'),
+
+               /* La table */
+               'field' => array(
+                       "id_gis" => "bigint(21) NOT NULL",
+                       "titre" => "varchar(255) NOT NULL DEFAULT ''",
+                       "descriptif" => "text NOT NULL DEFAULT ''",
+                       "lat" => "double NULL NULL",
+                       "lon" => "double NULL NULL",
+                       "zoom" => "tinyint(4) NULL NULL",
+                       "adresse" => "text NOT NULL DEFAULT ''",
+                       "pays" => "text NOT NULL DEFAULT ''",
+                       "code_pays" => "varchar(255) NOT NULL DEFAULT ''",
+                       "region" => "text NOT NULL DEFAULT ''",
+                       "ville" => "text NOT NULL DEFAULT ''",
+                       "code_postal" => "varchar(255) NOT NULL DEFAULT ''"
+               ),
+               'key' => array(
+                       "PRIMARY KEY" => "id_gis",
+               ),
+               'principale' => 'oui',
+               'modeles' => array('carte_gis', 'carte_gis_preview'),
+
+               /* Le titre, la date et la gestion du statut */
+               'titre' => "titre, '' AS lang",
+
+               /* L'édition, l'affichage et la recherche */
+               'page' => 'gis',
+               'url_voir' => 'gis',
+               'url_edit' => 'gis_edit',
+               'editable' => 'oui',
+               'champs_editables' => array('lat', 'lon', 'zoom', 'titre', 'descriptif', 'adresse', 'code_postal', 'ville', 'region', 'pays'),
+               /*'champs_editables' => array(), */
+               'icone_objet' => 'gis',
+               'rechercher_champs' => array(
+                       'titre' => 8,
+                       'descriptif' => 5,
+                       'pays' => 3,
+                       'region' => 3,
+                       'ville' => 3,
+                       'code_postal' => 3,
+               ),
+
+               /* Les textes standard */
+               'texte_ajouter' => 'gis:texte_ajouter_gis',
+               'texte_retour' => 'icone_retour',
+               'texte_modifier' => 'gis:texte_modifier_gis',
+               'texte_creer' => 'gis:texte_creer_gis',
+               'texte_creer_associer' => 'gis:texte_creer_associer_gis',
+               'texte_objet' => 'gis:gis_singulier',
+               'texte_objets' => 'gis:gis_pluriel',
+               'info_aucun_objet' => 'gis:info_aucun_gis',
+               'info_1_objet' => 'gis:info_1_gis',
+               'info_nb_objets' => 'gis:info_nb_gis',
+               'texte_logo_objet' => 'gis:libelle_logo_gis',
+       );
+
+       $spip_gis_liens = array(
+               "id_gis" => "bigint(21) NOT NULL",
+               "objet" => "VARCHAR (25) DEFAULT '' NOT NULL",
+               "id_objet" => "bigint(21) NOT NULL");
+
+       $spip_gis_liens_key = array(
+               "PRIMARY KEY" => "id_gis,id_objet,objet",
+               "KEY id_objet" => "id_gis");
+
+       $tables_auxiliaires['spip_gis_liens'] = array(
+               'field' => &$spip_gis_liens,
+               'key' => &$spip_gis_liens_key);
+
+       return $tables;
+}
+
+function gis_declarer_tables_auxiliaires($tables_auxiliaires){
+       $spip_gis_liens = array(
+               "id_gis" => "bigint(21) NOT NULL",
+               "objet" => "VARCHAR (25) DEFAULT '' NOT NULL",
+               "id_objet" => "bigint(21) NOT NULL");
+
+       $spip_gis_liens_key = array(
+               "PRIMARY KEY" => "id_gis,id_objet,objet",
+               "KEY id_objet" => "id_gis");
+
+       $tables_auxiliaires['spip_gis_liens'] = array(
+               'field' => &$spip_gis_liens,
+               'key' => &$spip_gis_liens_key);
+
+       return $tables_auxiliaires;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/crud/gis.php b/www/plugins/gis/crud/gis.php
new file mode 100644 (file)
index 0000000..1b743ad
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('action/editer_gis');
+
+/**
+ * Interface C(r)UD pour GIS
+ */
+
+/**
+ * Create :
+ * Crée un point géolocalisé
+ * 
+ * @param $dummy
+ * @param array $set : Le contenu des champs à mettre en base
+ * @return array : un array avec (bool) success, (string) message et (array) result indiquant l'id créé 
+ */
+function crud_gis_create_dist($dummy,$set=null){
+       if ($id = insert_gis()){
+               list($e,$ok) = revisions_gis($id,$set);
+       }
+       else{
+               $e = _L('create error');
+       }
+       return array('success'=>$e?false:true,'message'=>$e?$e:$ok,'result'=>array('id'=>$id));
+}
+
+/**
+ * Update :
+ * Met à jour un point géolocalisé
+ * 
+ * @param $dummy
+ * @param array $set : Le contenu des champs à mettre en base
+ * @return array : un array avec (bool) success, (string) message et (array) result indiquant l'id créé 
+ */
+function crud_gis_update_dist($id,$set=null){
+       $id_gis = sql_getfetsel('id_gis','spip_gis','id_gis='.intval($id));
+       if(!$id_gis){
+               $e = _T('gis:erreur_gis_inconnu',array('id'=>$id));
+       }else if(autoriser('modifier','gis',$id)){
+               list($e,$ok) = revisions_gis($id,$set);
+       }else{
+               $e = _L('update error');
+       }
+       return array('success'=>$e?false:true,'message'=>$e?$e:$ok,'result'=>array('id'=>$id));
+}
+
+/**
+ * Delete :
+ * Supprime un point géolocalisé
+ * 
+ * @param $dummy
+ * @param int $id : L'identifiant numérique du point à supprimer
+ * @return array : un array avec (bool) success, (string) message et (array) result indiquant l'id supprimé 
+ */
+function crud_gis_delete_dist($id){
+       if(autoriser('supprimer','gis',$id)){
+               list($e,$ok) = supprimer_gis($id);
+       }
+       return array('success'=>$e?false:true,'message'=>$e?$e:$ok,'result'=>array('id'=>$id));
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/embed/kml.html b/www/plugins/gis/embed/kml.html
new file mode 100644 (file)
index 0000000..3fe9d5a
--- /dev/null
@@ -0,0 +1,38 @@
+<BOUCLE_document(DOCUMENTS){id_document}>
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="#LANG" lang="#LANG" dir="#LANG_DIR">
+<head>
+    <title>[(#TITRE|sinon{#FICHIER|basename})] - #NOM_SITE_SPIP</title>
+    <base target="_parent" /> 
+    <meta name="generator" content="SPIP[ (#SPIP_VERSION)]" />
+    <meta http-equiv="Content-Type" content="text/html; charset=#CHARSET" />
+    [<link rel="stylesheet" href="(#CHEMIN{css/embed_code.css})">]
+               
+       [(#VAL{''}|gis_insert_head_css)]
+       [<script src="(#CHEMIN{prive/javascript/jquery.js})" type="text/javascript"></script>]
+    [<script src="(#CHEMIN{prive/javascript/jquery.placeholder-label.js})" type="text/javascript"></script>]
+    [<script src="(#CHEMIN{prive/javascript/ajaxCallback.js})" type="text/javascript"></script>]
+       [(#VAL{''}|gis_insert_head)]
+</head>
+<body id="document_#ENV{id_document}" class="document embed_document embed_document_#MEDIA" dir="#LANG_DIR" style="width:#ENV{largeur}px;height:#ENV{hauteur}px">
+       <div class="infos_document gis">
+               [<div class="logo">(#LOGO_DOCUMENT|image_reduire{100,100})</div>]
+               <div class="titre"><h1>[(#TITRE|sinon{#FICHIER|basename})]</h1></div>
+               <BOUCLE_gis(GIS){id_document}>
+                       <div class="spip_documents" style="clear:both">
+                       #MODELE{carte_gis,largeur=100%,hauteur=#ENV{hauteur,400px},kml=#ID_DOCUMENT,lat=#LAT,lon=#LON,zoom=#ZOOM,point=non,id_carte_gis=kml#ID_DOCUMENT}
+                       </div>
+               </BOUCLE_gis>
+               </B_gis>
+                       <div class="spip_documents" style="clear:both">
+                       #MODELE{carte_gis,largeur=100%,hauteur=#ENV{hauteur,400px},kml=#ID_DOCUMENT,point=non,id_carte_gis=kml#ID_DOCUMENT}
+                       </div>
+               <//B_gis>
+       </div>
+</body>
+</html>
+</BOUCLE_document>
+</B_document>
+#INCLURE{fond=embed/document,env}
+<//B_document>
+#FILTRE{trim}
\ No newline at end of file
diff --git a/www/plugins/gis/embed/kml_fonctions.php b/www/plugins/gis/embed/kml_fonctions.php
new file mode 100644 (file)
index 0000000..7ad44a3
--- /dev/null
@@ -0,0 +1,12 @@
+<?php
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * On inclue le fichier de pipelines pour avoir les fonctions:
+ * gis_insert_head_css
+ * gis_insert_head
+ */
+include_spip('gis_pipelines');
+
+?>
diff --git a/www/plugins/gis/formulaires/configurer_gis.html b/www/plugins/gis/formulaires/configurer_gis.html
new file mode 100755 (executable)
index 0000000..d38bdf2
--- /dev/null
@@ -0,0 +1,152 @@
+<div class="formulaire_spip formulaire_configurer formulaire_configurer_gis">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<div id="map_config" class="carte_gis" style="width: 100%; height: 370px"></div>
+
+<form method="post" action="#ENV{action}"><div>
+       #ACTION_FORMULAIRE{#ENV{action}}
+       <ul>
+               [(#SAISIE{input,lat,
+                       label=<:gis:lat:>,
+                       defaut=0,
+                       size=40})]
+               [(#SAISIE{input,lon,
+                       label=<:gis:lon:>,
+                       defaut=0,
+                       size=40})]
+               [(#SAISIE{input,zoom,
+                       label=<:gis:zoom:>,
+                       defaut=0,
+                       size=2,
+                       maxlength=2})]
+               
+               #SET{layers,#ARRAY}
+               <BOUCLE_layer(DATA){source table, #EVAL{$GLOBALS['gis_layers']}}>
+               #SET{layers,#GET{layers}|array_merge{#ARRAY{#CLE,#VALEUR|table_valeur{nom}}}}
+               </BOUCLE_layer>
+               
+               [(#SET{layer_defaut,openstreetmap_mapnik})]
+               [(#VAL{_GIS_LAYER_DEFAUT}|defined|oui)
+                       [(#SET{layer_defaut,[(#EVAL{_GIS_LAYER_DEFAUT})]})]
+               ]
+               [(#VAL{_GIS_LAYER_DEFAUT_FORCE}|defined|oui)
+                       [(#SET{layer_readonly,readonly})]
+                       [(#SET{layer_disable,disabled})]
+                       [(#SET{layer_forcee,[(#EVAL{_GIS_LAYER_DEFAUT_FORCE})]})]
+                       [(#SET{layer_explications,<:gis:explication_layer_forcee:>})]
+               ]
+               [(#SAISIE{selection,layer_defaut,
+                       label=<:gis:cfg_lbl_layer_defaut:>,
+                       cacher_option_intro=oui,
+                       defaut=#GET{layer_defaut},
+                       valeur_forcee=#GET{layer_forcee},
+                       readonly=#GET{layer_readonly},
+                       disable=#GET{layer_disable},
+                       explication=#GET{layer_explications},
+                       datas=#GET{layers}})]
+                       
+               [(#SAISIE{selection_multiple,layers,
+                       label=<:gis:cfg_lbl_layers:>,
+                       cacher_option_intro=oui,
+                       defaut=#GET{layer_defaut},
+                       datas=#GET{layers}})]
+               
+               [(#SAISIE{input,api_key_bing,
+                       label=<:gis:cfg_lbl_api_key_bing:>,
+                       explication=<:gis:cfg_inf_bing{url=https://www.bingmapsportal.com/}:>,
+                       size=40})]
+       
+               [(#SAISIE{oui_non,geocoder,
+                       defaut='',
+                       label=<:gis:cfg_lbl_geocoder:>,
+                       explication=<:gis:cfg_inf_geocoder:>})]
+               
+               [(#SAISIE{oui_non,adresse,
+                       defaut='',
+                       label=<:gis:cfg_lbl_adresse:>,
+                       explication=<:gis:cfg_inf_adresse:>})]
+               
+               [(#SAISIE{oui_non,geolocaliser_user_html5,
+                       defaut='',
+                       label=<:gis:cfg_lbl_geolocaliser_user_html5:>,
+                       explication=<:gis:cfg_inf_geolocaliser_user_html5:>})]
+
+               [(#SAISIE{choisir_objets,gis_objets,
+                       label=<:gis:cfg_lbl_activer_objets:>,
+                       exclus=spip_gis})]
+
+       </ul>
+
+
+       <p class="boutons">
+               <input type="submit" name="_cfg_ok" class="submit" value="<:bouton_enregistrer:>" />
+       </p>
+</div></form>
+
+<script type="text/javascript">
+<!---
+(function($){
+       
+       var maj_inputs = function(map,pos) {
+               var zoom = map.getZoom();
+               $("#champ_lat").val(pos.lat);
+               $("#champ_lon").val(pos.lng);
+               $("#champ_zoom").val(zoom);
+       }
+       
+       var init_config = function() {
+               var map;
+               var map_container = 'map_config';
+               map = new L.Map(map_container);
+               
+               map.attributionControl.setPrefix('');
+               
+               //default layer
+               #SET{layer_defaut,#REM|gis_layer_defaut} #SET{layers,#EVAL{$GLOBALS['gis_layers']}}
+               var [(#GET{layer_defaut})] = [new (#GET{layers}|table_valeur{#GET{layer_defaut}/layer})];
+               map.addLayer([(#GET{layer_defaut})]);
+               
+               <B_layers>
+               var layers_control = new L.Control.Layers();
+               layers_control.addBaseLayer([(#GET{layer_defaut})],["(#GET{layers}|table_valeur{#GET{layer_defaut}/nom})"]);
+               <BOUCLE_layers(DATA){source table, #GET{layers}}{si #ENV{control_type,#ENV{controle_type}}|!={non}|et{#ENV{no_control,#ENV{aucun_controle}}|!={oui}}|et{#CONFIG{gis/layers,#ARRAY}|count|>{1}|oui}|oui}>[
+               (#CLE|!={#GET{layer_defaut}}|oui|et{#CLE|in_array{#CONFIG{gis/layers,#ARRAY}}|oui}|oui)
+               layers_control.addBaseLayer([new (#VALEUR|table_valeur{layer})],"[(#VALEUR|table_valeur{nom})]");]
+               </BOUCLE_layers>
+               map.addControl(layers_control);
+               // classe noajax sur le layer_control pour éviter l'ajout de hidden par SPIP
+               $(layers_control._form).addClass('noajax');
+               </B_layers>
+
+               map.setView(new L.LatLng(#ENV{lat,0},#ENV{lon,0}),#ENV{zoom,0});
+               
+               var marker = new L.Marker(new L.LatLng(#ENV{lat,0},#ENV{lon,0}));
+               map.addLayer(marker);
+               
+               // mettre a jour les coordonnees quand on clique la carte
+               map.on('click', function(e) {
+                       marker.setLatLng(e.latlng);
+                       map.panTo(e.latlng);
+                       maj_inputs(map,e.latlng);
+               });
+               
+               // mettre à jour le zoom quand on le modifie
+               map.on('zoomend', function(e) {
+                       $("#champ_zoom").val(e.target._zoom);
+               });
+
+       }
+
+       $(function(){
+               jQuery.getScript('[(#PRODUIRE{fond=javascript/gis.js}|compacte)]',function(){
+                       init_config();
+               });
+               //onAjaxLoad(init_config);
+       });
+
+})(jQuery);
+-->
+</script>
+</div>
diff --git a/www/plugins/gis/formulaires/configurer_gis.php b/www/plugins/gis/formulaires/configurer_gis.php
new file mode 100644 (file)
index 0000000..40bdc3b
--- /dev/null
@@ -0,0 +1,33 @@
+<?php 
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Fonction de verification du formulaire de configuration
+ * - On vérifie que la clé Bing est présente si cette couche est sélectionnée
+ */
+function formulaires_configurer_gis_verifier_dist(){
+       $erreurs = array();
+       
+       if ((_request('layer_defaut') == 'bing_aerial') OR in_array('bing_aerial', _request('layers'))){
+               $obligatoire = 'api_key_bing';
+               if (!_request($obligatoire)){
+                       $erreurs[$obligatoire] = _T('info_obligatoire');
+               }
+       }
+       
+       // S'il n'y a pas d'erreur on va chercher l'ancienne couche par défaut pour voir si elle a changé
+       if (empty($erreurs)){
+               include_spip('inc/config');
+               $layer_defaut = lire_config('gis/layer_defaut');
+               // Si on change la couche par défaut ou si une couche google est présente dans la conf, le formulaire ne doit pas etre traiter en ajax
+               if ((_request('layer_defaut') != $layer_defaut)
+                       OR (count(array_intersect(array('google_roadmap', 'google_satellite', 'google_terrain'), _request('layers'))) > 0)
+                       OR (in_array('bing_aerial', _request('layers'))))
+                       refuser_traiter_formulaire_ajax();
+       }
+       
+       return $erreurs;
+}
+
+?>
diff --git a/www/plugins/gis/formulaires/editer_gis.html b/www/plugins/gis/formulaires/editer_gis.html
new file mode 100755 (executable)
index 0000000..6ff0371
--- /dev/null
@@ -0,0 +1,62 @@
+#CACHE{0}
+<div class="formulaire_spip formulaire_editer formulaire_editer_gis">
+       <!-- br class='spacer' / -->
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       <BOUCLE_editable(CONDITION){si #ENV{editable}}>
+       <form method='post' action='#ENV{action}' enctype='multipart/form-data' name='formulaire_editer_gis' id='formulaire_editer_gis'><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire 
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       [(#SAISIE{hidden,objet})]
+                       [(#SAISIE{hidden,id_objet})]
+                       [(#SAISIE{carte,editer_gis_#ENV{id_gis},env})]
+                       <li class="fieldset">
+                       <fieldset><ul>
+                               [(#SAISIE{input,lat,
+                                       label=<:gis:lat:>,
+                                       defaut=#ENV{lat,#CONFIG{gis/lat,0}},
+                                       obligatoire=oui})]
+                               [(#SAISIE{input,lon,
+                                       label=<:gis:lon:>,
+                                       defaut=#ENV{lon,#CONFIG{gis/lon,0}},
+                                       obligatoire=oui})]
+                               [(#SAISIE{input,zoom,
+                                       label=<:gis:zoom:>,
+                                       defaut=#ENV{zoom,#CONFIG{gis/zoom,0}},
+                                       size=2,
+                                       maxlength=2,
+                                       obligatoire=oui})]
+                               [(#SAISIE{input,titre,
+                                       defaut=#INFO_TITRE{#OBJET,#ID_OBJET},
+                                       label=<:info_titre:>,
+                                       obligatoire=oui})]
+                               [(#SAISIE{textarea,descriptif,
+                                       label=<:info_descriptif:>,
+                                       rows=5})]
+                       </ul></fieldset>
+                       </li>
+                       <li class="fieldset adresse"[(#CONFIG{gis/adresse}|=={on}|non) style="display: none;"]>
+                       <fieldset><ul>
+                               [(#SAISIE{input,adresse,
+                                       label=<:gis:label_adress:>})]
+                               [(#SAISIE{input,code_postal,
+                                       label=<:gis:label_code_postal:>})]
+                               [(#SAISIE{input,ville,
+                                       label=<:gis:label_ville:>})]
+                               [(#SAISIE{input,region,
+                                       label=<:gis:label_region:>})]
+                               [(#SAISIE{input,pays,
+                                       label=<:gis:label_pays:>})]
+                       </ul></fieldset>
+                       </li>
+               </ul>
+               [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
+               <!--extra-->
+               <p class='boutons'[ style="direction: (#LANG_DIR|=={ltr}|?{rtl,ltr})"]>
+                       <input class='submit' type='submit' name='enregistrer' value='<:bouton_enregistrer:>' />
+               </p>
+       </div></form>
+       </BOUCLE_editable>
+</div>
diff --git a/www/plugins/gis/formulaires/editer_gis.php b/www/plugins/gis/formulaires/editer_gis.php
new file mode 100644 (file)
index 0000000..22619dd
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Formulaire de création et d'édition d'un point géolocalisé
+ */
+
+include_spip('inc/actions');
+include_spip('inc/editer');
+
+/**
+ * Chargement des valeurs par défaut du formulaire
+ * 
+ * @param int|string $id_gis Identifiant numérique du point ou 'new' pour un nouveau
+ * @param string $objet Le type d'objet SPIP auquel il est attaché
+ * @param int $id_objet L'id_objet de l'objet auquel il est attaché
+ * @param string $retour L'url de retour
+ * @param string $ajaxload initialiser la carte à chaque onAjaxLoad()
+ * @param array $options TODO à documenter, voir avec l'auteur de http://zone.spip.org/trac/spip-zone/changeset/53906
+ */
+function formulaires_editer_gis_charger_dist($id_gis='new', $objet='', $id_objet='', $retour='', $ajaxload='oui', $options=''){
+       $valeurs = formulaires_editer_objet_charger('gis', $id_gis, '', '', $retour, '');
+       $valeurs['objet'] = $objet;
+       $valeurs['id_objet'] = $id_objet;
+       $valeurs['ajaxload'] = $ajaxload;
+    /* Traitement des options */
+       /* peut etre a envoyer dans une fonction generique de verification des options */
+       if (is_array($options)) {
+       if (!$valeurs['lat'] and is_numeric($options['lat']))
+               $valeurs['lat']=$options['lat'];
+           if (!$valeurs['lon'] and is_numeric($options['lon']))
+               $valeurs['lon']=$options['lon'];
+       if (!$valeurs['zoom'] and is_numeric($options['zoom']) && intval($options['zoom'])==$options['zoom'])
+               $valeurs['zoom']=$options['zoom'];
+               /* Bounding Box */
+           if (is_numeric($options['sw_lat']))
+               $valeurs['sw_lat']=$options['sw_lat'];
+           if (is_numeric($options['sw_lon']))
+               $valeurs['sw_lon']=$options['sw_lon'];
+           if (is_numeric($options['ne_lat']))
+               $valeurs['ne_lat']=$options['ne_lat'];
+           if (is_numeric($options['ne_lon']))
+               $valeurs['ne_lon']=$options['ne_lon'];
+       }
+       return $valeurs;
+}
+
+/**
+ * Vérification des valeurs du formulaire
+ * 
+ * 4 champs sont obligatoires :
+ * -* Son titre
+ * -* Sa latitude
+ * -* Sa longitude
+ * -* Son niveau de zoom
+ * 
+ * @param int|string $id_gis Identifiant numérique du point ou 'new' pour un nouveau
+ * @param string $objet Le type d'objet SPIP auquel il est attaché
+ * @param int $id_objet L'id_objet de l'objet auquel il est attaché
+ * @param string $retour L'url de retour
+ * @param string $ajaxload initialiser la carte à chaque onAjaxLoad()
+ * @param array $options ???
+ */
+function formulaires_editer_gis_verifier_dist($id_gis='new', $objet='', $id_objet='', $retour='', $ajaxload='oui', $options=''){
+       $erreurs = formulaires_editer_objet_verifier('gis', $id_gis,array('titre','lat','lon','zoom'));
+       return $erreurs;
+}
+
+/**
+ * Traitement des valeurs du formulaire
+ * 
+ * @param int|string $id_gis Identifiant numérique du point ou 'new' pour un nouveau
+ * @param string $objet Le type d'objet SPIP auquel il est attaché
+ * @param int $id_objet L'id_objet de l'objet auquel il est attaché
+ * @param string $retour L'url de retour
+ * @param string $ajaxload initialiser la carte à chaque onAjaxLoad()
+ * @param array $options ???
+ */
+function formulaires_editer_gis_traiter_dist($id_gis='new', $objet='', $id_objet='', $retour='', $ajaxload='oui', $options=''){
+       if (_request('supprimer')){
+               include_spip('action/editer_gis');
+               supprimer_gis($id_gis);
+               $id_table_objet = id_table_objet($objet);
+               if ($retour)
+                       $res['redirect'] = parametre_url($retour,$id_table_objet,$id_objet);
+               return $res;
+       } else {
+               return formulaires_editer_objet_traiter('gis', $id_gis, '', '', $retour, '');
+       }
+}
+
+?>
diff --git a/www/plugins/gis/formulaires/gis_inserer_modeles_traiter.php b/www/plugins/gis/formulaires/gis_inserer_modeles_traiter.php
new file mode 100644 (file)
index 0000000..0126211
--- /dev/null
@@ -0,0 +1,34 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+function formulaires_gis_inserer_modeles_traiter_dist($champs) {\r
+\r
+       // champs a ne pas prendre en compte\r
+       $ignorer = array('adresse','code_postal','ville','pays');\r
+\r
+       $code = '<'._request('modele');\r
+       if (_request('id_modele') && _request('id_modele')!='')\r
+               $code .= _request('id_modele');\r
+       if (_request('variante') && _request('variante')!='')\r
+               $code .= '|'._request('variante');\r
+       if (_request('classe') && _request('classe')!='')\r
+               $code .= '|'._request('classe');\r
+       if (_request('align') && _request('align')!='')\r
+               $code .= '|'._request('align');\r
+       foreach ($champs as $champ) {\r
+               if( !in_array($champ, $ignorer) && $champ != 'modele' && $champ != 'variante' && $champ != 'classe' && $champ != 'id_modele' && $champ != 'align' && _request($champ) && _request($champ)!='') {\r
+                       if($champ == _request($champ))\r
+                               $code .= "|$champ";\r
+                       // On transforme les tableaux en une liste\r
+                       elseif (is_array(_request($champ)))\r
+                               $code .= "|$champ=".implode(',',_request($champ));\r
+                       else\r
+                               $code .= "|$champ="._request($champ);\r
+               }\r
+       }\r
+       $code .= '>';\r
+\r
+       return $code;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/gis/formulaires/rechercher_gis.html b/www/plugins/gis/formulaires/rechercher_gis.html
new file mode 100755 (executable)
index 0000000..55409e0
--- /dev/null
@@ -0,0 +1,36 @@
+#CACHE{0}
+<BOUCLE_exclure(GIS){objet=#ENV{objet}}{id_objet=#ENV{id_objet}}{doublons objet}> </BOUCLE_exclure>
+<BOUCLE_si_recherche(CONDITION){si #ENV{recherche_gis}}>
+<B_recherche>
+       <ul class="liste_items">
+       <BOUCLE_recherche(GIS){titre LIKE %(#ENV{recherche_gis})%}{doublons objet}>#SET{id_gis,#ID_GIS}
+       #SET{ou, #LISTE{#VILLE, #PAYS}|array_filter|join{", "}}
+       [<li class="item">(#TITRE)[ ((#GET{ou}))]
+               <div class="actions">
+                       [(#BOUTON_ACTION{<:gis:bouton_lier:>,[(#URL_ACTION_AUTEUR{editer_lien_gis,lier/#GET{id_gis}/#ENV{objet}/#ENV{id_objet},#SELF})],ajax})]
+               </div>
+       </li>]
+       </BOUCLE_recherche>
+       </ul>
+</B_recherche>
+<p class="reponse_formulaire reponse_formulaire_erreur"><:gis:erreur_recherche_pas_resultats:></p>
+<//B_recherche>
+</BOUCLE_si_recherche>
+<div class="formulaire_spip formulaire_rechercher formulaire_rechercher_gis">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       <BOUCLE_si_editable(CONDITION){si #ENV{editable}}>
+       <form method='post' action='#ENV{action}' name='formulaire_rechercher_gis' id='formulaire_rechercher_gis'><div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       [(#SAISIE{input,recherche_gis,
+                               label=<:gis:label_rechercher_point:>})]
+               </ul>
+               [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
+               <!--extra-->
+               <p class='boutons'>
+                       <input class='submit' type='submit' name='enregistrer' value='<:info_rechercher:>' />
+               </p>
+       </div></form>
+       </BOUCLE_si_editable>
+</div>
diff --git a/www/plugins/gis/formulaires/rechercher_gis.php b/www/plugins/gis/formulaires/rechercher_gis.php
new file mode 100755 (executable)
index 0000000..5e1597a
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Formulaire de création et d'édition d'un point géolocalisé
+ */
+
+include_spip('inc/actions');
+include_spip('inc/editer');
+
+/**
+ * Chargement des valeurs par défaut du formulaire
+ * 
+ * @param string $objet Le type d'objet SPIP auquel il est attaché
+ * @param int $id_objet L'id_objet de l'objet auquel il est attaché
+ * @param string $retour L'url de retour
+ * @param string $recherche
+ */
+function formulaires_rechercher_gis_charger_dist($objet='', $id_objet='', $retour='', $recherche=''){
+       $valeurs['recherche_gis'] = _request('recherche_gis');
+       $valeurs['objet'] = $objet;
+       $valeurs['id_objet'] = $id_objet;
+       return $valeurs;
+}
+
+/**
+ * Vérification des valeurs du formulaire
+ * 
+ * @param string $objet Le type d'objet SPIP auquel il est attaché
+ * @param int $id_objet L'id_objet de l'objet auquel il est attaché
+ * @param string $retour L'url de retour
+ * @param string $recherche
+ */
+function formulaires_rechercher_gis_verifier_dist($objet='', $id_objet='', $retour='', $recherche=''){
+       return $erreurs;
+}
+
+/**
+ * Traitement des valeurs du formulaire
+ * 
+ * @param string $objet Le type d'objet SPIP auquel il est attaché
+ * @param int $id_objet L'id_objet de l'objet auquel il est attaché
+ * @param string $retour L'url de retour
+ * @param string $recherche
+ */
+function formulaires_rechercher_gis_traiter_dist($objet='', $id_objet='', $retour='', $recherche=''){
+       return;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/genie/gis_nettoyer_base.php b/www/plugins/gis/genie/gis_nettoyer_base.php
new file mode 100644 (file)
index 0000000..09f40f1
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+function genie_gis_nettoyer_base_dist($t){
+
+       $liens = array();
+       
+       # liens vers un article inexistant
+       if ($articles = sql_allfetsel("A.id_article,L.id_gis,L.objet,L.id_objet","spip_gis_liens AS L 
+                       INNER JOIN spip_articles AS A 
+                       ON (A.id_article = L.id_objet AND L.objet='article')",
+                       "A.id_article IS NULL")) {
+               $liens = array_merge($liens, $articles);
+       }
+                       
+       # liens vers une breve inexistante
+       if ($breves = sql_allfetsel("B.id_breve,L.id_gis,L.objet,L.id_objet","spip_gis_liens AS L 
+                       INNER JOIN spip_breves AS B 
+                       ON (B.id_breve = L.id_objet AND L.objet='breve')",
+                       "B.id_breve IS NULL")) {
+               $liens = array_merge($liens, $breves);
+       }
+       
+       foreach ($liens as $row) {
+               sql_delete("spip_gis_liens","id_gis=".$row['id_gis']." AND objet=".$row['objet']." AND id_objet=".$row['id_objet']);
+               spip_log("GIS GENIE : Suppression du lien gis ". $row['id_gis'] ." => ". $row['objet'] ." ". $row['id_objet'],"gis");
+       }
+
+       return 1;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/gis_administrations.php b/www/plugins/gis/gis_administrations.php
new file mode 100644 (file)
index 0000000..b6e2093
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Installation/maj des tables gis
+ *
+ * @param string $nom_meta_base_version
+ * @param string $version_cible
+ */
+function gis_upgrade($nom_meta_base_version, $version_cible){
+       $maj = array();
+       
+       // Première installation
+       $maj['create'] = array(
+               array('maj_tables', array('spip_gis')),
+               array('maj_tables', array('spip_gis_liens')),
+       );
+       
+       // Mise à jour depuis GIS 1
+       $maj['2.0'] = array(
+               // On ajoute la nouvelle table
+               array('maj_tables', array('spip_gis_liens')),
+               // On renomme le champ #LONX en #LON
+               array('sql_alter', 'TABLE spip_gis CHANGE lonx lon float(21) NULL NULL'),
+               // On déplace les liaisons articles, rubriques et mots
+               array('gis_upgrade_2_0'),
+               // Virer les champs id_article et id_rubrique
+               array('sql_alter', 'TABLE spip_gis DROP id_article'),
+               array('sql_alter', 'TABLE spip_gis DROP id_rubrique'),
+               // Virer les index id_article et id_rubrique
+               array('sql_alter', 'TABLE spip_gis DROP INDEX id_article'),
+               array('sql_alter', 'TABLE spip_gis DROP INDEX id_rubrique'),
+               // Virer la table pour les mots
+               array('sql_drop_table', 'spip_gis_mots'),
+       );
+       
+       // Des nouveaux champs
+       $maj['2.0.1'] = array(
+               array('maj_tables', array('spip_gis')),
+       );
+       
+       // Augmenter la précision des champs de coordonnées
+       $maj['2.0.2'] = array(
+               array('sql_alter', 'TABLE spip_gis CHANGE lat lat DOUBLE NULL NULL'),
+               array('sql_alter', 'TABLE spip_gis CHANGE lon lon DOUBLE NULL NULL'),
+       );
+       
+       include_spip('base/upgrade');
+       maj_plugin($nom_meta_base_version, $version_cible, $maj);
+}
+
+function gis_upgrade_2_0(){
+       include_spip('action/editer_gis');
+       
+       // On déplace les liaisons articles et rubriques
+       $res = sql_select('*','spip_gis');
+       while ($row = sql_fetch($res)) {
+               if($row['id_article'] != 0)
+                       lier_gis($row['id_gis'], 'article', $row['id_article']);
+               if($row['id_rubrique'] != 0)
+                       lier_gis($row['id_gis'], 'article', $row['id_rubrique']);
+       }
+       
+       // On déplace les liaisons mots
+       $res = sql_select('*','spip_gis_mots');
+       while ($row = sql_fetch($res)) {
+               $titre_mot = sql_getfetsel('titre','spip_mots','id_mot='.$row['id_mot']);
+               $c = array(
+                       'titre' => $titre_mot,
+                       'lat'=> $row['lat'],
+                       'lon' => $row['lonx'],
+                       'zoom' => $row['zoom']
+               );
+               $id_gis = insert_gis();
+               revisions_gis($id_gis,$c);
+               lier_gis($id_gis, 'mot', $row['id_mot']);
+       }
+}
+
+/**
+ * Desinstallation/suppression des tables gis
+ *
+ * @param string $nom_meta_base_version
+ */
+function gis_vider_tables($nom_meta_base_version) {
+       sql_drop_table("spip_gis");
+       sql_drop_table("spip_gis_liens");
+       effacer_meta($nom_meta_base_version);
+       // Effacer la config
+       effacer_meta('gis');
+}
+
+?>
diff --git a/www/plugins/gis/gis_autoriser.php b/www/plugins/gis/gis_autoriser.php
new file mode 100644 (file)
index 0000000..2a2c739
--- /dev/null
@@ -0,0 +1,107 @@
+<?php 
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function gis_autoriser(){};
+
+/**
+ * Autorisation a modifier le logo d'un point
+ * Si on est autorisé à modifier le point en question
+ * 
+ * @param string $faire L'action
+ * @param string $type Le type d'objet
+ * @param int $id L'identifiant numérique de l'objet
+ * @param array $qui Les informations de session de l'auteur
+ * @param array $opt Des options
+ * @return boolean true/false
+ */
+function autoriser_gis_iconifier_dist($faire,$quoi){
+       return autoriser('modifier','gis',$id,$qui,$opts);
+}
+
+/**
+ * Autorisation a modifier un point
+ * Avoir un statut dans les 3 fournis par SPIP
+ * (On n'a pas d'auteur pour un point ...)
+ * 
+ * @param string $faire L'action
+ * @param string $type Le type d'objet
+ * @param int $id L'identifiant numérique de l'objet
+ * @param array $qui Les informations de session de l'auteur
+ * @param array $opt Des options
+ * @return boolean true/false
+ */
+function autoriser_gis_modifier_dist($faire,$quoi,$id,$qui,$opts){
+       return (in_array($qui['statut'],array('0minirezo','1comite','6forum')));
+}
+
+/**
+ * Autorisation a creer un point
+ * Avoir un statut dans les 3 fournis par SPIP
+ * (On n'a pas d'auteur pour un point ...)
+ * 
+ * @param string $faire L'action
+ * @param string $type Le type d'objet
+ * @param int $id L'identifiant numérique de l'objet
+ * @param array $qui Les informations de session de l'auteur
+ * @param array $opt Des options
+ * @return boolean true/false
+ */
+function autoriser_gis_creer_dist($faire,$quoi,$id,$qui,$opts){
+       return (in_array($qui['statut'],array('0minirezo','1comite','6forum')));
+}
+
+/**
+ * Autorisation a lier un point d'un objet
+ * Un auteur peut lier un point à un autre objet que s'il peut modifier l'objet à lier en question
+ * 
+ * @param string $faire L'action
+ * @param string $type Le type d'objet
+ * @param int $id L'identifiant numérique de l'objet
+ * @param array $qui Les informations de session de l'auteur
+ * @param array $opt Des options
+ * @return boolean true/false
+ */
+function autoriser_gis_lier_dist($faire,$quoi,$id,$qui,$opts){
+       if(is_array($opts) && isset($opts['objet']) && isset($opts['id_objet'])){
+               return autoriser('modifier',$opts['objet'],$opts['id_objet'],$qui);
+       }
+       return false;
+}
+
+/**
+ * Autorisation a délier un point d'un objet
+ * Un auteur peut délier un point à un autre objet que s'il peut modifier l'objet à lier en question
+ * 
+ * @param string $faire L'action
+ * @param string $type Le type d'objet
+ * @param int $id L'identifiant numérique de l'objet
+ * @param array $qui Les informations de session de l'auteur
+ * @param array $opt Des options
+ * @return boolean true/false
+ */
+function autoriser_gis_delier_dist($faire,$quoi,$id,$qui,$opts){
+       return autoriser('lier','gis',$id,$qui,$opts);
+}
+
+/**
+ * Autorisation a supprimer un point
+ * Un auteur peut supprimer un point s'il peut délier tous les objets et modifier le point
+ * 
+ * @param string $faire L'action
+ * @param string $type Le type d'objet
+ * @param int $id L'identifiant numérique de l'objet
+ * @param array $qui Les informations de session de l'auteur
+ * @param array $opt Des options
+ * @return boolean true/false
+ */
+function autoriser_gis_supprimer_dist($faire,$quoi,$id,$qui,$opts){
+       $liaisons = sql_select('*','spip_gis_liens','id_gis='.intval($id));
+       while($liaison = sql_fetch($liaisons)){
+               if(!autoriser('delier','gis',$liaison['id_gis'],$qui,$liaison)){
+                       return false;
+               }
+       }
+       return autoriser('modifier','gis',$id,$qui,$opts);
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/gis_download.html b/www/plugins/gis/gis_download.html
new file mode 100644 (file)
index 0000000..914a7bd
--- /dev/null
@@ -0,0 +1 @@
+<BOUCLE_gis(GIS){id_gis}>[(#ENV**{format}|=={kml}|?{#HTTP_HEADER{Content-Type: application/vnd.google-earth.kml+xml;charset=#CHARSET},#HTTP_HEADER{Content-Type: application/gpx+xml;charset=#CHARSET}})][(#HTTP_HEADER{Content-Disposition: attachment; filename=#TITRE|concat{.#ENV**{format}}})][(#INCLURE{fond=inclure/download_#ENV{format},id_gis})]</BOUCLE_gis>
\ No newline at end of file
diff --git a/www/plugins/gis/gis_fonctions.php b/www/plugins/gis/gis_fonctions.php
new file mode 100755 (executable)
index 0000000..494d01c
--- /dev/null
@@ -0,0 +1,379 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+include_spip('inc/config');
+include_spip('inc/json');
+
+/** 
+ * Filtre dec_to_dms, http://www.statemaster.com/encyclopedia/Geographic-coordinate-conversion
+ * 
+ * @param decimal $coord
+ * @return string
+ */
+function dec_to_dms($coord) {
+       return sprintf(
+               "%0.0f° %2.3f",
+               floor(abs($coord)),
+               60*(abs($coord)-floor(abs($coord)))
+       );
+}
+
+/** 
+ * Filtre dms_to_dec, http://www.statemaster.com/encyclopedia/Geographic-coordinate-conversion
+ * 
+ * @param string $ref N, E, S, W
+ * @param int $deg
+ * @param int $min
+ * @param int $sec
+ * @return decimal
+ */
+function dms_to_dec($ref,$deg,$min,$sec) {
+
+       $arrLatLong = array();
+       $arrLatLong["N"] = 1;
+       $arrLatLong["E"] = 1;
+       $arrLatLong["S"] = -1;
+       $arrLatLong["W"] = -1;
+
+       return ($deg+((($min*60)+($sec))/3600)) * $arrLatLong[$ref];
+}
+
+/** 
+ * Filtre distance pour renvoyer la distance entre deux points
+ * http://snipplr.com/view/2531/calculate-the-distance-between-two-coordinates-latitude-longitude/
+ * sinon voir ici : http://zone.spip.org/trac/spip-zone/browser/_plugins_/forms/geoforms/inc/gPoint.php
+ * 
+ * @param int|array $from
+ *     id_gis du point de référence ou tableau de coordonnées
+ * @param int|array $to
+ *     id_gis du point distant ou tableau de coordonnées
+ * @param bool $miles
+ *     Renvoyer le résultat en miles (kilomètres par défaut)
+ * @return float
+ *     Retourne la distance en kilomètre ou en miles
+ */
+function distance($from, $to, $miles=false) {
+       // On ne travaille que si on a toutes les infos
+       if (
+               // Le départ est soit un tableau soit un entier
+               (
+                       (is_array($from) and isset($from['lat']) and isset($from['lon']))
+                       or
+                       ($from = intval($from) and $from > 0 and $from = sql_fetsel('lat,lon','spip_gis',"id_gis=$from"))
+               )
+               and
+               // Le distant est soit un tableau soit un entier
+               (
+                       (is_array($to) and isset($to['lat']) and isset($to['lon']))
+                       or
+                       ($to = intval($to) and $to > 0 and $to = sql_fetsel('lat,lon','spip_gis',"id_gis=$to"))
+               )
+       ){
+               $pi80 = M_PI / 180;
+               $from['lat'] *= $pi80;
+               $from['lon'] *= $pi80;
+               $to['lat'] *= $pi80;
+               $to['lon'] *= $pi80;
+
+               $r = 6372.797; // mean radius of Earth in km
+               $dlat = $to['lat'] - $from['lat'];
+               $dlng = $to['lon'] - $from['lon'];
+               $a = sin($dlat / 2) * sin($dlat / 2) + cos($from['lat']) * cos($to['lat']) * sin($dlng / 2) * sin($dlng / 2);
+               $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
+               $km = $r * $c;
+
+               return ($miles ? ($km * 0.621371192) : $km);
+       }
+       
+       return false;
+}
+
+/**
+ * Compilation du critère {distancefrom}
+ * 
+ * Critère {distancefrom} qui permet de ne sélectionner que les objets se trouvant à une distance comparée avec un point de repère.
+ * On doit lui passer 3 paramètres obligatoires :
+ * - le point de repère qui est un tableau avec les clés "lat" et "lon" ou un id_gis
+ * - l'opérateur de comparaison
+ * - la distance à comparer, en kilomètres
+ * Cela donne par exemple :
+ *   {distancefrom #ARRAY{lat,#LAT,lon,#LON},<,30}
+ *   {distancefrom #ARRAY{lat,#ENV{lat},lon,#ENV{lon}},<=,#ENV{distance}}
+ *
+ * @param unknown $idb
+ * @param unknown &$boucles
+ * @param unknown $crit
+ */
+function critere_distancefrom_dist($idb, &$boucles, $crit) {
+       $boucle = &$boucles[$idb];
+       $id_table = $boucle->id_table; // articles
+       $primary = $boucle->primary; // id_article
+       $objet = objet_type($id_table); // article
+       
+       if (
+               // Soit depuis une boucle (GIS) soit un autre objet mais avec {gis}
+               ($id_table == 'gis' or isset($boucle->join['gis']))
+               // Il faut aussi qu'il y ait 3 critères obligatoires
+               and count($crit->param) == 3
+       ){
+               $point_reference = calculer_liste($crit->param[0], array(), $boucles, $boucles[$idb]->id_parent);
+               $operateur = calculer_liste($crit->param[1], array(), $boucles, $boucles[$idb]->id_parent);
+               $distance = calculer_liste($crit->param[2], array(), $boucles, $boucles[$idb]->id_parent);
+
+               // Si le point de référence est un entier, on essaye de récupérer les coordonnées du point GIS
+               // Et si on a toujours pas de tableau correct, on met false
+               $boucle->hierarchie .= '$point_reference = '.$point_reference.';';
+               $boucle->hierarchie .= 'if (is_numeric($point_reference)){ $point_reference = sql_fetsel("lat,lon", "spip_gis", "id_gis = ".intval($point_reference)); }';
+               $boucle->hierarchie .= 'if (!is_array($point_reference) or !isset($point_reference["lat"]) or !isset($point_reference["lon"])){ $point_reference = false; }';
+               // L'opérateur doit exister dans une liste précise
+               $boucle->hierarchie .= '$operateur_distance = trim('.$operateur.');';
+               $boucle->hierarchie .= 'if (!in_array($operateur_distance, array("=","<",">","<=",">="))){ $operateur_distance = false; }';
+               $boucle->hierarchie .= '$distance = '.$distance.';';
+               
+               $boucle->select[] = '".(!$point_reference ? "\'\' as distance" : "(6371 * acos( cos( radians(".$point_reference["lat"].") ) * cos( radians( gis.lat ) ) * cos( radians( gis.lon ) - radians(".$point_reference["lon"].") ) + sin( radians(".$point_reference["lat"].") ) * sin( radians( gis.lat ) ) ) ) AS distance")."';
+               $boucle->having[] = '((!$point_reference or !$operateur_distance or !$distance) ? "1=1" : "distance $operateur_distance ".sql_quote($distance))';
+       }
+}
+
+/**
+ * Critere {gis distance<XX} pour filtrer une liste de points par rapport à la distance du point de l'env
+ *
+ * @param unknown_type $idb
+ * @param unknown_type $boucles
+ * @param unknown_type $crit
+ */
+function critere_gis_dist($idb, &$boucles, $crit) {
+       $boucle = &$boucles[$idb];
+       $id_table = $boucle->id_table; // articles
+       $primary = $boucle->primary; // id_article
+       $objet = objet_type($id_table); // article
+       
+       if ($id_table == 'gis') {
+               // exclure l'élément en cours des résultats
+               $id_gis = calculer_argument_precedent($idb,$primary, $boucles);
+               $boucle->where[]= array("'!='", "'$boucle->id_table." . "$primary'", $id_gis);
+               
+               // récupérer les paramètres du critère
+               $op='';
+               $params = $crit->param;
+               $type = array_shift($params);
+               $type = $type[0]->texte;
+               if(preg_match(',^(\w+)([<>=]+)([0-9]+)$,',$type,$r)){
+                       $type=$r[1];
+                       $op=$r[2];
+                       $op_val=$r[3];
+               }
+               if ($op)
+                       $boucle->having[]= array("'".$op."'", "'".$type."'",$op_val);
+               
+               // récupérer lat/lon du point de la boucle englobante
+               $lat = calculer_argument_precedent($idb,'lat', $boucles);
+               $lon = calculer_argument_precedent($idb,'lon', $boucles);
+               
+               // http://www.awelty.fr/developpement-web/php/
+               // http://www.movable-type.co.uk/scripts/latlong-db.html
+               // http://code.google.com/intl/fr/apis/maps/articles/geospatial.html#geospatial
+               $select = "(6371 * acos( cos( radians(\".$lat.\") ) * cos( radians( gis.lat ) ) * cos( radians( gis.lon ) - radians(\".$lon.\") ) + sin( radians(\".$lat.\") ) * sin( radians( gis.lat ) ) ) ) AS distance";
+               $order = "'distance'";
+               
+               $boucle->select[]= $select;
+               $boucle->order[]= $order;
+       } else {
+               // ajouter tous les champs du point au select 
+               // et les suffixer pour lever toute ambiguite avec des champs homonymes
+               $boucle->select[]= 'gis.titre AS titre_gis';
+               $boucle->select[]= 'gis.descriptif AS descriptif_gis';
+               $boucle->select[]= 'gis.adresse AS adresse_gis';
+               $boucle->select[]= 'gis.pays AS pays_gis';
+               $boucle->select[]= 'gis.code_pays AS code_pays_gis';
+               $boucle->select[]= 'gis.region AS region_gis';
+               $boucle->select[]= 'gis.ville AS ville_gis';
+               $boucle->select[]= 'gis.code_postal AS code_postal_gis';
+               // jointure sur spip_gis_liens/spip_gis
+               // cf plugin notation
+               // $boucle->join["surnom (as) table de liaison"] = array("surnom de la table a lier", "cle primaire de la table de liaison", "identifiant a lier", "type d'objet de l'identifiant");
+               $boucle->from['gis_liens'] = 'spip_gis_liens';
+               $boucle->join['gis_liens']= array("'$id_table'","'id_objet'","'$primary'","'gis_liens.objet='.sql_quote('$objet')");
+               $boucle->from['gis'] = 'spip_gis';
+               $boucle->join['gis']= array("'gis_liens'","'id_gis'");
+               // bien renvoyer tous les points qui son attachés à l'objet
+               // mais attention, si on trouve en amont un groupement portant sur un champ *de GIS*,
+               // alors cela signifie que la personne veut faire une opération de groupement sur les points donc là on n'ajoute pas id_gis
+               $tous_les_points = true;
+               foreach ($boucle->group as $champ){
+                       if (in_array($champ, array('ville', 'code_postal', 'pays', 'code_pays', 'region'))) {
+                               $tous_les_points = false;
+                       }
+               }
+               if ($tous_les_points) {
+                       $boucle->group[] = 'gis_liens.id_gis';
+               }
+               // ajouter gis aux jointures et spécifier les jointures explicites pour pouvoir utiliser les balises de la table de jointure
+               // permet de passer dans trouver_champ_exterieur() depuis index_tables_en_pile()
+               // cf http://article.gmane.org/gmane.comp.web.spip.zone/6628
+               $boucle->jointures[] = 'gis';
+               if (empty($boucle->jointures_explicites)){
+                       $boucle->jointures_explicites = 'gis_liens gis';
+               }
+               else{
+                       $boucle->jointures_explicites .= ' gis_liens gis';
+               }
+       }
+}
+
+/**
+ * Balise #DISTANCE issue du critère {gis distance<XX}
+ * merci marcimant : http://formation.magraine.net/spip.php?article61
+ *
+ * @param unknown_type $p
+ */
+function balise_distance_dist($p) {
+       return rindex_pile($p, 'distance', 'gis');
+}
+
+/**
+ * Balise #TITRE_GIS : retourne le titre du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_titre_gis_dist($p) {
+       return rindex_pile($p, 'titre_gis', 'gis');
+}
+
+/**
+ * Balise #DESCRIPTIF_GIS : retourne le descriptif du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_descriptif_gis_dist($p) {
+       return rindex_pile($p, 'descriptif_gis', 'gis');
+}
+
+/**
+ * Balise #ADRESSE_GIS : retourne l'adresse du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_adresse_gis_dist($p) {
+       return rindex_pile($p, 'adresse_gis', 'gis');
+}
+
+/**
+ * Balise #PAYS_GIS : retourne le pays du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_pays_gis_dist($p) {
+       return rindex_pile($p, 'pays_gis', 'gis');
+}
+
+/**
+ * Balise #CODE_PAYS_GIS : retourne le code pays du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_code_pays_gis_dist($p) {
+       return rindex_pile($p, 'code_pays_gis', 'gis');
+}
+
+/**
+ * Balise #VILLE_GIS : retourne la ville du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_ville_gis_dist($p) {
+       return rindex_pile($p, 'ville_gis', 'gis');
+}
+
+/**
+ * Balise #REGION_GIS : retourne la région du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_region_gis_dist($p) {
+       return rindex_pile($p, 'region_gis', 'gis');
+}
+
+/**
+ * Balise #CODE_POSTAL_GIS : retourne le code postal du point
+ * Necessite le critere {gis} sur la boucle
+ *
+ * @param unknown_type $p
+ */
+function balise_code_postal_gis_dist($p) {
+       return rindex_pile($p, 'code_postal_gis', 'gis');
+}
+
+/**
+ * Définition du fond de carte à utiliser par défaut en prenant compte les defines
+ */
+function gis_layer_defaut(){
+       $defaut = 'openstreetmap_mapnik';
+       if(defined('_GIS_LAYER_DEFAUT_FORCE')){
+               return _GIS_LAYER_DEFAUT_FORCE;
+       }else{
+               if(defined('_GIS_LAYER_DEFAUT')){
+                       $defaut = _GIS_LAYER_DEFAUT;
+               }
+               $config = lire_config('gis/layer_defaut');
+               return $config ? $config : $defaut;
+       }
+}
+
+/**
+ * Recuperer les cles primaires du env pour l'appel a l'url json des points
+ * @param $env
+ * @return array
+ */
+function gis_modele_url_json_env($env){
+       $contexte = array();
+       if (is_string($env))
+               $env = unserialize($env);
+       if ($env){
+               // d'abord toutes les cles primaires connues
+               $tables_sql = lister_tables_objets_sql();
+               foreach (array_keys($tables_sql) as $table){
+                       $primary = id_table_objet($table);
+                       if (isset($env[$primary]))
+                               $contexte[$primary] = $env[$primary];
+               }
+               // puis cas particuliers
+               $keys = array("id_objet","id_secteur","id_parent","media","recherche","mots");
+               foreach ($keys as $key){
+                       if (isset($env[$key]))
+                               $contexte[$key] = $env[$key];
+               }
+       }
+       return $contexte;
+}
+
+/**
+ * Transformer le tableau de kml en tableau d'urls :
+ *   si numerique c'est un id de document
+ *   si chaine c'est une url qu'on rapatrie en local
+ * @param array $kml
+ * @return array
+ */
+function gis_kml_to_urls($kml){
+       if ($kml AND count($kml)){
+               include_spip("inc/filtres_mini");
+               include_spip("inc/distant");
+               foreach($kml as $k=>$v){
+                       if (is_numeric($v)){
+                               $kml[$k] = url_absolue(generer_url_entite($v,"document"));
+                       }
+                       else
+                               $kml[$k] = _DIR_RACINE.copie_locale($kml[$k]);
+               }
+       }
+       return $kml;
+}
+?>
diff --git a/www/plugins/gis/gis_json.html b/www/plugins/gis/gis_json.html
new file mode 100644 (file)
index 0000000..ab7370c
--- /dev/null
@@ -0,0 +1,6 @@
+#HTTP_HEADER{Content-Type: application/json; charset=#CHARSET}
+{"type": "FeatureCollection",
+       "features": [
+               [(#INCLURE{fond=json/gis[_(#ENV{objets})],env})]
+       ]
+}
diff --git a/www/plugins/gis/gis_kml.html b/www/plugins/gis/gis_kml.html
new file mode 100755 (executable)
index 0000000..28e2934
--- /dev/null
@@ -0,0 +1,13 @@
+#HTTP_HEADER{Content-Type: application/vnd.google-earth.kml+xml;charset=#CHARSET}[(#ENV**{dl}
+|?{#HTTP_HEADER{Content-Disposition: attachment; filename=#CONFIG{gis/nom_fichier_kml}|sinon{gis}|concat{.kml}},''})]<?xml 
+version="1.0" encoding="#CHARSET" ?>
+<kml xmlns="http://www.opengis.net/kml/2.2"
+       xmlns:atom="http://www.w3.org/2005/Atom">
+<Document>
+[<name>(#NOM_SITE_SPIP|texte_backend)</name>]
+[<description>(#DESCRIPTIF_SITE_SPIP|supprimer_tags|texte_backend)</description>]
+<BOUCLE_gis(GIS gis_liens){id_gis ?}{id_rubrique ?}{id_article ?}{id_breve ?}{id_document ?}{id_mot ?}{id_auteur ?}{id_syndic ?}{recherche ?}{0, #ENV{limit,500}}>
+       [(#INCLURE{fond=inclure/kml-item,id_gis,objet,id_objet})]
+</BOUCLE_gis>
+</Document>
+</kml>
\ No newline at end of file
diff --git a/www/plugins/gis/gis_options.php b/www/plugins/gis/gis_options.php
new file mode 100755 (executable)
index 0000000..730774c
--- /dev/null
@@ -0,0 +1,155 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+define('_DIR_LIB_GIS','lib/leaflet-gis-4.8.7/');
+
+$GLOBALS['logo_libelles']['id_gis'] = _T('gis:libelle_logo_gis');
+
+$config = @unserialize($GLOBALS['meta']['gis']);
+
+$GLOBALS['gis_layers'] = array (
+       'openstreetmap_mapnik' => array(
+               'nom' => 'OpenStreetMap',
+               'layer' => 'L.tileLayer.provider("OpenStreetMap")'
+       ),
+       'openstreetmap_blackandwhite' => array(
+               'nom' => 'OpenStreetMap Black and White',
+               'layer' => 'L.tileLayer.provider("OpenStreetMap.BlackAndWhite")'
+       ),
+       'openstreetmap_de' => array(
+               'nom' => 'OpenStreetMap DE',
+               'layer' => 'L.tileLayer.provider("OpenStreetMap.DE")'
+       ),
+       'google_roadmap' => array(
+               'nom' => 'Google Roadmap',
+               'layer' => 'L.Google("ROADMAP")'
+       ),
+       'google_satellite' => array(
+               'nom' => 'Google Satelitte',
+               'layer' => 'L.Google("SATELLITE")'
+       ),
+       'google_terrain' => array(
+               'nom' => 'Google Terrain',
+               'layer' => 'L.Google("TERRAIN")'
+       ),
+       'bing_aerial' => array(
+               'nom' => 'Bing Aerial',
+               'layer' => 'L.BingLayer("'.$config['api_key_bing'].'")'
+       ),
+       'thunderforest_opencyclemap' => array(
+               'nom' => 'Thunderforest OpenCycleMap',
+               'layer' => 'L.tileLayer.provider("Thunderforest.OpenCycleMap")'
+       ),
+       'thunderforest_transport' => array(
+               'nom' => 'Thunderforest Transport',
+               'layer' => 'L.tileLayer.provider("Thunderforest.Transport")'
+       ),
+       'thunderforest_landscape' => array(
+               'nom' => 'Thunderforest Landscape',
+               'layer' => 'L.tileLayer.provider("Thunderforest.Landscape")'
+       ),
+       'thunderforest_outdoors' => array(
+               'nom' => 'Thunderforest Outdoors',
+               'layer' => 'L.tileLayer.provider("Thunderforest.Outdoors")'
+       ),
+       'openmapsurfer' => array(
+               'nom' => 'OpenMapSurfer',
+               'layer' => 'L.tileLayer.provider("OpenMapSurfer")'
+       ),
+       'openmapsurfer_grayscale' => array(
+               'nom' => 'OpenMapSurfer Grayscale',
+               'layer' => 'L.tileLayer.provider("OpenMapSurfer.Grayscale")'
+       ),
+       'mapquestopen_osm' => array(
+               'nom' => 'Mapquest Open',
+               'layer' => 'L.tileLayer.provider("MapQuestOpen.OSM")'
+       ),
+       'mapquestopen_aerial' => array(
+               'nom' => 'Mapquest Open Aerial',
+               'layer' => 'L.tileLayer.provider("MapQuestOpen.Aerial")'
+       ),
+       'stamen_toner' => array(
+               'nom' => 'Stamen Toner',
+               'layer' => 'L.tileLayer.provider("Stamen.Toner")'
+       ),
+       'stamen_tonerlite' => array(
+               'nom' => 'Stamen Toner Lite',
+               'layer' => 'L.tileLayer.provider("Stamen.TonerLite")'
+       ),
+       'stamen_terrain' => array(
+               'nom' => 'Stamen Terrain',
+               'layer' => 'L.tileLayer.provider("Stamen.Terrain")'
+       ),
+       'stamen_watercolor' => array(
+               'nom' => 'Stamen Watercolor',
+               'layer' => 'L.tileLayer.provider("Stamen.Watercolor")'
+       ),
+       'esri_worldstreetmap' => array(
+               'nom' => 'Esri WorldStreetMap',
+               'layer' => 'L.tileLayer.provider("Esri.WorldStreetMap")'
+       ),
+       'esri_delorme' => array(
+               'nom' => 'Esri DeLorme',
+               'layer' => 'L.tileLayer.provider("Esri.DeLorme")'
+       ),
+       'esri_worldtopomap' => array(
+               'nom' => 'Esri WorldTopoMap',
+               'layer' => 'L.tileLayer.provider("Esri.WorldTopoMap")'
+       ),
+       'esri_worldimagery' => array(
+               'nom' => 'Esri WorldImagery',
+               'layer' => 'L.tileLayer.provider("Esri.WorldImagery")'
+       ),
+       'esri_worldterrain' => array(
+               'nom' => 'Esri WorldTerrain',
+               'layer' => 'L.tileLayer.provider("Esri.WorldTerrain")'
+       ),
+       'esri_worldshadedrelief' => array(
+               'nom' => 'Esri WorldShadedRelief',
+               'layer' => 'L.tileLayer.provider("Esri.WorldShadedRelief")'
+       ),
+       'esri_worldphysical' => array(
+               'nom' => 'Esri WorldPhysical',
+               'layer' => 'L.tileLayer.provider("Esri.WorldPhysical")'
+       ),
+       
+       'esri_oceanbasemap' => array(
+               'nom' => 'Esri OceanBasemap',
+               'layer' => 'L.tileLayer.provider("Esri.OceanBasemap")'
+       ),
+       'esri_natgeoworldmap' => array(
+               'nom' => 'Esri NatGeoWorldMap',
+               'layer' => 'L.tileLayer.provider("Esri.NatGeoWorldMap")'
+       ),
+       'esri_worldgraycanvas' => array(
+               'nom' => 'Esri WorldGrayCanvas',
+               'layer' => 'L.tileLayer.provider("Esri.WorldGrayCanvas")'
+       ),
+       'nokia_normalday' => array(
+               'nom' => 'Nokia normalDay',
+               'layer' => 'L.tileLayer.provider("Nokia.normalDay")'
+       ),
+       'nokia_normalgreyday' => array(
+               'nom' => 'Nokia normalGreyDay',
+               'layer' => 'L.tileLayer.provider("Nokia.normalGreyDay")'
+       ),
+       'nokia_satellitenolabelsday' => array(
+               'nom' => 'Nokia satelliteNoLabelsDay',
+               'layer' => 'L.tileLayer.provider("Nokia.satelliteNoLabelsDay")'
+       ),
+       'nokia_satelliteyeslabelsday' => array(
+               'nom' => 'Nokia satelliteYesLabelsDay',
+               'layer' => 'L.tileLayer.provider("Nokia.satelliteYesLabelsDay")'
+       ),
+       'nokia_terrainday' => array(
+               'nom' => 'Nokia terrainDay',
+               'layer' => 'L.tileLayer.provider("Nokia.terrainDay")'
+       ),
+       'acetate' => array(
+               'nom' => 'Acetate',
+               'layer' => 'L.tileLayer.provider("Acetate.all")'
+       ),
+);
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/gis_pipelines.php b/www/plugins/gis/gis_pipelines.php
new file mode 100755 (executable)
index 0000000..5259a55
--- /dev/null
@@ -0,0 +1,320 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Insertion des css du plugin dans les pages publiques
+ *
+ * @param $flux
+ * @return mixed
+ */
+function gis_insert_head_css($flux){
+       $flux .="\n".'<link rel="stylesheet" href="'. find_in_path(_DIR_LIB_GIS.'dist/leaflet.css') .'" />';
+       $flux .="\n".'<!--[if lte IE 8]> <link rel="stylesheet" href="'. find_in_path(_DIR_LIB_GIS.'dist/leaflet.ie.css') .'" /> <![endif]-->';
+       $flux .="\n".'<link rel="stylesheet" href="'. find_in_path(_DIR_LIB_GIS.'plugins/leaflet-plugins.css') .'" />';
+       $flux .="\n".'<link rel="stylesheet" href="'. sinon(find_in_path('css/leaflet.markercluster.css'),find_in_path(_DIR_LIB_GIS.'plugins/leaflet.markercluster.css')) .'" />';
+       $flux .="\n".'<!--[if lte IE 8]><link rel="stylesheet" href="'. sinon(find_in_path('css/leaflet.markercluster.ie.css'),find_in_path(_DIR_LIB_GIS.'plugins/leaflet.markercluster.ie.css')) .'" /><![endif]-->';
+       return $flux;
+}
+
+/**
+ * Insertion des scripts du plugin dans les pages publiques
+ *
+ * @param $flux
+ * @return mixed
+ */
+function gis_insert_head($flux){
+       
+       // initialisation des valeurs de config
+       $config = @unserialize($GLOBALS['meta']['gis']);
+       if (!is_array($config['layers']))
+               $config['layers'] = array('openstreetmap_mapnik');
+       
+       include_spip('gis_fonctions');
+       if (!in_array(gis_layer_defaut(),$config['layers']))
+               $config['layers'][] = gis_layer_defaut();
+       
+       // insertion des scripts pour google si nécessaire
+       if (count(array_intersect(array('google_roadmap', 'google_satellite', 'google_terrain'), $config['layers'])) > 0) {
+               $flux .="\n".'<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false&amp;language='.$GLOBALS['spip_lang'].'"></script>';
+       }
+       
+       return $flux;
+}
+
+/**
+ * Insertion des scripts et css du plugin dans les pages de l'espace privé
+ * @param $flux
+ * @return mixed
+ */
+function gis_header_prive($flux){
+       $flux .= gis_insert_head_css('');
+       $flux .= gis_insert_head('');
+       return $flux;
+}
+
+function gis_afficher_contenu_objet($flux){
+       if ($objet = $flux['args']['type']
+               and include_spip('inc/config')
+               and in_array(table_objet_sql($objet), lire_config('gis/gis_objets', array()))
+               and ($id = intval($flux['args']['id_objet']))
+               
+       ){
+               // TODO : seulement si la conf permet de geolocaliser cet objet
+               // -> ajouter un element a la array suivante (qqch comme ca - voir les mots):
+               //   'editable'=>autoriser('associergis',$type,$id)?'oui':'non'
+               $texte = recuperer_fond(
+                       'prive/contenu/gis_objet',
+                       array(
+                               'table_source'=>'gis',
+                               'objet'=>$objet,
+                               'id_objet'=>$id
+                       )
+               );
+               $flux['data'] .= $texte;
+       }
+       
+       return $flux;
+}
+
+function gis_post_edition($flux){
+       
+       if (($flux['args']['operation'] == 'ajouter_document') 
+               AND ($document = sql_fetsel("*","spip_documents","id_document=".intval($flux['args']['id_objet'])))
+       ) {
+               if(in_array($document['extension'],array('jpg','kml','kmz'))){
+                       $config = @unserialize($GLOBALS['meta']['gis']);
+                       if(!is_array($config))
+                               $config = array();
+                       include_spip('inc/documents');
+                       $fichier = get_spip_doc($document['fichier']);
+                       $id_document = $document['id_document'];
+               }
+               if ($document['extension'] == 'jpg') {
+                       // on recupere les coords definies dans les exif du document s'il y en a
+                       if ($exifs =  @exif_read_data($fichier,'GPS')) {
+                               if(!function_exists('dms_to_dec'))
+                                       include_spip('gis_fonctions');
+                               spip_log("GIS EXIFS : Récuperation des coordonnees du fichier $fichier","gis");
+                               
+                               $LatDeg = explode("/",$exifs["GPSLatitude"][0]);
+                               if(is_numeric($LatDeg[1]) > 0)
+                                       $intLatDeg = $LatDeg[0]/$LatDeg[1];
+
+                               $LatMin = explode("/",$exifs["GPSLatitude"][1]);
+                               if(is_numeric($LatMin[1]) > 0)
+                                       $intLatMin = $LatMin[0]/$LatMin[1];
+
+                               $LatSec = explode("/",$exifs["GPSLatitude"][2]);
+                               if(is_numeric($LatSec[1]) > 0)
+                                       $intLatSec = $LatSec[0]/$LatSec[1];
+
+                               $LongDeg = explode("/",$exifs["GPSLongitude"][0]);
+                               if(is_numeric($LongDeg[1]) > 0)
+                                       $intLongDeg = $LongDeg[0]/$LongDeg[1];
+
+                               $LongMin = explode("/",$exifs["GPSLongitude"][1]);
+                               if(is_numeric($LongMin[1]) > 0)
+                                       $intLongMin = $LongMin[0]/$LongMin[1];
+
+                               $LongSec = explode("/",$exifs["GPSLongitude"][2]);
+                               if(is_numeric($LongSec[1]) > 0)
+                                       $intLongSec = $LongSec[0]/$LongSec[1];
+
+                               // round to 5 = approximately 1 meter accuracy
+                               if(is_numeric($intLatDeg) && is_numeric($intLatMin) && is_numeric($intLatSec))
+                                       $latitude = round(dms_to_dec($exifs["GPSLatitudeRef"],
+                                               $intLatDeg,$intLatMin,$intLatSec),5);
+
+                               if(is_numeric($intLongDeg) && is_numeric($intLongMin) && is_numeric($intLongSec))
+                                       $longitude =  round(dms_to_dec($exifs["GPSLongitudeRef"],
+                                               $intLongDeg,$intLongMin,$intLongSec), 5);
+                               if($config['geocoder'] == 'on'){
+                                       include_spip('inc/xml');
+                                       $url_geocoder = 'http://maps.googleapis.com/maps/api/geocode/xml?latlng='.urlencode($latitude).','.urlencode($longitude).'&sensor=true';
+                                       $geocoder = spip_xml_load($url_geocoder);
+                                       spip_xml_match_nodes(',result,',$geocoder,$matches_adress);
+                                       if(is_array($matches_adress['result'])){
+                                               foreach($matches_adress['result'] as $component){
+                                                       if(in_array('country',$component['type'])){
+                                                               $pays = $component['address_component'][0]['long_name'][0];
+                                                               $code_pays = $component['address_component'][0]['short_name'][0];
+                                                       }
+                                                       if(in_array('administrative_area_level_1',$component['type'])){
+                                                               $region = $component['address_component'][0]['long_name'][0];
+                                                       }
+                                                       if(in_array('locality',$component['type'])){
+                                                               $ville = $component['address_component'][0]['long_name'][0];
+                                                       }
+                                                       if(in_array('postal_code',$component['type'])){
+                                                               $code_postal = $component['address_component'][0]['long_name'][0];
+                                                       }
+                                                       if(in_array('route',$component['type'])){
+                                                               $adresse = $component['address_component'][0]['long_name'][0];
+                                                       }
+                                               }
+                                       }
+                               }
+                       }else if(file_exists($fichier)){
+                               include_spip("inc/iptc");
+
+                               $er = new class_IPTC($fichier);
+                               $iptc = $er->fct_lireIPTC();
+                               $codesiptc = $er->h_codesIptc;
+                               $string_recherche = '';
+                               
+                               if($iptc['city']){
+                                       $string_recherche .= $iptc['city'].', ';
+                               }
+                               if($iptc['provinceState']){
+                                       $string_recherche .= $iptc['provinceState'].', ';
+                               }
+                               if($iptc['country']){
+                                       $string_recherche .= $iptc['country'];
+                               }
+                               if(strlen($string_recherche)){
+                                       include_spip('inc/xml');
+                                       $url_geocoder = 'http://maps.googleapis.com/maps/api/geocode/xml?address='.urlencode($string_recherche).'&sensor=true';
+                                       $geocoder = spip_xml_load($url_geocoder);
+                                       if(is_array($geocoder)){
+                                               spip_xml_match_nodes(',location,',$geocoder,$matches);
+                                               $latitude = $matches['location']['0']['lat']['0'];
+                                               $longitude = $matches['location']['0']['lng']['0'];
+                                               if($config['adresse'] == 'on'){
+                                                       spip_xml_match_nodes(',address_component,',$geocoder,$matches_adress);
+                                                       if(is_array($matches_adress['address_component'])){
+                                                               foreach($matches_adress['address_component'] as $component){
+                                                                       if(in_array('country',$component['type'])){
+                                                                               $pays = $component['long_name'][0];
+                                                                               $code_pays = $component['short_name'][0];
+                                                                       }
+                                                                       if(in_array('administrative_area_level_1',$component['type'])){
+                                                                               $region = $component['long_name'][0];
+                                                                       }
+                                                                       if(in_array('locality',$component['type'])){
+                                                                               $ville = $component['long_name'][0];
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       if(is_numeric($latitude) && is_numeric($longitude)){
+                               $c = array(
+                                       'titre' => basename($fichier),
+                                       'lat'=> $latitude,
+                                       'lon' => $longitude,
+                                       'zoom' => $config['zoom'] ? $config['zoom'] :'4',
+                                       'adresse' => $adresse,
+                                       'code_postal' => $code_postal,
+                                       'ville' => $ville,
+                                       'region' => $region,
+                                       'pays' => $pays,
+                                       'code_pays' => $code_pays
+                               );
+                               
+                               if (defined('_DIR_PLUGIN_GISGEOM')) {
+                                       $geojson = '{"type":"Point","coordinates":['.$longitude.','.$latitude.']}';
+                                       set_request('geojson',$geojson);
+                               }
+                               
+                               include_spip('action/editer_gis');
+       
+                               if($id_gis = sql_getfetsel("G.id_gis","spip_gis AS G LEFT  JOIN spip_gis_liens AS T ON T.id_gis=G.id_gis ","T.id_objet=" . intval($id_document) . " AND T.objet='document'")){
+                                       // Des coordonnées sont déjà définies pour ce document => on les update
+                                       revisions_gis($id_gis,$c);
+                                       spip_log("GIS EXIFS : Update des coordonnées depuis EXIFS pour le document $id_document => id_gis = $id_gis","gis");
+                               }
+                               else{
+                                       // Aucune coordonnée n'est définie pour ce document  => on les crées
+                                       $id_gis = insert_gis();
+                                       revisions_gis($id_gis,$c);
+                                       lier_gis($id_gis, 'document', $id_document);
+                                       spip_log("GIS EXIFS : Création des coordonnées depuis EXIFS pour le document $id_document => id_gis = $id_gis","gis");
+                               }
+                       }
+               }elseif(in_array($document['extension'],array('kml','kmz','gpx'))){
+                       $recuperer_info = charger_fonction('kml_infos','inc');
+                       $infos = $recuperer_info($document['id_document']);
+                       if($infos){
+                               if(is_numeric($latitude = $infos['latitude']) && is_numeric($longitude = $infos['longitude'])){
+                                       $c = array(
+                                               'titre' => $infos['titre'] ? $infos['titre'] : basename($fichier),
+                                               'descriptif' => $infos['descriptif'],
+                                               'lat'=> $latitude,
+                                               'lon' => $longitude,
+                                               'zoom' => $config['zoom'] ? $config['zoom'] :'4'
+                                       );
+                       
+                                       include_spip('action/editer_gis');
+               
+                                       if($id_gis = sql_getfetsel("G.id_gis","spip_gis AS G LEFT  JOIN spip_gis_liens AS T ON T.id_gis=G.id_gis ","T.id_objet=" . intval($id_document) . " AND T.objet='document'")){
+                                               // Des coordonnées sont déjà définies pour ce document => on les update
+                                               revisions_gis($id_gis,$c);
+                                               spip_log("GIS EXIFS : Update des coordonnées depuis EXIFS pour le document $id_document => id_gis = $id_gis","gis");
+                                       }
+                                       else{
+                                               // Aucune coordonnée n'est définie pour ce document  => on les crées
+                                               $id_gis = insert_gis();
+                                               revisions_gis($id_gis,$c);
+                                               lier_gis($id_gis, 'document', $id_document);
+                                               spip_log("GIS EXIFS : Création des coordonnées depuis EXIFS pour le document $id_document => id_gis = $id_gis","gis");
+                                       }
+                               }
+                               unset($infos['longitude']);
+                               unset($infos['latitude']);
+                               if(count($infos) > 0){
+                                       include_spip('action/editer_document');
+                                       document_modifier($id_document, $infos);
+                               }
+                       }
+               }
+       }
+       if (($flux['args']['operation'] == 'supprimer_document') 
+               AND ($id_document = intval($flux['args']['id_objet'])
+               AND ($id_gis = sql_getfetsel("G.id_gis","spip_gis AS G LEFT  JOIN spip_gis_liens AS T ON T.id_gis=G.id_gis ","T.id_objet=" . intval($id_document) . " AND T.objet='document'")))
+       ) {
+               include_spip('action/editer_gis');
+               supprimer_gis($id_gis);
+               spip_log("GIS EXIFS : Suppression des coordonnées pour le document $id_document => id_gis = $id_gis","gis");
+       }
+       
+       return $flux;
+}
+
+function gis_taches_generales_cron($taches_generales){
+       $taches_generales['gis_nettoyer_base'] = 3600*48;
+       return $taches_generales;
+}
+
+function gis_saisies_autonomes($flux){
+       $flux[] = 'carte';
+       return $flux;
+}
+
+/**
+ * Insertion dans le pipeline xmlrpc_methodes (xmlrpc)
+ * Ajout de méthodes xml-rpc spécifiques à GIS
+ * 
+ * @param array $flux : un array des methodes déjà présentes, fonctionnant sous la forme :
+ * -* clé = nom de la méthode;
+ * -* valeur = le nom de la fonction à appeler;
+ * @return array $flux : l'array complété avec nos nouvelles méthodes 
+ */
+function gis_xmlrpc_methodes($flux){
+       $flux['spip.liste_gis'] = 'spip_liste_gis';
+       $flux['spip.lire_gis'] = 'spip_lire_gis';
+       return $flux;
+}
+
+/**
+ * Insertion dans le pipeline xmlrpc_server_class (xmlrpc)
+ * Ajout de fonctions spécifiques utilisés par le serveur xml-rpc 
+ */
+function gis_xmlrpc_server_class($flux){
+       include_spip('inc/gis_xmlrpc');
+       return $flux;
+}
+
+?>
diff --git a/www/plugins/gis/icones_barre/gis.png b/www/plugins/gis/icones_barre/gis.png
new file mode 100644 (file)
index 0000000..b0e5a4c
Binary files /dev/null and b/www/plugins/gis/icones_barre/gis.png differ
diff --git a/www/plugins/gis/images/gis-16.png b/www/plugins/gis/images/gis-16.png
new file mode 100644 (file)
index 0000000..b0e5a4c
Binary files /dev/null and b/www/plugins/gis/images/gis-16.png differ
diff --git a/www/plugins/gis/images/gis-24.png b/www/plugins/gis/images/gis-24.png
new file mode 100755 (executable)
index 0000000..6cb9f54
Binary files /dev/null and b/www/plugins/gis/images/gis-24.png differ
diff --git a/www/plugins/gis/images/gis.png b/www/plugins/gis/images/gis.png
new file mode 100755 (executable)
index 0000000..8f867fc
Binary files /dev/null and b/www/plugins/gis/images/gis.png differ
diff --git a/www/plugins/gis/images/marker.png b/www/plugins/gis/images/marker.png
new file mode 100644 (file)
index 0000000..c05d02c
Binary files /dev/null and b/www/plugins/gis/images/marker.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/blank.gif b/www/plugins/gis/images/openlayers/dark/blank.gif
new file mode 100644 (file)
index 0000000..2799b45
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/blank.gif differ
diff --git a/www/plugins/gis/images/openlayers/dark/cloud-popup-relative.png b/www/plugins/gis/images/openlayers/dark/cloud-popup-relative.png
new file mode 100644 (file)
index 0000000..9db138a
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/cloud-popup-relative.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/east-mini.png b/www/plugins/gis/images/openlayers/dark/east-mini.png
new file mode 100644 (file)
index 0000000..3f1f3d8
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/east-mini.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/layer-switcher-maximize.png b/www/plugins/gis/images/openlayers/dark/layer-switcher-maximize.png
new file mode 100644 (file)
index 0000000..20ad0b9
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/layer-switcher-maximize.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/layer-switcher-minimize.png b/www/plugins/gis/images/openlayers/dark/layer-switcher-minimize.png
new file mode 100644 (file)
index 0000000..3d27de3
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/layer-switcher-minimize.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/north-mini.png b/www/plugins/gis/images/openlayers/dark/north-mini.png
new file mode 100644 (file)
index 0000000..cfb9b7d
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/north-mini.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/slider.png b/www/plugins/gis/images/openlayers/dark/slider.png
new file mode 100644 (file)
index 0000000..45622bc
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/slider.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/south-mini.png b/www/plugins/gis/images/openlayers/dark/south-mini.png
new file mode 100644 (file)
index 0000000..f8cac08
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/south-mini.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/west-mini.png b/www/plugins/gis/images/openlayers/dark/west-mini.png
new file mode 100644 (file)
index 0000000..34e9776
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/west-mini.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/zoom-minus-mini.png b/www/plugins/gis/images/openlayers/dark/zoom-minus-mini.png
new file mode 100644 (file)
index 0000000..abc125e
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/zoom-minus-mini.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/zoom-panel.png b/www/plugins/gis/images/openlayers/dark/zoom-panel.png
new file mode 100644 (file)
index 0000000..f94fbb9
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/zoom-panel.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/zoom-plus-mini.png b/www/plugins/gis/images/openlayers/dark/zoom-plus-mini.png
new file mode 100644 (file)
index 0000000..f7a717c
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/zoom-plus-mini.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/zoom-world-mini.png b/www/plugins/gis/images/openlayers/dark/zoom-world-mini.png
new file mode 100644 (file)
index 0000000..0dee7ee
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/zoom-world-mini.png differ
diff --git a/www/plugins/gis/images/openlayers/dark/zoombar.png b/www/plugins/gis/images/openlayers/dark/zoombar.png
new file mode 100644 (file)
index 0000000..4a13fe0
Binary files /dev/null and b/www/plugins/gis/images/openlayers/dark/zoombar.png differ
diff --git a/www/plugins/gis/inc/gis_xmlrpc.php b/www/plugins/gis/inc/gis_xmlrpc.php
new file mode 100644 (file)
index 0000000..fdc5291
--- /dev/null
@@ -0,0 +1,125 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Récupère la liste des points géolocalisés
+ * 
+ * Arguments possibles :
+ * -* login string 
+ * -* pass string
+ * -* objet string : le type d'objets liés
+ * -* id_objet int : l'identifiant numérique de l'objet lié
+ * -* where array : conditions à ajouter dans la clause where du select
+ * -* tri array : les éléments de tri
+ * -** Si 'distance' dans le tri
+ * -*** lat float : la latitude à partir de laquelle chercher
+ * -*** lon float : la longitude à partir de laquelle chercher
+ * -* limite int : le nombre d'éléments maximum à retourner
+ */
+function spip_liste_gis($args) {
+       global $spip_xmlrpc_serveur;
+       
+       if(!$spip_xmlrpc_serveur)
+               return false;
+       
+       $objet = 'gis';
+       
+       $what[] = 'gis.id_gis';
+       $from = 'spip_gis as gis LEFT JOIN spip_gis_liens as lien ON gis.id_gis=lien.id_gis';
+       $where = is_array($args['where']) ? $args['where'] : array();
+       $order = is_array($args['tri']) ? $args['tri'] : array();
+       if((intval($args['id_objet']) > 0) && $args['objet']){
+               $where[] = 'lien.id_objet='.intval($args['id_objet']).' AND lien.objet='.sql_quote($args['objet']);
+       }
+       
+       if(in_array('distance',$order) OR in_array('!distance',$order)){
+               $distance = true;
+               $lat = $args['lat'];
+               $lon = $args['lon'];
+               if(!is_numeric($lon) OR !is_numeric($lat)){
+                       $erreur = _T('gis:erreur_xmlrpc_lat_lon');
+                       return new IXR_Error(-32601, attribut_html($erreur));
+               }else{
+                       $what[] = "(6371 * acos( cos( radians(\"$lat\") ) * cos( radians( gis.lat ) ) * cos( radians( gis.lon ) - radians(\"$lon\") ) + sin( radians(\"$lat\") ) * sin( radians( gis.lat ) ) ) ) AS distance";
+               }
+       }
+       
+       /**
+        * Une recherche
+        */     
+       if(is_string($args['recherche']) AND strlen($args['recherche']) > 3){
+               $prepare_recherche = charger_fonction('prepare_recherche', 'inc');
+               list($rech_select, $rech_where) = $prepare_recherche($args['recherche'], $objet.'s', $where);
+               $what[] = $rech_select;
+               $from .= ' INNER JOIN spip_resultats AS resultats ON ( resultats.id = gis.id_gis ) ';
+               $where[] = 'resultats.'.$rech_where;
+       }
+       
+       $points_struct = array();
+
+       if($points = sql_select($what,$from,$where,'',$order,$args['limite'])){
+               while($point = sql_fetch($points)){
+                       $struct=array();
+                       $args['id_gis'] = $point['id_gis'];
+                       /**
+                        * On utilise la fonction geodiv_lire_media pour éviter de dupliquer trop de code
+                        */
+                       $struct = spip_lire_gis($args);
+                       if($distance)
+                               $struct['distance'] = $point['distance'];
+                       $points_struct[] = $struct;
+               }
+       }
+       return $points_struct;
+}
+
+/**
+ * Récupère le contenu d'un point géolocalisé
+ * 
+ * Arguments possibles :
+ * -* login
+ * -* pass
+ * -* id_gis (Obligatoire)
+ * -* lat : si disponible avec lon, on ajoute la distance dans les infos
+ * -* lon : si disponible avec lat, on ajoute la distance dans les infos
+ */
+function spip_lire_gis($args){
+       global $spip_xmlrpc_serveur;
+       
+       if(!$spip_xmlrpc_serveur)
+               return false;
+       
+       if(!intval($args['id_gis']) > 0){
+               $erreur = _T('xmlrpc:erreur_identifiant',array('objet'=>'gis'));
+               return new IXR_Error(-32601, attribut_html($erreur));
+       }
+       
+       $args_gis = array('objet'=>'gis','id_objet'=>$args['id_gis']);
+       $res = $spip_xmlrpc_serveur->read($args_gis);
+       if(!$res)
+               return $spip_xmlrpc_serveur->error;
+       
+       if(isset($args['lat']) && is_numeric($args['lat']) && isset($args['lon']) && is_numeric($args['lon'])){
+               $lat = $args['lat'];
+               $lon = $args['lon'];
+               $what[] = 'gis.id_gis';
+               $what[] = "(6371 * acos( cos( radians(\"$lat\") ) * cos( radians( gis.lat ) ) * cos( radians( gis.lon ) - radians(\"$lon\") ) + sin( radians(\"$lat\") ) * sin( radians( gis.lat ) ) ) ) AS distance";
+               $distance = sql_fetsel($what,"spip_gis AS gis","gis.id_gis=".intval($args['id_gis']));
+               $res['result'][0]['distance'] = $distance['distance'];
+       }
+       
+       if(autoriser('modifier','gis',$args['id_gis'],$GLOBALS['visiteur_session']))
+               $res['result'][0]['modifiable'] = 1;
+       else
+               $res['result'][0]['modifiable'] = 0;
+       $logo = quete_logo('id_gis','on', $res['result'][0]['id_gis'], '', false);
+       if(is_array($logo))
+               $res['result'][0]['logo'] = url_absolue($logo[0]);
+       
+       $gis_struct = $res['result'][0];
+       $gis_struct = array_map('texte_backend',$gis_struct);
+       return $gis_struct;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/inc/iptc.php b/www/plugins/gis/inc/iptc.php
new file mode 100644 (file)
index 0000000..9eff943
--- /dev/null
@@ -0,0 +1,328 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+//#############################################################################################
+//##############################################################################################
+
+/* INFOS SUR LE FICHIER 
+
+Nom : iptc.class.php 
+Rôle : contient la classe permettant de gérer les IPTC d'un fichier image 
+Développeur(s) : Arica Alex, Thies C. Arntzen 
+
+FIN INFOS SUR LE FICHIER 
+
+
+INFOS SUR LA CLASSE 'class_iptc' 
+
+REFERENCES : Développée le 04 Octobre 02 par Arica Alex avec l'aide de Thies C. Arntzen 
+
+ROLE : permet de manipuler les iptc d'une image 
+
+VARIABLES : 
+- $h_codesIptc 
+- $h_cheminFichier 
+- $h_iptcData 
+
+METHODES : 
+- fct_lireIPTC 
+- fct_ecrireIPTC 
+- fct_iptcMaketag 
+
+FIN INFOS SUR LA CLASSE 
+
+*/ 
+
+
+class class_IPTC 
+{ 
+
+
+
+/* VARIABLES statics */ 
+
+var $h_codesIptc; /* $h_codesIptc : (tableau associatif) contient les codes des champs IPTC associés à un libellé */ 
+var $h_cheminImg; /* $h_cheminImg : (chaine) contient le chemin complet du fichier d'image */ 
+var $h_iptcData; /* $h_iptcData : (chaine) contient les données encodées de l'iptc de l'image */ 
+
+/* FIN VARIABLES statics 
+
+
+
+
+
+
+
+
+
+------------------------------------------------------------------------------------------------------- 
+
+
+
+
+
+
+
+
+INFOS SUR LA FONCTION 
+
+ROLE : constructeur 
+FONCTION : class_IPTC($cheminImg) 
+DESCRIPTION DES PARAMETRES : 
+- $cheminImg = (chaine) le chemin complet du fichier d'image à traiter 
+
+FIN INFOS SUR LA FONCTION */ 
+
+
+function class_IPTC($cheminImg) 
+{ 
+
+// Inititalisations 
+
+// Les valeurs IPTC pouvant être manipulées 
+$this -> h_codesIptc = array("005" => "objectName", 
+"007" => "editStatus", 
+"010" => "priority", 
+"015" => "category", 
+"020" => "supplementalCategory", 
+"022" => "fixtureIdentifier", 
+"025" => "keywords", 
+"030" => "releaseDate", 
+"035" => "releaseTime", 
+"040" => "specialInstructions", 
+"045" => "referenceService", 
+"047" => "referenceDate", 
+"050" => "referenceNumber", 
+"055" => "createdDate", 
+"060" => "createdTime", 
+"065" => "originatingProgram", 
+"070" => "programVersion", 
+"075" => "objectCycle", 
+"080" => "byline", 
+"085" => "bylineTitle", 
+"090" => "city", 
+"095" => "provinceState", 
+"100" => "countryCode", 
+"101" => "country", 
+"103" => "originalTransmissionReference", 
+"105" => "headline", 
+"110" => "credit", 
+"115" => "source", 
+"116" => "copyright", 
+"120" => "caption", 
+"121" => "localCaption", 
+"122" => "captionWriter"); 
+
+
+// On enregistre le chemin de l'image à traiter 
+$this -> h_cheminImg = $cheminImg; 
+
+
+// On extrait les données encodées de l'iptc 
+// getimagesize($this -> h_cheminImg, &$info); //avant,marche pas sinon
+getimagesize($this -> h_cheminImg, $info); //marche sans le & 
+$this -> h_iptcData = $info["APP13"]; 
+
+} 
+
+/* FIN FONCTION class_IPTC(); 
+
+
+
+
+
+
+
+
+
+------------------------------------------------------------------------------------------------------- 
+
+
+
+
+
+
+
+
+INFOS SUR LA FONCTION 
+
+ROLE : lit les IPTC d'une image et les renvoie dans un tableau associatif 
+FONCTION : fct_lireIPTC() 
+TYPE RETOURNE : chaine sous forme de tableau associatif 
+
+FIN INFOS SUR LA FONCTION */ 
+
+function fct_lireIPTC() 
+{ 
+       $tblIPTC = iptcparse($this -> h_iptcData); 
+       
+       while( (is_array($tblIPTC)) && (list($codeIPTC, $valeurIPTC) = each($tblIPTC)) ) 
+       { 
+               $codeIPTC = str_replace("2#", "", $codeIPTC); 
+               
+               if( ($codeIPTC != "000") && ($codeIPTC != "140")  && $this->h_codesIptc["$codeIPTC"]) 
+               { 
+                       while(list($index, ) = each($valeurIPTC)) 
+                       { 
+                               if ($this->h_codesIptc["$codeIPTC"]) $codeIPTC = $this->h_codesIptc["$codeIPTC"];
+                               $lesIptc[$codeIPTC] .= $valeurIPTC[$index].$retourLigne; 
+                               $retourLigne = "\n"; 
+                       } 
+               } 
+       } 
+       
+       if(is_array($lesIptc)) return $lesIptc; 
+       else return false; 
+} 
+
+/* FIN FONCTION fct_lireIPTC(); 
+
+
+
+
+
+
+
+
+------------------------------------------------------------------------------------------------------- 
+
+
+
+
+
+
+
+
+INFOS SUR LA FONCTION 
+
+ROLE : écrit des IPTC dans le fichier image 
+FONCTION : fct_ecrireIPTC() 
+DESCRIPTION DES PARAMETRES : 
+- $tblIPTC_util = (tableau associatif) contient les codes des champs IPTC à modifier associés leur valeur 
+- $cheminImgAModifier = (chaine) stocke le chemin de l'image dont l'IPTC est à modifier ; s'il est null 
+le chemin sera celui contenu dans '$this -> h_cheminImg' 
+TYPE RETOURNE : booléen 
+
+FIN INFOS SUR LA FONCTION */ 
+
+function fct_ecrireIPTC($tblIPTC_util, $cheminImgAModifier = "") 
+{ 
+
+// La tableau devant contenir des IPTC est vide ou n'est pas un tableau associatif 
+if( (empty($tblIPTC_util)) || (!is_array($tblIPTC_util)) ) return false; 
+
+
+// Si le chemin de l'image à modifier est vide alors on lui spécifie le chemin par défaut 
+if(empty($cheminImgAModifier)) $cheminImgAModifier = $this -> h_cheminImg; 
+
+
+// On récupère l'IPTC du fichier image courant 
+$tblIPTC_old = iptcparse($this -> h_iptcData); 
+
+
+// On prélève le tableau contenant les codes et les valeurs des IPTC de la photo 
+while(list($codeIPTC, $codeLibIPTC) = each($this -> h_codesIptc)) 
+{ 
+
+// On teste si les données originelles correspondant au code en cours sont présents 
+if (is_array($tblIPTC_old["2#".$codeIPTC])) $valIPTC_new = $tblIPTC_old["2#".$codeIPTC]; 
+else $valIPTC_new = array(); 
+
+
+// On remplace les valeurs des IPTC demandées 
+if (is_array($tblIPTC_util[$codeIPTC])) 
+{ 
+if (count($tblIPTC_util[$codeIPTC])) $valIPTC_new = $tblIPTC_util[$codeIPTC]; 
+
+}else{ 
+
+$val = trim(strval($tblIPTC_util[$codeIPTC])); 
+if (strlen($val)) $valIPTC_new[0] = $val; 
+} 
+
+
+// On crée un nouveau iptcData à partir de '$tblIPTC_new' qui contient le code et la valeur de l'IPTC 
+foreach($valIPTC_new as $val) 
+{ 
+$iptcData_new .= $this -> fct_iptcMaketag(2, $codeIPTC, $val); 
+} 
+
+} 
+
+
+/* A partir du nouveau iptcData contenu dans '$iptcData_new' on crée grâce à la fonction 'iptcembed()' 
+le contenu binaire du fichier image avec le nouveau IPTC inclu */ 
+$contenuImage = iptcembed($iptcData_new, $this -> h_cheminImg); 
+
+
+// Ecriture dans le fichier image 
+$idFichier = fopen($cheminImgAModifier, "wb"); 
+fwrite($idFichier, $contenuImage); 
+fclose($idFichier); 
+
+
+return true; 
+
+} 
+
+/* FIN FONCTION fct_ecrireIPTC(); 
+
+
+
+
+
+
+
+
+------------------------------------------------------------------------------------------------------- 
+
+
+
+
+
+
+
+
+INFOS SUR LA FONCTION 
+
+ROLE : permet de transformer une valeur de d'IPTC (code + valeur) en iptcData 
+AUTEUR : Thies C. Arntzen 
+FONCTION : fct_iptcMaketag($rec, $dat, $val) 
+DESCRIPTION DES PARAMETRES : 
+- $rec = (entier) toujours à mettre à 2 
+- $dat = (chaine) le code de l'IPTC (de type '110' et non '2#110') 
+- $val = (chaine) la valeur de l'IPTC 
+TYPE RETOURNE : booléen 
+
+FIN INFOS SUR LA FONCTION */ 
+
+function fct_iptcMaketag($rec, $dat, $val) 
+{ 
+$len = strlen($val); 
+if ($len < 0x8000) 
+return chr(0x1c).chr($rec).chr($dat). 
+chr($len >> 8). 
+chr($len & 0xff). 
+$val; 
+else 
+return chr(0x1c).chr($rec).chr($dat). 
+chr(0x80).chr(0x04). 
+chr(($len >> 24) & 0xff). 
+chr(($len >> 16) & 0xff). 
+chr(($len >> 8 ) & 0xff). 
+chr(($len ) & 0xff). 
+$val; 
+} 
+
+// FIN FONCTION fct_iptcMaketag(); 
+
+
+
+
+
+} 
+
+/* Fin class_IPTC */
+
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/inc/kml_infos.php b/www/plugins/gis/inc/kml_infos.php
new file mode 100644 (file)
index 0000000..484c03e
--- /dev/null
@@ -0,0 +1,187 @@
+<?php
+/**
+ * Plugin GIS
+ * Récupération de données dans les fichiers kml permettant de :
+ * -* récupérer latitude et longitude d'un point correspondant centré sur la moyenne des points ou polygones du kml
+ * -* récupérer un titre
+ * -* récupérer un descriptif
+ */
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function inc_kml_infos($id_document){
+       if(!intval($id_document))
+               return false;
+       include_spip('inc/documents');
+       $document = sql_fetsel("*", "spip_documents","id_document=".intval($id_document));
+       $chemin = $document['fichier'];
+       $chemin = get_spip_doc($chemin);
+       $extension = $document['extension'];
+       
+       if(in_array($extension,array('kml','kmz'))){
+               $supprimer_chemin = false;
+               /**
+                * Si on est dans un kmz (kml + autres fichiers compressés en zip),
+                * On dézip pour trouver le kml
+                */
+               if($extension == 'kmz'){
+                       include_spip('inc/pclzip');
+                       $zip = new PclZip($chemin);
+                       $list = $zip->listContent();
+                       foreach($list as $fichier => $info_fichier){
+                               if(substr(basename($info_fichier['filename']),-3) == 'kml'){
+                                       $zip->extractByIndex($info_fichier['index'],_DIR_TMP);
+                                       $chemin = _DIR_TMP.$info_fichier['filename'];
+                                       $supprimer_chemin = true;
+                                       break;
+                               }
+                       }
+               }
+               include_spip('inc/xml');
+               $ret = lire_fichier($chemin,$donnees);
+               $arbre = spip_xml_parse($donnees);
+               spip_xml_match_nodes(",^Document,",$arbre, $documents);
+               foreach($documents as $document => $info){
+                       $infos['titre'] = $info[0]['name'][0];
+                       $infos['descriptif'] = $info[0]['description'][0];
+                       $infos['longitude'] = $info[0]['LookAt'][0]['longitude'][0] ? $info[0]['LookAt'][0]['longitude'][0] : false;
+                       $infos['latitude'] = $info[0]['LookAt'][0]['latitude'][0] ? $info[0]['LookAt'][0]['latitude'][0] : false;
+               }
+               
+               /**
+                * Si on n'a pas de longitude ou de latitude, 
+                * on essaie de faire une moyenne des placemarks
+                */
+               if(!$infos['longitude'] OR !$infos['latitude']){
+                       spip_xml_match_nodes(",^Placemark,",$arbre, $placemarks);
+                       $latitude = 0;
+                       $longitude = 0;
+                       $compte = 0;
+                       foreach($placemarks as $places){
+                               foreach($places as $placemark => $lieu){
+                                       if($compte > 500)
+                                                       break;  
+                                       if($lieu['LookAt'][0]['longitude'][0] && $latitude + $lieu['LookAt'][0]['latitude'][0]){
+                                               if($compte > 500)
+                                                       break;  
+                                               $latitude = $latitude + $lieu['LookAt'][0]['latitude'][0];
+                                               $longitude = $longitude + $lieu['LookAt'][0]['longitude'][0];
+                                               $compte++;
+                                       }else if($lieu['Point'][0]['coordinates'][0]){
+                                               if($compte > 500)
+                                                       break;
+                                               $coordinates = explode(',',$lieu['Point'][0]['coordinates'][0]);
+                                               $latitude = $latitude + trim($coordinates[1]);
+                                               $longitude = $longitude + trim($coordinates[0]);
+                                               $compte++;
+                                       }else if($lieu['Polygon'][0]['outerBoundaryIs'][0]['LinearRing'][0]['coordinates'][0]){
+                                               if($compte > 500)
+                                                       break;
+                                               $coordinates = explode(' ',trim($lieu['Polygon'][0]['outerBoundaryIs'][0]['LinearRing'][0]['coordinates'][0]));
+                                               foreach($coordinates as $coordinate){
+                                                       if($compte > 500)
+                                                               break;
+                                                       $coordinate = explode(',',$coordinate);
+                                                       $latitude = $latitude + trim($coordinate[1]);
+                                                       $longitude = $longitude + trim($coordinate[0]);
+                                                       $compte++;
+                                               }
+                                       }
+                               }
+                       }
+                       if(($latitude != 0) && ($longitude != 0)){
+                               $infos['latitude'] = $latitude / $compte;
+                               $infos['longitude'] = $longitude / $compte; 
+                       }
+               }
+               
+               /**
+                * Si pas de titre ou si le titre est égal au nom de fichier ou contient kml ou kmz :
+                * -* on regarde s'il n'y a qu'un seul Folder et on récupère son nom;
+                * -* on regarde s'il n'y a qu'un seul Placemark et on récupère son nom;
+                */
+               if(!$infos['titre'] OR ($infos['titre'] == basename($chemin)) OR (preg_match(',\.km.,',$infos['titre']) > 0)){
+                       spip_xml_match_nodes(",^Folder,",$arbre, $folders);
+                       if(count($folders['Folder']) == 1){
+                               foreach($folders['Folder'] as $folder => $dossier){
+                                       if($dossier['name'][0])
+                                               $infos['titre'] = $dossier['name'][0];
+                                       if(!$infos['descriptif'] && $dossier['description'][0])
+                                               $infos['descriptif'] = $dossier['description'][0];
+                               }
+                       }else{
+                               if(!is_array($placemarks)){
+                                       spip_xml_match_nodes(",^Placemark,",$arbre, $placemarks);
+                               }
+                               if(count($placemarks) == 1){
+                                       foreach($placemarks as $places){
+                                               if(count($places) == 1){
+                                                       foreach($places as $placemark => $lieu){
+                                                               if($lieu['name'][0])
+                                                                       $infos['titre'] = $lieu['name'][0];
+                                                               if(!$infos['descriptif'] && $lieu['description'][0])
+                                                                       $infos['descriptif'] = $lieu['description'][0];
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }else if(in_array($extension,array('gpx'))){
+               $supprimer_chemin = false;
+               include_spip('inc/xml');
+               $ret = lire_fichier($chemin,$donnees);
+               $arbre = spip_xml_parse($donnees);
+               spip_xml_match_nodes(",^metadata,",$arbre, $metadatas);
+               foreach($metadatas as $metadata => $info){
+                       $infos['titre'] = $info[0]['name'][0];
+                       //$infos['date'] =  $info[0]['time'][0];
+                       $infos['descriptif'] = $info[0]['description'][0];
+                       foreach($info[0] as $meta => $data){
+                               if(preg_match(',^bounds ,',$meta)){
+                                       $meta = '<'.$meta.'>';
+                                       $maxlat = extraire_attribut($meta,'maxlat');
+                                       $minlat = extraire_attribut($meta,'minlat');
+                                       $maxlon = extraire_attribut($meta,'maxlon');
+                                       $minlon = extraire_attribut($meta,'minlon');
+                                       if($maxlat && $minlat)
+                                               $infos['latitude'] = (($maxlat+$minlat)/2);
+                                       if($maxlon && $minlon)
+                                               $infos['longitude'] = (($maxlon+$minlon)/2);
+                               }
+                       }
+               }
+               /**
+                * Si on n'a pas de longitude ou de latitude, 
+                * on essaie de faire une moyenne des placemarks
+                */
+               if(!$infos['longitude'] OR !$infos['latitude']){
+                       spip_xml_match_nodes(",^trkpt,",$arbre, $trackpoints);
+                       $latitude = 0;
+                       $longitude = 0;
+                       $compte = 0;
+                       foreach($trackpoints as $places => $place){
+                               foreach($place as $placemark => $lieu){
+                                       if($compte > 10)
+                                                       break;
+                               }
+                       }
+                       if(($latitude != 0) && ($longitude != 0)){
+                               $infos['latitude'] = $latitude / $compte;
+                               $infos['longitude'] = $longitude / $compte; 
+                       }
+               }
+       }else
+               return false;
+       
+       if(isset($infos['titre']))
+               $infos['titre'] = preg_replace('/<!\[cdata\[(.*?)\]\]>/is', '$1',$infos['titre']);
+       if(isset($infos['descriptif']))
+               $infos['descriptif'] = preg_replace('/<!\[cdata\[(.*?)\]\]>/is', '$1', $infos['descriptif']);
+               
+       if($supprimer_chemin){
+               supprimer_fichier($chemin);
+       }
+               
+       return $infos;
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/inclure/download_gpx.html b/www/plugins/gis/inclure/download_gpx.html
new file mode 100644 (file)
index 0000000..8191d49
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="#CHARSET" standalone="no" ?>
+<gpx version="1.1" creator="SPIP"
+       xmlns="http://www.topografix.com/GPX/1/1"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
+       [(#INCLURE{fond=inclure/gpx-item,id_gis})]
+</gpx>
\ No newline at end of file
diff --git a/www/plugins/gis/inclure/download_kml.html b/www/plugins/gis/inclure/download_kml.html
new file mode 100644 (file)
index 0000000..87d6aff
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="#CHARSET" ?>
+<kml xmlns="http://www.opengis.net/kml/2.2"
+       xmlns:atom="http://www.w3.org/2005/Atom">
+<Document>
+[<name>(#NOM_SITE_SPIP|texte_backend)</name>]
+[<description>(#DESCRIPTIF_SITE_SPIP|supprimer_tags|texte_backend)</description>]
+       [(#INCLURE{fond=inclure/kml-item,id_gis})]
+</Document>
+</kml>
\ No newline at end of file
diff --git a/www/plugins/gis/inclure/gpx-item.html b/www/plugins/gis/inclure/gpx-item.html
new file mode 100755 (executable)
index 0000000..5264c65
--- /dev/null
@@ -0,0 +1,9 @@
+<BOUCLE_gis(GIS){id_gis}>
+<trk>
+       [<name>(#TITRE|supprimer_numero|texte_backend)</name>][
+       <desc>(#DESCRIPTIF|texte_backend)</desc>
+       ]<trkseg>
+               [<trkpt lat="(#LAT)" lon="[(#LON)]"></trkpt>]
+       </trkseg>
+</trk>
+</BOUCLE_gis>
\ No newline at end of file
diff --git a/www/plugins/gis/inclure/kml-item.html b/www/plugins/gis/inclure/kml-item.html
new file mode 100755 (executable)
index 0000000..ade8ba0
--- /dev/null
@@ -0,0 +1,42 @@
+<BOUCLE_gis(GIS){id_gis}>
+       <Placemark id="#gis[(#ID_GIS)]">
+               <name>[(#TITRE|supprimer_numero|texte_backend)]</name>[
+               <atom:link rel="related" href="(#ID_OBJET|generer_url_entite{#OBJET}|url_absolue)" />
+               ]<description>
+                       <![CDATA[
+                               [(#DESCRIPTIF|texte_backend)]
+                       ]]>
+               </description>
+               [<Point>
+                       <coordinates>(#LON),[(#LAT)]</coordinates>
+               </Point>]
+               [(#SET{logo_doc,''})]
+               [(#LOGO_GIS|oui)
+               [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{28,28}|image_recadre{28,28}|image_recadre{32,32,center}})]]
+               [(#LOGO_GIS|non)
+               [(#CHEMIN{images/marker_defaut.png}|oui)[
+                       (#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{28,28}|image_recadre{28,28}})]
+               ]]
+               [(#GET{logo_doc}|oui)
+               #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+               #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+               #SET{icon_anchorPoint,''}
+               <Style>
+                       <IconStyle>
+                               <scale>1.0</scale>
+                               [<Icon>
+                                       <href>(#GET{logo_doc}|extraire_attribut{src}|url_absolue)</href>
+                               </Icon>]
+                               <hotSpot x="0.5"  y="0.5" xunits="pixels" yunits="pixels"/>
+                       </IconStyle>
+               </Style>
+               <ExtendedData>
+                       [<Data name="iconSize">
+                               <value>(#GET{icon_w}),[(#GET{icon_h})]</value>
+                       </Data>]
+                       <Data name="iconAnchor">
+                               <value>0.5,0.5</value>
+                       </Data>
+               </ExtendedData>]
+       </Placemark>
+</BOUCLE_gis>
\ No newline at end of file
diff --git a/www/plugins/gis/javascript/gis.js.html b/www/plugins/gis/javascript/gis.js.html
new file mode 100644 (file)
index 0000000..6746daa
--- /dev/null
@@ -0,0 +1,47 @@
+#HTTP_HEADER{Content-type:text/javascript}
+
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})dist/[(#CONFIG{auto_compress_js}|=={oui}|?{'leaflet','leaflet-src'})].js]})]})]
+
+[L.Icon.Default.imagePath = "(#CHEMIN{#EVAL{_DIR_LIB_GIS}dist/images}|url_absolue)";]
+
+[(#INCLURE{javascript/gis_geocoder.js})]
+
+[(#INCLURE{javascript/gis_utils.js})]
+
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/KML.js]})]})]
+
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/GPX.js]})]})]
+
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/leaflet-providers.js]})]})]
+
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/Control.FullScreen.js]})]})]
+
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/Control.MiniMap.js]})]})]
+
+[(#REM) Tester suivant la config pour ces deux scripts ]
+
+#SET{layers,#CONFIG{gis/layers,#ARRAY{0,openstreetmap_mapnik}}}
+[(#VAL|gis_layer_defaut|in_array{#GET{layers}}|non)
+       #SET{layers,#GET{layers}|push{#VAL|gis_layer_defaut}}
+]
+
+[(#LISTE{google_roadmap,google_satellite,google_terrain}|array_intersect{#GET{layers}}|count|>{0}|oui)
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/Google.js]})]})]
+]
+
+[(#VAL{bing_aerial}|in_array{#GET{layers}}|oui)
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/Bing.js]})]})]
+]
+
+#INCLURE{javascript/gis_init_map.js}
+
+[(#REM)
+Lib clustering si besoin
+]
+[(#ENV{cluster}|=={oui}|oui)
+[(#INCLURE{[(#VAL{[(#EVAL{_DIR_LIB_GIS})plugins/leaflet.markercluster-src.js]})]})]
+]
+
+[(#CONFIG{auto_compress_js}|=={oui}|oui)
+#FILTRE{compacte}
+]
diff --git a/www/plugins/gis/javascript/gis_geocoder.js b/www/plugins/gis/javascript/gis_geocoder.js
new file mode 100644 (file)
index 0000000..825b07d
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * L.Geocoder is used to make geocoding or reverse geocoding requests.
+ */
+
+L.Geocoder = L.Class.extend({
+
+       includes: L.Mixin.Events,
+
+       options: {
+               forwardUrl: 'http://open.mapquestapi.com/nominatim/v1/search',
+               reverseUrl: 'http://open.mapquestapi.com/nominatim/v1/reverse',
+               limit: 1,
+               addressdetails: 1
+       },
+
+       initialize: function (callback, options) {
+               L.Util.setOptions(this, options);
+               this._user_callback = callback;
+       },
+
+       geocode: function (data) {
+               if (L.LatLng && (data instanceof L.LatLng)) {
+                       this._reverse_geocode(data);
+               } else if (typeof(data) == 'string') {
+                       this._geocode(data);
+               }
+       },
+
+       _geocode: function (text) {
+               this._request(
+                       this.options.forwardUrl,
+                       {
+                               format: 'json',
+                               q: text,
+                               limit: this.options.limit,
+                               addressdetails: this.options.addressdetails
+                       }
+               );
+       },
+
+       _reverse_geocode: function (latlng) {
+               this._request(
+                       this.options.reverseUrl,
+                       {
+                               format: 'json',
+                               lat: latlng.lat,
+                               lon: latlng.lng
+                       }
+               );
+       },
+
+       _request: function (url, data) {
+               $.ajax({
+                       cache: true,
+                       context: this,
+                       data: data,
+                       dataType: 'jsonp',
+                       jsonp: 'json_callback',
+                       success: this._callback,
+                       url: url
+               });
+       },
+       
+       _callback: function (response) {
+               var return_location = {};
+               if (response instanceof Array && !response.length) {
+                       return false;
+               } else {
+                       return_location.street = '';
+                       return_location.postcode = '';
+                       return_location.locality = '';
+                       return_location.region = '';
+                       return_location.country = '';
+                       
+                       if (response.length > 0) {
+                               place = response[0];
+                       } else {
+                               place = response;
+                       }
+                       
+                       var street_components = [];
+                       
+                       if (place.address.country) {
+                               return_location.country = place.address.country;
+                       }
+                       if (place.address.state) {
+                               return_location.region = place.address.state;
+                       }
+                       if (place.address.city) {
+                               return_location.locality = place.address.city;
+                       }else if(place.address.county){
+                               street_components.push(place.address.pedestrian);
+                       }
+                       if (place.address.postcode) {
+                               return_location.postcode = place.address.postcode;
+                       }
+                       if (place.address.road) {
+                               street_components.push(place.address.road);
+                       }else if(place.address.pedestrian){
+                               street_components.push(place.address.pedestrian);
+                       }
+                       if (place.address.house_number) {
+                               street_components.unshift(place.address.house_number);
+                       }
+                       
+                       if (return_location.street === '' && street_components.length > 0) {
+                               return_location.street = street_components.join(' ');
+                       }
+                       
+                       return_location.point = new L.LatLng(place.lat, place.lon);
+                       
+                       this._user_callback(return_location);
+               }
+       }
+});
\ No newline at end of file
diff --git a/www/plugins/gis/javascript/gis_init_map.js b/www/plugins/gis/javascript/gis_init_map.js
new file mode 100644 (file)
index 0000000..e99e7e1
--- /dev/null
@@ -0,0 +1,252 @@
+var gis_init_map = function(mapcfg) {
+       var map_container = mapcfg["mapid"];
+
+       // Création de la carte Leafleat
+       var map = new L.Map(map_container,{
+               scrollWheelZoom: mapcfg["scrollWheelZoom"],
+               zoomControl: mapcfg["zoomControl"],
+               maxZoom: mapcfg["maxZoom"]
+       });
+       // affecter sur la globale homonyme a mapid/map_container (compat ascendante)
+       eval(map_container+"=map;");
+       // affecter sur l'objet du DOM
+       jQuery("#"+map_container).get(0).map=map;
+
+       // Appeler l'éventuelle fonction de callback et trigger "load"
+       map.on('load',function(e){
+               if (mapcfg["callback"] && typeof(mapcfg["callback"]) === "function") {
+                       var callback = mapcfg["callback"];
+                       callback(e.target);
+               }
+               jQuery("#"+map_container).trigger('load',e.target);
+       });
+
+       // Déterminer la position initiale de la carte
+       if (!mapcfg['utiliser_bb']){
+               map.setView(new L.LatLng(mapcfg['lat'], mapcfg['lon']), mapcfg['zoom']);
+       }
+       else {
+               map.fitBounds(
+                       new L.LatLngBounds(
+                               new L.LatLng(mapcfg['sw_lat'], mapcfg['sw_lon']),
+                               new L.LatLng(mapcfg['ne_lat'], mapcfg['ne_lon'])
+                       )
+               );
+       }
+
+       var get_layer=function(name){
+               var layer;
+               if (typeof mapcfg['layers'][name]!=="undefined")
+               eval("layer=new "+ mapcfg['layers'][name]["layer"]+";");
+               return layer;
+       }
+
+       // Fond de carte par défaut (layer)
+       var default_layer = get_layer(mapcfg['default_layer']);
+       map.addLayer(default_layer);
+
+       if (mapcfg['control_type'] && !mapcfg['no_control'] && mapcfg['affiche_layers'].length>1){
+               var layers_control = new L.Control.Layers();
+               layers_control.addBaseLayer(default_layer,mapcfg['layers'][mapcfg['default_layer']]["nom"]);
+               for(var l in mapcfg['affiche_layers']){
+                       if (mapcfg['affiche_layers'][l]!==mapcfg['default_layer']){
+                               var layer = get_layer(mapcfg['affiche_layers'][l]);
+                               if (typeof layer!=="undefined")
+                                       layers_control.addBaseLayer(layer,mapcfg['layers'][mapcfg['affiche_layers'][l]]["nom"]);
+                       }
+               }
+               map.addControl(layers_control);
+               // ajouter l'objet du controle de layers à la carte pour permettre d'y accéder depuis le callback
+               map.layersControl = layers_control;
+               // classe noajax sur le layer_control pour éviter l'ajout de hidden par SPIP
+               jQuery(layers_control._form).addClass('noajax');
+       }
+
+
+       map.attributionControl.setPrefix('');
+
+       // Ajout des contrôles de la carte
+       if (!mapcfg['no_control']){
+               if (mapcfg['scale'])
+                       map.addControl(new L.Control.Scale());
+               if (mapcfg['fullscreen'])
+                       map.addControl(new L.Control.FullScreen());
+               if (mapcfg['overview']){
+                       var minimap_layer = get_layer(mapcfg['default_layer']);
+                       var miniMap = new L.Control.MiniMap(minimap_layer,{width: 100,height: 100, toggleDisplay: true}).addTo(map);
+               }
+       }
+
+       // API setGeoJsonFeatureIcon : Pour Ajouter l'icone d'un point (feature = item d'un GeoJson)
+       map.setGeoJsonFeatureIcon = function (feature, layer) {
+               // Déclarer l'icone du points, si défini
+               if (feature.properties && feature.properties.icon){
+                       icon_options = {
+                               'iconUrl': feature.properties.icon,
+                               'iconSize': new L.Point( feature.properties.icon_size[0], feature.properties.icon_size[1] ),
+                               'iconAnchor': new L.Point( feature.properties.icon_anchor[0], feature.properties.icon_anchor[1] ),
+                               'popupAnchor': new L.Point( feature.properties.popup_anchor[0], feature.properties.popup_anchor[1] )
+                       };
+                       if (feature.properties.shadow)
+                               icon_options.shadowUrl = feature.properties.shadow;
+                       if (feature.properties.shadow_size)
+                               icon_options.shadowSize = new L.Point( feature.properties.shadow_size[0], feature.properties.shadow_size[1] );
+                       layer.setIcon(new L.Icon(icon_options));
+               }
+       }
+
+       // API setGeoJsonFeaturePopup : Pour Ajouter le texte de popup d'un point (feature = item d'un GeoJson)
+       map.setGeoJsonFeaturePopup = function (feature, layer) {
+               // Déclarer le contenu de la popup s'il y en a
+               if (feature.properties && (feature.properties.title || feature.properties.description)){
+                       var popupContent = '';
+                       var popupOptions = '';
+                       if (feature.properties.title)
+                               popupContent = '<strong class="title">' + feature.properties.title + '</strong>';
+                       if (feature.properties.description)
+                               popupContent = popupContent + feature.properties.description;
+                       if (feature.properties.popup_options)
+                               popupOptions = feature.properties.popup_options;
+                       layer.bindPopup(popupContent,popupOptions);
+               }
+       }
+
+       /*
+               Il y a pour le moment 2 façons d'analyser le GeoJson calculé
+               en fonction de si on veut faire du clustering (regrouper les points proches)
+               ou non. Il y a certainement moyen de regrouper en un seul élément
+               la plupart du code, en se passant du js L.geoJson même hors clustering.
+               À réfléchir.
+       */
+       // API parseGeoJson
+       if (!mapcfg['cluster']){
+               // Analyse des points et déclaration (sans regroupement des points en cluster)
+               map.parseGeoJson = function(data) {
+                       if (data.features.length > 0) {
+                               var geojson = new L.geoJson('', {
+                                       style: mapcfg['path_styles'],
+                                       onEachFeature: function (feature, layer) {
+                                               // Déclarer l'icone du point
+                                               map.setGeoJsonFeatureIcon(feature, layer);
+                                               // Déclarer le contenu de la popup s'il y en a
+                                               map.setGeoJsonFeaturePopup(feature, layer);
+                                       }
+                               }).addTo(map);
+                               geojson.addData(data);
+                               if (mapcfg['autocenterandzoom'])
+                                       map.fitBounds(geojson.getBounds());
+                               if (mapcfg['open_id'].length)
+                                       gis_focus_marker(mapcfg['open_id'],map_container.substring(3));
+
+                               if (typeof map.geojsons=="undefined") map.geojsons = [];
+                               map.geojsons.push(geojson);
+                       }
+               }
+       }
+       else {
+               // Analyse des points et déclaration (en regroupant les points en cluster)
+               map.parseGeoJson = function(data) {
+                       var options = {
+                               showCoverageOnHover:false
+                       };
+                       if (mapcfg["clusterMaxZoom"])
+                               options.disableClusteringAtZoom = parseInt(mapcfg["clusterMaxZoom"]);
+                       if (mapcfg["clusterShowCoverageOnHover"])
+                               options.showCoverageOnHover = Boolean(mapcfg["clusterShowCoverageOnHover"]);
+
+                       map.markers = new L.MarkerClusterGroup(options);
+
+                       /* Pour chaque points présents, on crée un marqueur */
+                       $.each(data.features, function(i, feature) {
+                               if (feature.geometry.coordinates[0]) {
+                                       var latlng = new L.LatLng(feature.geometry.coordinates[1], feature.geometry.coordinates[0]);
+                                       var marker = new L.Marker(latlng);
+
+                                       // Déclarer l'icone du point
+                                       map.setGeoJsonFeatureIcon(feature, marker);
+                                       // Déclarer le contenu de la popup s'il y en a
+                                       map.setGeoJsonFeaturePopup(feature, marker);
+
+                                       marker.id = feature.id;
+                                       map.markers.addLayer(marker);
+                               }
+                       });
+
+                       map.addLayer(map.markers);
+
+                       if (mapcfg['autocenterandzoom'])
+                               map.fitBounds(map.markers.getBounds());
+               }
+       }
+
+       // API Compat Gis3 : addJSON et removeAllMarkers
+       map.addJSON = map.parseGeoJson
+       map.removeAllMarkers = function(){
+               if (typeof map.geojsons=="undefined") map.geojsons = [];
+               for(i in map.geojsons){
+                       map.geojsons[i].clearLayers();
+                       map.removeLayer(map.geojsons[i]);
+               }
+               map.geojsons = [];
+       }
+
+       if (mapcfg['affiche_points']
+               && typeof(mapcfg['json_points'])!=="undefined"
+               && mapcfg['json_points']['url'].length){
+               // Récupération des points à mettre sur la carte, via json externe
+               var args = {};
+               jQuery.extend(true, args, mapcfg['json_points']['env']);
+               if (typeof mapcfg['json_points']['objets']!=="undefined"){
+                       args["objets"] = mapcfg['json_points']['objets'];
+                       if (args["objets"]=="point_libre"){
+                               args["lat"]=mapcfg['lat'];
+                               args["lon"]=mapcfg['lon'];
+                               if (typeof mapcfg['json_points']['titre']!=="undefined")
+                                       args["titre"]= mapcfg['json_points']['titre'];
+                               if (typeof mapcfg['json_points']['description']!=="undefined")
+                                       args["description"]=mapcfg['json_points']['description'];
+                               if (typeof mapcfg['json_points']['icone']!=="undefined")
+                                       args["icone"]=mapcfg['json_points']['icone'];
+                       }
+               }
+               if (typeof mapcfg['json_points']['limit']!=="undefined")
+                       args["limit"] = mapcfg['json_points']['limit'];
+               jQuery.getJSON(mapcfg['json_points']['url'],args,
+                       function(data) {
+                               if (data){
+                                       // Charger le json (data) et déclarer les points
+                                       map.parseGeoJson(data);
+                                       jQuery("#"+map_container).trigger('ready',map);
+                               }
+                       }
+               );
+       }
+
+       if (mapcfg['kml'] && mapcfg['kml'].length){
+               map.kml = {};
+               for(var i in mapcfg['kml']){
+                       map.kml[i] = new L.KML(mapcfg['kml'][i], {async: true});
+                       if (mapcfg['centrer_fichier']) {
+                               map.kml[i].on("loaded", function(e) { map.fitBounds(e.target.getBounds()); });
+                       }
+                       map.addLayer(map.kml[i]);
+               }
+       }
+       if (mapcfg['gpx'] && mapcfg['gpx'].length){
+               map.gpx = {};
+               for(var i in mapcfg['gpx']){
+                       map.gpx[i] = new L.GPX(mapcfg['gpx'][i], {async: true});
+                       if (mapcfg['centrer_fichier']) {
+                               map.gpx[i].on("loaded", function(e) { map.fitBounds(e.target.getBounds()); });
+                       }
+                       map.addLayer(map.gpx[i]);
+               }
+       }
+
+       if (mapcfg['localize_visitor'])
+               map.locate({setView: true, maxZoom: mapcfg['zoom']});
+
+       // si pas de points trigger ici
+       if (!mapcfg['affiche_points'] || !mapcfg['json_points'].length)
+               jQuery("#"+map_container).trigger('ready',map);
+}
diff --git a/www/plugins/gis/javascript/gis_utils.js b/www/plugins/gis/javascript/gis_utils.js
new file mode 100644 (file)
index 0000000..0faa8fd
--- /dev/null
@@ -0,0 +1,11 @@
+function gis_focus_marker(id, map) {
+       var carte = eval('map'+ map);
+       var i, count = 0;
+       for(i in carte._layers) {
+               if ((carte._layers[i].feature) && (carte._layers[i].feature.id == id)) {
+                       carte.panTo(carte._layers[i].getLatLng());
+                       carte._layers[i].openPopup();
+               }
+       count++;
+       }
+}
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis.html b/www/plugins/gis/json/gis.html
new file mode 100644 (file)
index 0000000..6ad03a8
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_gis(GIS){id_gis ?}{id_rubrique ?}{id_article ?}{id_breve ?}{id_document ?}{id_mot ?}{id_auteur ?}{id_syndic ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE*|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)[
+                               (#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_gis>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_articles.html b/www/plugins/gis/json/gis_articles.html
new file mode 100644 (file)
index 0000000..52a5ac5
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_art(ARTICLES){gis}{id_article ?}{id_rubrique ?}{id_secteur ?}{id_mot ?}{id_groupe ?}{id_auteur ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#TITRE*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#DESCRIPTIF}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_art>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_articles_branche.html b/www/plugins/gis/json/gis_articles_branche.html
new file mode 100644 (file)
index 0000000..71fcbc8
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_art(ARTICLES){gis}{id_article ?}{branche ?}{id_mot ?}{id_groupe ?}{id_auteur ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#TITRE*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#DESCRIPTIF}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_art>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_articles_plus_sites.html b/www/plugins/gis/json/gis_articles_plus_sites.html
new file mode 100644 (file)
index 0000000..8527953
--- /dev/null
@@ -0,0 +1,2 @@
+[(#INCLURE{fond=json/gis_articles,env})#SET{articlesvus,1}][[(#GET{articlesvus}|?{','})]\r
+               (#INCLURE{fond=json/gis_sites,env})]
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_auteurs.html b/www/plugins/gis/json/gis_auteurs.html
new file mode 100644 (file)
index 0000000..c1c2edc
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_auteurs(AUTEURS){gis}{id_article ?}{id_auteur ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#NOM*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#BIO}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_auteurs>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_documents.html b/www/plugins/gis/json/gis_documents.html
new file mode 100644 (file)
index 0000000..7c738d0
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_doc(DOCUMENTS){gis}{id_article ?}{id_rubrique ?}{id_secteur ?}{id_mot ?}{recherche ?}{media ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#TITRE*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#DESCRIPTIF}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_doc>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_evenements.html b/www/plugins/gis/json/gis_evenements.html
new file mode 100644 (file)
index 0000000..ff10c5b
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_events(EVENEMENTS){gis}{id_evenement ?}{id_article ?}{id_rubrique ?}{id_secteur ?}{id_mot ?}{id_auteur ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#TITRE*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#DESCRIPTIF}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_events>
diff --git a/www/plugins/gis/json/gis_mots.html b/www/plugins/gis/json/gis_mots.html
new file mode 100644 (file)
index 0000000..18b308b
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_mots(MOTS){gis}{id_mot ?}{id_groupe ?}{id_article ?}{id_rubrique ?}{id_breve ?}{id_syndic ?}{id_forum ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#TITRE*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#DESCRIPTIF}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_mots>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_point_libre.html b/www/plugins/gis/json/gis_point_libre.html
new file mode 100644 (file)
index 0000000..96edf86
--- /dev/null
@@ -0,0 +1,19 @@
+{
+       "type": "Feature",
+       "geometry": {"type": "Point", "coordinates": [[(#ENV{lon})], [(#ENV{lat})]]},
+       "id":"1",
+       "properties": {
+               "title":[(#ENV{titre}|json_encode)],
+               "description":[(#ENV{description}|wrap{<p>}|json_encode)]
+               #SET{icone, #CHEMIN_IMAGE{#ENV*{icone,0}}|sinon{#CHEMIN{#ENV*{icone,0}}}}
+               #SET{icone_defaut, #CHEMIN{images/marker_defaut.png}}
+               #SET{logo_doc,#GET{icone}|sinon{#GET{icone_defaut}}|image_passe_partout{32,32}|image_recadre{32,32,center}|extraire_attribut{src}|url_absolue}
+               [(#GET{logo_doc}|oui)
+               #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+               #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+               [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+               "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+               "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+               "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+       }
+}
diff --git a/www/plugins/gis/json/gis_rubriques.html b/www/plugins/gis/json/gis_rubriques.html
new file mode 100644 (file)
index 0000000..0c88fd1
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_rub(RUBRIQUES){gis}{id_rubrique ?}{id_secteur ?}{id_parent?=#ENV{id_parent}}{id_mot ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#TITRE*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#DESCRIPTIF}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_rub>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_sites.html b/www/plugins/gis/json/gis_sites.html
new file mode 100644 (file)
index 0000000..0de784f
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_sit(SITES){gis}{id_syndic ?}{id_rubrique ?}{id_secteur ?}{id_mot ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#TITRE_GIS*|sinon{#NOM_SITE*}|supprimer_numero|json_encode)],
+                       "description":[(#DESCRIPTIF_GIS|sinon{#DESCRIPTIF}|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)
+                               [(#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_sit>
\ No newline at end of file
diff --git a/www/plugins/gis/json/gis_tous_avec_liens_espace_prive.html b/www/plugins/gis/json/gis_tous_avec_liens_espace_prive.html
new file mode 100644 (file)
index 0000000..b9c3d50
--- /dev/null
@@ -0,0 +1,21 @@
+               <BOUCLE_gis(GIS){id_gis ?}{id_rubrique ?}{id_article ?}{id_breve ?}{id_document ?}{id_mot ?}{id_auteur ?}{id_syndic ?}{recherche ?}{0, #ENV{limit}}{","}>
+               {"type": "Feature",
+               "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},
+               "id":"#ID_GIS",
+               "properties": {
+                       "title":[(#VAL{<a href='[(#ID_GIS|generer_url_entite{gis,'','',0})]'>[(#TITRE*|supprimer_numero|sinon{----})]</a>}|json_encode)],
+                       "description":[(#DESCRIPTIF|json_encode)][(#SET{logo_doc,''})]
+                       [(#LOGO_GIS|oui)
+                       [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]]
+                       [(#LOGO_GIS|non)
+                       [(#CHEMIN{images/marker_defaut.png}|oui)[
+                               (#SET{logo_doc,#CHEMIN{images/marker_defaut.png}|image_passe_partout{32,32}|image_recadre{32,32}})]
+                       ]]
+                       [(#GET{logo_doc}|oui)
+                       #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                       #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                       [,"icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                       "icon_size": \[[(#GET{icon_w})],[(#GET{icon_h})]\],
+                       "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                       "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+               }}</BOUCLE_gis>
diff --git a/www/plugins/gis/lang/gis.xml b/www/plugins/gis/lang/gis.xml
new file mode 100644 (file)
index 0000000..5ab9a60
--- /dev/null
@@ -0,0 +1,16 @@
+<traduction module="gis" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/gis/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/gis?lang_cible=en">
+               <traducteur nom="Benitron" lien="http://trad.spip.net/auteur/benitron" />
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/gis?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/gis?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/gis?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/gis/lang/gis_en.php b/www/plugins/gis/lang/gis_en.php
new file mode 100644 (file)
index 0000000..71c3699
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/gis?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'aucun_gis' => 'No point',
+       'aucun_objet' => 'No object',
+
+       // B
+       'bouton_lier' => 'Link this point',
+       'bouton_supprimer_gis' => 'Delete this point permanently',
+       'bouton_supprimer_lien' => 'Remove this link',
+
+       // C
+       'cfg_descr_gis' => 'Geographic Information System.<br /><a href="http://www.spip-contrib.net/3887" class="spip_out">Link to the documentation</a>.',
+       'cfg_inf_adresse' => 'Displays additional address fields (country, city, state, address ...)',
+       'cfg_inf_bing' => 'The Bing Aerial layer needs a key you can create on <a href=\'@url@\' class="spip_out">the Bing website</a>.',
+       'cfg_inf_cloudmade' => 'This API needs a key you can create on <a href=\'@url@\' class="spip_out">the CloudMade website</a>.',
+       'cfg_inf_geocoder' => 'Enable geocoder functions (search from an address, recovery of the address from the coordinates).',
+       'cfg_inf_geolocaliser_user_html5' => 'If the user\'s browser allows it, its approximate geographic location is retrieved to give the default position when creating a new point.',
+       'cfg_inf_google' => 'This API needs a key you can create on <a href=\'@url@\' class="spip_out">the GoogleMaps website</a>.',
+       'cfg_inf_yandex' => 'This API needs a key you can create on <a href=\'@url@\' class="spip_out">the yandex website</a>.',
+       'cfg_lbl_activer_objets' => 'Enable geotagging of content:',
+       'cfg_lbl_adresse' => 'Show address fields',
+       'cfg_lbl_api' => 'Geolocation API',
+       'cfg_lbl_api_cloudmade' => 'CloudMade',
+       'cfg_lbl_api_google' => 'Google Maps v2',
+       'cfg_lbl_api_googlev3' => 'Google Maps v3',
+       'cfg_lbl_api_key_bing' => 'Bing key',
+       'cfg_lbl_api_key_cloudmade' => 'CloudMade API key',
+       'cfg_lbl_api_key_google' => 'GoogleMaps API key',
+       'cfg_lbl_api_key_yandex' => 'Yandex API key',
+       'cfg_lbl_api_mapquest' => 'MapQuest',
+       'cfg_lbl_api_microsoft' => 'Microsoft Bing',
+       'cfg_lbl_api_openlayers' => 'OpenLayers',
+       'cfg_lbl_api_ovi' => 'Ovi Nokia',
+       'cfg_lbl_api_yandex' => 'Yandex',
+       'cfg_lbl_geocoder' => 'Geocoder',
+       'cfg_lbl_geolocaliser_user_html5' => 'Center the map on the location of the user at the creation step',
+       'cfg_lbl_layer_defaut' => 'Default layer',
+       'cfg_lbl_layers' => 'Proposed layers',
+       'cfg_lbl_maptype' => 'Base map',
+       'cfg_lbl_maptype_carte' => 'Map',
+       'cfg_lbl_maptype_hybride' => 'Hybrid',
+       'cfg_lbl_maptype_relief' => 'Relief',
+       'cfg_lbl_maptype_satellite' => 'Satellite',
+       'cfg_titre_gis' => 'GIS',
+
+       // E
+       'editer_gis_editer' => 'Edit this point',
+       'editer_gis_explication' => 'This page lists the whole location-based points of the website.',
+       'editer_gis_nouveau' => 'Create a new point',
+       'editer_gis_titre' => 'The location-based points',
+       'erreur_recherche_pas_resultats' => 'No point corresponds to the searched text.',
+       'erreur_xmlrpc_lat_lon' => 'Latitude and longitude should be set as arguments',
+       'explication_api_forcee' => 'The is imposed by another plugin or skeleton.',
+       'explication_import' => 'Import a file in GPX or KML format.',
+       'explication_layer_forcee' => 'The layer is imposed by another plugin or skeleton.',
+       'explication_maptype_force' => 'The base map is imposed by another plugin or skeleton.',
+
+       // F
+       'formulaire_creer_gis' => 'Create a new location-based point :',
+       'formulaire_modifier_gis' => 'Modify the location-based point :',
+
+       // G
+       'gis_pluriel' => 'Location-based points',
+       'gis_singulier' => 'Location-based point',
+
+       // I
+       'icone_gis_tous' => 'Location-based points',
+       'info_1_gis' => 'A location-based point',
+       'info_1_objet_gis' => '1 object linked to that point',
+       'info_aucun_gis' => 'No location-based point',
+       'info_aucun_objet_gis' => 'No object linked to that point',
+       'info_geolocalisation' => 'Geolocation',
+       'info_id_objet' => 'N°',
+       'info_liste_gis' => 'Location-based points',
+       'info_nb_gis' => '@nb@ location-based points',
+       'info_nb_objets_gis' => '@nb@ objects linked to that point',
+       'info_numero_gis' => 'Point number',
+       'info_objet' => 'Object',
+       'info_recherche_gis_zero' => 'No result for « @cherche_gis@ ».',
+       'info_supprimer_lien' => 'Unlink',
+       'info_supprimer_liens' => 'Unlink all the points',
+       'info_voir_fiche_objet' => 'Go to page',
+
+       // L
+       'label_adress' => 'Address',
+       'label_code_postal' => 'Postal code',
+       'label_import' => 'Import',
+       'label_inserer_modele_articles' => 'linked to articles',
+       'label_inserer_modele_articles_sites' => 'linked to articles + websites',
+       'label_inserer_modele_auteurs' => 'linked to authors',
+       'label_inserer_modele_centrer_auto' => 'No automatic centring',
+       'label_inserer_modele_centrer_fichier' => 'Do not center the map on the KLM/GPX files',
+       'label_inserer_modele_controle' => 'Hide controls',
+       'label_inserer_modele_controle_type' => 'Hide types',
+       'label_inserer_modele_description' => 'Description',
+       'label_inserer_modele_documents' => 'linked to documents',
+       'label_inserer_modele_echelle' => 'Scale',
+       'label_inserer_modele_fullscreen' => 'Full screen button',
+       'label_inserer_modele_gpx' => 'GPX file to overlay',
+       'label_inserer_modele_hauteur_carte' => 'Map height',
+       'label_inserer_modele_identifiant' => 'ID',
+       'label_inserer_modele_identifiant_opt' => 'ID (optionnal)',
+       'label_inserer_modele_identifiant_placeholder' => 'id_gis',
+       'label_inserer_modele_kml' => 'KML files to overlay',
+       'label_inserer_modele_kml_gpx' => 'id_document or url',
+       'label_inserer_modele_largeur_carte' => 'Map width',
+       'label_inserer_modele_limite' => 'Maximum number of points',
+       'label_inserer_modele_localiser_visiteur' => 'Center on the visitor',
+       'label_inserer_modele_mini_carte' => 'Mini situation map',
+       'label_inserer_modele_molette' => 'Disable the scroll wheel',
+       'label_inserer_modele_mots' => 'Linked to words',
+       'label_inserer_modele_objets' => 'Point(s) category',
+       'label_inserer_modele_point_gis' => 'single point recorded',
+       'label_inserer_modele_point_libre' => 'free single point',
+       'label_inserer_modele_points' => 'Hide points',
+       'label_inserer_modele_rubriques' => 'linked to sections',
+       'label_inserer_modele_sites' => 'linked to websites',
+       'label_inserer_modele_titre_carte' => 'Map title',
+       'label_pays' => 'Country',
+       'label_rechercher_address' => 'Search for an address',
+       'label_rechercher_point' => 'Search for a point',
+       'label_region' => 'Region',
+       'label_ville' => 'Town',
+       'lat' => 'Latitude',
+       'libelle_logo_gis' => 'POINT\\\'S LOGO',
+       'lien_ajouter_gis' => 'Add this point',
+       'lon' => 'Longitude',
+
+       // T
+       'telecharger_gis' => 'Download in @format@ format',
+       'texte_ajouter_gis' => 'Add a location-based point',
+       'texte_creer_associer_gis' => 'Create and link a location-based point',
+       'texte_creer_gis' => 'Create a location-based point',
+       'texte_modifier_gis' => 'Modify the location-based point',
+       'texte_voir_gis' => 'Show the location-based point',
+       'titre_bloc_creer_point' => 'Link a new point',
+       'titre_bloc_points_lies' => 'Linked points',
+       'titre_bloc_rechercher_point' => 'Search for a point',
+       'titre_nombre_utilisation' => 'One use',
+       'titre_nombre_utilisations' => '@nb@ uses',
+       'titre_nouveau_point' => 'New point',
+       'titre_objet' => 'Title',
+
+       // Z
+       'zoom' => 'Zoom'
+);
+
+?>
diff --git a/www/plugins/gis/lang/gis_es.php b/www/plugins/gis/lang/gis_es.php
new file mode 100644 (file)
index 0000000..020bc3d
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/gis?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'aucun_gis' => 'Ningún punto',
+       'aucun_objet' => 'Ningún objeto',
+
+       // B
+       'bouton_lier' => 'Asociar este punto',
+       'bouton_supprimer_gis' => 'Eliminar definitivamente este punto',
+       'bouton_supprimer_lien' => 'Eliminar este enlace',
+
+       // C
+       'cfg_descr_gis' => 'Sistema de Información Geográfica.<br /><a href="http://www.spip-contrib.net/3887">Ir a la documentación</a>.',
+       'cfg_inf_adresse' => 'Mostrar campos adicionales de dirección (país, ciudad, región, dirección...)',
+       'cfg_inf_bing' => 'La capa Bing Aerial necesita crear una clave <a href=\'@url@\' class="spip_out">el sitio de Bing</a>.',
+       'cfg_inf_cloudmade' => 'Esta API necesita crear una clave en <a href=\'@url@\'>el sitio de CloudMade</a>.',
+       'cfg_inf_geocoder' => 'Activar las funciones del geocoder (búsqueda desde una dirección, recuperación de una dirección partiendo de coordenadas).',
+       'cfg_inf_geolocaliser_user_html5' => 'Si el navegador del usuario lo permite, su ubicación geográfica aproximada se recupera para dar la posición por defecto durante la creación de un punto.',
+       'cfg_inf_google' => 'Esta API necesita crear una clave en <a href=\'@url@\'>el sitio de GoogleMaps</a>.',
+       'cfg_inf_yandex' => 'Esta API necesita crear una clave en <a href=\'@url@\'>el sitio de Yandex</a>.',
+       'cfg_lbl_activer_objets' => 'Activar la geolocalización en los contenidos:',
+       'cfg_lbl_adresse' => 'Mostrar los campos de dirección',
+       'cfg_lbl_api' => 'API de cartografía',
+       'cfg_lbl_api_cloudmade' => 'CloudMade',
+       'cfg_lbl_api_google' => 'Google Maps v2',
+       'cfg_lbl_api_googlev3' => 'Google Maps v3',
+       'cfg_lbl_api_key_bing' => 'Clave Bing',
+       'cfg_lbl_api_key_cloudmade' => 'Clave CloudMade',
+       'cfg_lbl_api_key_google' => 'Clave GoogleMaps',
+       'cfg_lbl_api_key_yandex' => 'Clave Yandex',
+       'cfg_lbl_api_mapquest' => 'MapQuest',
+       'cfg_lbl_api_microsoft' => 'Microsoft Bing',
+       'cfg_lbl_api_openlayers' => 'OpenLayers',
+       'cfg_lbl_api_ovi' => 'Ovi Nokia',
+       'cfg_lbl_api_yandex' => 'Yandex',
+       'cfg_lbl_geocoder' => 'Geocoder',
+       'cfg_lbl_geolocaliser_user_html5' => 'Centrar el mapa en base a la ubicación del usuario durante la creación',
+       'cfg_lbl_layer_defaut' => 'Capa por defecto',
+       'cfg_lbl_layers' => 'Capas propuestas',
+       'cfg_lbl_maptype' => 'Fondo cartográfico',
+       'cfg_lbl_maptype_carte' => 'Mapa',
+       'cfg_lbl_maptype_hybride' => 'Híbrido',
+       'cfg_lbl_maptype_relief' => 'Relieve',
+       'cfg_lbl_maptype_satellite' => 'Satélite',
+       'cfg_titre_gis' => 'GIS',
+
+       // E
+       'editer_gis_editer' => 'Modificar este punto',
+       'editer_gis_explication' => 'Esta página lista todos los puntos geolocalizados del sitio.',
+       'editer_gis_nouveau' => 'Crear un nuevo punto',
+       'editer_gis_titre' => 'Puntos geolocalizados',
+       'erreur_recherche_pas_resultats' => 'Ningún punto corresponde a la búsqueda.',
+       'erreur_xmlrpc_lat_lon' => 'La latitud y la longitud deben indicarse como parámetros',
+       'explication_api_forcee' => 'La API esta impuesta por otro plugin o esqueleto.',
+       'explication_import' => 'Importar un archivo en formato GPX o KML.',
+       'explication_layer_forcee' => 'La capa se ha impuesto por otro plugin o esqueleto. ',
+       'explication_maptype_force' => 'El fondo del mapa está impuesto por otro plugin o esqueleto.',
+
+       // F
+       'formulaire_creer_gis' => 'Crear un punto geolocalizado:',
+       'formulaire_modifier_gis' => 'Modificar el punto geolocalizado:',
+
+       // G
+       'gis_pluriel' => 'Puntos geolocalizados',
+       'gis_singulier' => 'Punto geolocalizado',
+
+       // I
+       'icone_gis_tous' => 'Puntos geolocalizados',
+       'info_1_gis' => 'Un punto geolocalizado',
+       'info_1_objet_gis' => '1 objeto asociado a este punto',
+       'info_aucun_gis' => 'Ningún punto geolocalizado',
+       'info_aucun_objet_gis' => 'Ningún objeto asociado a este punto',
+       'info_geolocalisation' => 'Geolocalización',
+       'info_id_objet' => 'N°',
+       'info_liste_gis' => 'Puntos geolocalizados',
+       'info_nb_gis' => '@nb@ puntos geolocalizados',
+       'info_nb_objets_gis' => '@nb@ objetos asociados a este punto',
+       'info_numero_gis' => 'Punto número',
+       'info_objet' => 'Objeto',
+       'info_recherche_gis_zero' => 'Ningún resultados para «@cherche_gis@».',
+       'info_supprimer_lien' => 'Desunir',
+       'info_supprimer_liens' => 'Desunir todos los puntos',
+       'info_voir_fiche_objet' => 'Ver la ficha',
+
+       // L
+       'label_adress' => 'Dirección',
+       'label_code_postal' => 'Código postal',
+       'label_import' => 'Importar',
+       'label_inserer_modele_articles' => 'asociados a los artículos',
+       'label_inserer_modele_articles_sites' => 'asociados a los artículos + sitios',
+       'label_inserer_modele_auteurs' => 'asociados a los autores',
+       'label_inserer_modele_centrer_auto' => 'Ningún autocentrado',
+       'label_inserer_modele_centrer_fichier' => 'No centrar el mapa en los archivos KLM/GPX',
+       'label_inserer_modele_controle' => 'Esconder los controles',
+       'label_inserer_modele_controle_type' => 'Esconder los tipos',
+       'label_inserer_modele_description' => 'Descripción',
+       'label_inserer_modele_documents' => 'asociados a los documentos',
+       'label_inserer_modele_echelle' => 'Escala',
+       'label_inserer_modele_fullscreen' => 'Botón de pantalla completa',
+       'label_inserer_modele_gpx' => 'Archivo GPX para sobreponer',
+       'label_inserer_modele_hauteur_carte' => 'Altura del mapa',
+       'label_inserer_modele_identifiant' => 'Identificador',
+       'label_inserer_modele_identifiant_opt' => 'Identificador (opcional)',
+       'label_inserer_modele_identifiant_placeholder' => 'id_gis',
+       'label_inserer_modele_kml' => 'Archivo KML para sobreponer',
+       'label_inserer_modele_kml_gpx' => 'id_document o url',
+       'label_inserer_modele_largeur_carte' => 'Anchura del mapa',
+       'label_inserer_modele_limite' => 'Número máximo de puntos',
+       'label_inserer_modele_localiser_visiteur' => 'Centrar en el visitante',
+       'label_inserer_modele_mini_carte' => 'Mini mapa de situación',
+       'label_inserer_modele_molette' => 'Desactivar la rueda',
+       'label_inserer_modele_mots' => 'asociados a las palabras',
+       'label_inserer_modele_objets' => 'Tipo de punto(s)',
+       'label_inserer_modele_point_gis' => 'punto único registrado',
+       'label_inserer_modele_point_libre' => 'punto único libre',
+       'label_inserer_modele_points' => 'Esconder los puntos',
+       'label_inserer_modele_rubriques' => 'asociados a las secciones',
+       'label_inserer_modele_sites' => 'asociados a los sitios',
+       'label_inserer_modele_titre_carte' => 'Título del mapa',
+       'label_pays' => 'País',
+       'label_rechercher_address' => 'Buscar una dirección',
+       'label_rechercher_point' => 'Buscar un punto',
+       'label_region' => 'Región',
+       'label_ville' => 'Ciudad',
+       'lat' => 'Latitud',
+       'libelle_logo_gis' => 'LOGOTIPO DEL PUNTO',
+       'lien_ajouter_gis' => 'Añadir este punto',
+       'lon' => 'Longitud',
+
+       // T
+       'telecharger_gis' => 'Descargar en formato @format@',
+       'texte_ajouter_gis' => 'Añadir un punto geolocalizado',
+       'texte_creer_associer_gis' => 'Crear y asociar un punto geolocalizado',
+       'texte_creer_gis' => 'Crear un punto geolocalizado',
+       'texte_modifier_gis' => 'Modificar el punto geolocalizado',
+       'texte_voir_gis' => 'Ver el punto geolocalizado',
+       'titre_bloc_creer_point' => 'Asociar un nuevo punto',
+       'titre_bloc_points_lies' => 'Puntos asociados',
+       'titre_bloc_rechercher_point' => 'Buscar un punto',
+       'titre_nombre_utilisation' => 'Una utilización',
+       'titre_nombre_utilisations' => '@nb@ utilizaciones',
+       'titre_nouveau_point' => 'Nuevo punto',
+       'titre_objet' => 'Título',
+
+       // Z
+       'zoom' => 'Zoom'
+);
+
+?>
diff --git a/www/plugins/gis/lang/gis_fr.php b/www/plugins/gis/lang/gis_fr.php
new file mode 100644 (file)
index 0000000..70e25c0
--- /dev/null
@@ -0,0 +1,154 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/gis/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'aucun_gis' => 'Aucun point',
+       'aucun_objet' => 'Aucun objet',
+
+       // B
+       'bouton_lier' => 'Lier ce point',
+       'bouton_supprimer_gis' => 'Supprimer définitivement ce point',
+       'bouton_supprimer_lien' => 'Supprimer ce lien',
+
+       // C
+       'cfg_descr_gis' => 'Système d\'Information Géographique.<br /><a href="http://www.spip-contrib.net/3887" class="spip_out">Accéder la documentation</a>.',
+       'cfg_inf_adresse' => 'Affiche des champs supplémentaires d\'adresse (pays, ville, région, adresse...)',
+       'cfg_inf_bing' => 'La couche Bing Aerial nécessite une clé à créer sur <a href=\'@url@\' class="spip_out">le site de Bing</a>.',
+       'cfg_inf_cloudmade' => 'Cette API nécessite une clé à créer sur <a href=\'@url@\' class="spip_out">le site de CloudMade</a>.',
+       'cfg_inf_geocoder' => 'Activer les fonctions du geocoder (recherche à partir d\'une adresse, récupération de l\'adresse à partir des coordonnées).',
+       'cfg_inf_geolocaliser_user_html5' => 'Si le navigateur de l\'utilisateur le permet, son emplacement géographique approximatif est récupéré pour donner la position par défaut lors de la création d\'un point.',
+       'cfg_inf_google' => 'Cette API nécessite une clé à créer sur <a href=\'@url@\' class="spip_out">le site de GoogleMaps</a>.',
+       'cfg_inf_yandex' => 'Cette API nécessite une clé à créer sur <a href=\'@url@\' class="spip_out">le site de Yandex</a>.',
+       'cfg_lbl_activer_objets' => 'Activer la géolocalisation sur les contenus :',
+       'cfg_lbl_adresse' => 'Afficher les champs d\'adresse',
+       'cfg_lbl_api' => 'API de cartographie',
+       'cfg_lbl_api_cloudmade' => 'CloudMade',
+       'cfg_lbl_api_google' => 'Google Maps v2',
+       'cfg_lbl_api_googlev3' => 'Google Maps v3',
+       'cfg_lbl_api_key_bing' => 'Clé Bing',
+       'cfg_lbl_api_key_cloudmade' => 'Clé CloudMade',
+       'cfg_lbl_api_key_google' => 'Clé GoogleMaps',
+       'cfg_lbl_api_key_yandex' => 'Clé Yandex',
+       'cfg_lbl_api_mapquest' => 'MapQuest',
+       'cfg_lbl_api_microsoft' => 'Microsoft Bing',
+       'cfg_lbl_api_openlayers' => 'OpenLayers',
+       'cfg_lbl_api_ovi' => 'Ovi Nokia',
+       'cfg_lbl_api_yandex' => 'Yandex',
+       'cfg_lbl_geocoder' => 'Geocoder',
+       'cfg_lbl_geolocaliser_user_html5' => 'Centrer la carte sur l\'emplacement de l\'utilisateur à la création',
+       'cfg_lbl_layer_defaut' => 'Couche par défaut',
+       'cfg_lbl_layers' => 'Couches proposées',
+       'cfg_lbl_maptype' => 'Fond cartographique',
+       'cfg_lbl_maptype_carte' => 'Carte',
+       'cfg_lbl_maptype_hybride' => 'Hybride',
+       'cfg_lbl_maptype_relief' => 'Relief',
+       'cfg_lbl_maptype_satellite' => 'Satellite',
+       'cfg_titre_gis' => 'GIS',
+
+       // E
+       'editer_gis_editer' => 'Modifier ce point',
+       'editer_gis_explication' => 'Cette page liste l\'ensemble des points géolocalisés du site.',
+       'editer_gis_nouveau' => 'Créer un nouveau point',
+       'editer_gis_titre' => 'Les points géolocalisés',
+       'erreur_recherche_pas_resultats' => 'Aucun point ne correspond à la recherche.',
+       'erreur_xmlrpc_lat_lon' => 'La latitude et la longitude doivent être passées en argument',
+       'explication_api_forcee' => 'L\'API est imposée par un autre plugin ou squelette.',
+       'explication_import' => 'Importer un fichier au format GPX ou KML.',
+       'explication_layer_forcee' => 'La couche est imposée par un autre plugin ou un squelette.',
+       'explication_maptype_force' => 'Le fond cartographique est imposé par un autre plugin ou squelette.',
+
+       // F
+       'formulaire_creer_gis' => 'Créer un point géolocalisé :',
+       'formulaire_modifier_gis' => 'Modifier le point géolocalisé :',
+
+       // G
+       'gis_pluriel' => 'Points géolocalisés',
+       'gis_singulier' => 'Point géolocalisé',
+
+       // I
+       'icone_gis_tous' => 'Points géolocalisés',
+       'info_1_gis' => 'Un point géolocalisé',
+       'info_1_objet_gis' => '1 objet lié à ce point',
+       'info_aucun_gis' => 'Aucun point géolocalisé',
+       'info_aucun_objet_gis' => 'Aucun objet lié à ce point',
+       'info_geolocalisation' => 'Géolocalisation',
+       'info_id_objet' => 'N°',
+       'info_liste_gis' => 'Points géolocalisés',
+       'info_nb_gis' => '@nb@ points géolocalisés',
+       'info_nb_objets_gis' => '@nb@ objets liés à ce point',
+       'info_numero_gis' => 'Point numéro',
+       'info_objet' => 'Objet',
+       'info_recherche_gis_zero' => 'Aucun résultat pour « @cherche_gis@ ».',
+       'info_supprimer_lien' => 'Détacher',
+       'info_supprimer_liens' => 'Détacher tous les points',
+       'info_voir_fiche_objet' => 'Voir la fiche',
+
+       // L
+       'label_adress' => 'Adresse',
+       'label_code_postal' => 'Code postal',
+       'label_import' => 'Importer',
+       'label_inserer_modele_articles' => 'liés aux articles',
+       'label_inserer_modele_articles_sites' => 'liés aux articles + sites',
+       'label_inserer_modele_auteurs' => 'liés aux auteurs',
+       'label_inserer_modele_centrer_auto' => 'Pas de centrage auto',
+       'label_inserer_modele_centrer_fichier' => 'Ne pas centrer la carte sur les fichiers KLM/GPX',
+       'label_inserer_modele_controle' => 'Cacher les contrôles',
+       'label_inserer_modele_controle_type' => 'Cacher les types',
+       'label_inserer_modele_description' => 'Description',
+       'label_inserer_modele_documents' => 'liés aux documents',
+       'label_inserer_modele_echelle' => 'Echelle',
+       'label_inserer_modele_fullscreen' => 'Bouton plein écran',
+       'label_inserer_modele_gpx' => 'Fichier GPX à superposer',
+       'label_inserer_modele_hauteur_carte' => 'Hauteur de la carte',
+       'label_inserer_modele_identifiant' => 'Identifiant',
+       'label_inserer_modele_identifiant_opt' => 'Identifiant (optionnel)',
+       'label_inserer_modele_identifiant_placeholder' => 'id_gis',
+       'label_inserer_modele_kml' => 'Fichier KML à superposer',
+       'label_inserer_modele_kml_gpx' => 'id_document ou url',
+       'label_inserer_modele_largeur_carte' => 'Largeur de la carte',
+       'label_inserer_modele_limite' => 'Nombre de points maximum',
+       'label_inserer_modele_localiser_visiteur' => 'Centrer sur le visiteur',
+       'label_inserer_modele_mini_carte' => 'Mini carte de situation',
+       'label_inserer_modele_molette' => 'Désactiver la molette',
+       'label_inserer_modele_mots' => 'liés aux mots',
+       'label_inserer_modele_objets' => 'Type de point(s)',
+       'label_inserer_modele_point_gis' => 'point unique enregistré',
+       'label_inserer_modele_point_libre' => 'point unique libre',
+       'label_inserer_modele_points' => 'Cacher les points',
+       'label_inserer_modele_rubriques' => 'liés aux rubriques',
+       'label_inserer_modele_sites' => 'liés aux sites',
+       'label_inserer_modele_titre_carte' => 'Titre de la carte',
+       'label_pays' => 'Pays',
+       'label_rechercher_address' => 'Rechercher une adresse',
+       'label_rechercher_point' => 'Rechercher un point',
+       'label_region' => 'Région',
+       'label_ville' => 'Ville',
+       'lat' => 'Latitude',
+       'libelle_logo_gis' => 'LOGO DU POINT',
+       'lien_ajouter_gis' => 'Ajouter ce point',
+       'lon' => 'Longitude',
+
+       // T
+       'telecharger_gis' => 'Télécharger au format @format@',
+       'texte_ajouter_gis' => 'Ajouter un point géolocalisé',
+       'texte_creer_associer_gis' => 'Créer et associer un point géolocalisé',
+       'texte_creer_gis' => 'Créer un point géolocalisé',
+       'texte_modifier_gis' => 'Modifier le point géolocalisé',
+       'texte_voir_gis' => 'Voir le point géolocalisé',
+       'titre_bloc_creer_point' => 'Lier un nouveau point',
+       'titre_bloc_points_lies' => 'Points liés',
+       'titre_bloc_rechercher_point' => 'Rechercher un point',
+       'titre_nombre_utilisation' => 'Une utilisation',
+       'titre_nombre_utilisations' => '@nb@ utilisations',
+       'titre_nouveau_point' => 'Nouveau point',
+       'titre_objet' => 'Titre',
+
+       // Z
+       'zoom' => 'Zoom'
+);
+
+?>
diff --git a/www/plugins/gis/lang/gis_ru.php b/www/plugins/gis/lang/gis_ru.php
new file mode 100644 (file)
index 0000000..0a3c096
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/gis?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'aucun_gis' => 'Нет ни одной точки на карте',
+       'aucun_objet' => 'Нет связанных объектов',
+
+       // B
+       'bouton_lier' => 'Связать точку',
+       'bouton_supprimer_gis' => 'Удалить точку',
+       'bouton_supprimer_lien' => 'Удалить связь',
+
+       // C
+       'cfg_descr_gis' => 'Географическая Информационная Система (GIS).<br /><a href="http://www.spip-contrib.net/3887" class="spip_out">Документация</a>.',
+       'cfg_inf_adresse' => 'Показываются дополнительные поля для ввода адреса (страна, город, область, адрес...)',
+       'cfg_inf_bing' => 'Для использования карты Bing Aerial необходимо создать ключ  <a href=\'@url@\' class="spip_out">на сайте Bing</a>.',
+       'cfg_inf_cloudmade' => 'Для использования карты необходимо создать ключ  <a href=\'@url@\' class="spip_out">на сайте CloudMade</a>.',
+       'cfg_inf_geocoder' => 'Включить функцию геопоиска (поиск точки на карте по адресу).',
+       'cfg_inf_geolocaliser_user_html5' => 'Новая карта центрируется по расположению пользователя ( если позволяет его браузер).',
+       'cfg_inf_google' => 'Для работы с картой необходим API ключ, который  можно создать на <a href=\'@url@\' class="spip_out">сайте  GoogleMaps</a>.',
+       'cfg_inf_yandex' => 'Для работы с картой необходим API ключ. <a href=\'@url@\' class="spip_out"> Получить на сайте Yandex</a>.',
+       'cfg_lbl_activer_objets' => 'Связывать карту с объектами:',
+       'cfg_lbl_adresse' => 'Показать поля для адреса',
+       'cfg_lbl_api' => 'Используемое API',
+       'cfg_lbl_api_cloudmade' => 'CloudMade',
+       'cfg_lbl_api_google' => 'Google Maps v2',
+       'cfg_lbl_api_googlev3' => 'Google Maps v3',
+       'cfg_lbl_api_key_bing' => 'API ключ  Bing',
+       'cfg_lbl_api_key_cloudmade' => 'API ключ CloudMade ',
+       'cfg_lbl_api_key_google' => 'API ключ  GoogleMaps',
+       'cfg_lbl_api_key_yandex' => 'Yandex API ключ',
+       'cfg_lbl_api_mapquest' => 'MapQuest',
+       'cfg_lbl_api_microsoft' => 'Microsoft Bing',
+       'cfg_lbl_api_openlayers' => 'OpenLayers',
+       'cfg_lbl_api_ovi' => 'Ovi Nokia',
+       'cfg_lbl_api_yandex' => 'Yandex',
+       'cfg_lbl_geocoder' => 'Geocoder',
+       'cfg_lbl_geolocaliser_user_html5' => 'Центрировать карту по месту расположения пользователя, создавшего карту',
+       'cfg_lbl_layer_defaut' => 'Слой по умолчанию',
+       'cfg_lbl_layers' => 'Предложенные слои',
+       'cfg_lbl_maptype' => 'Тип карты',
+       'cfg_lbl_maptype_carte' => 'Карта',
+       'cfg_lbl_maptype_hybride' => 'Гибрид',
+       'cfg_lbl_maptype_relief' => 'Рельеф',
+       'cfg_lbl_maptype_satellite' => 'Спутник',
+       'cfg_titre_gis' => 'GIS',
+
+       // E
+       'editer_gis_editer' => 'Изменить точку',
+       'editer_gis_explication' => 'Список всех точек, используемых на вашем сайте.',
+       'editer_gis_nouveau' => 'Создать точку',
+       'editer_gis_titre' => 'Точки на карте',
+       'erreur_recherche_pas_resultats' => 'Нет точек, соответствующих поисковому запросу.',
+       'erreur_xmlrpc_lat_lon' => 'В качестве аргумента должна быть указанна долгота и широта',
+       'explication_api_forcee' => 'На API накладывается другой плагин или шаблон.',
+       'explication_import' => 'Импортировать GPX или KML файл.',
+       'explication_layer_forcee' => 'На слой накладывается другой плагин или шаблон.',
+       'explication_maptype_force' => 'На базовую карту накладывается другой плагин или шаблон.',
+
+       // F
+       'formulaire_creer_gis' => 'Создание новой точки :',
+       'formulaire_modifier_gis' => 'Изменить точку :',
+
+       // G
+       'gis_pluriel' => 'Точки на карте',
+       'gis_singulier' => 'Точка на карте',
+
+       // I
+       'icone_gis_tous' => 'Точки на карте',
+       'info_1_gis' => 'Точка на карте',
+       'info_1_objet_gis' => '1 материал связан с точкой',
+       'info_aucun_gis' => 'Нет точек на карте',
+       'info_aucun_objet_gis' => 'У точки нет связанных материалов',
+       'info_geolocalisation' => 'Расположение (Geolocation)',
+       'info_id_objet' => 'N°',
+       'info_liste_gis' => 'Точки на карте',
+       'info_nb_gis' => '@nb@ точек на карте',
+       'info_nb_objets_gis' => '@nb@ объектов связано с точкой',
+       'info_numero_gis' => 'ID точки',
+       'info_objet' => 'Объект',
+       'info_recherche_gis_zero' => 'Ничего не найдено по запросу « @cherche_gis@ ».',
+       'info_supprimer_lien' => 'Убрать',
+       'info_supprimer_liens' => 'Убрать все точки',
+       'info_voir_fiche_objet' => 'Перейти на страницу',
+
+       // L
+       'label_adress' => 'Адрес',
+       'label_code_postal' => 'Индекс',
+       'label_import' => 'Импорт',
+       'label_inserer_modele_articles' => 'связано со статьями',
+       'label_inserer_modele_articles_sites' => 'связано с авторами и сайтами',
+       'label_inserer_modele_auteurs' => 'связано с авторами',
+       'label_inserer_modele_centrer_auto' => 'Без автоматического центрирования',
+       'label_inserer_modele_centrer_fichier' => 'Не центрировать карту по KLM/GPX файлу.',
+       'label_inserer_modele_controle' => 'Спрятать управление картой',
+       'label_inserer_modele_controle_type' => 'Спрятать выбор типа карты',
+       'label_inserer_modele_description' => 'Описание',
+       'label_inserer_modele_documents' => 'связано с документами',
+       'label_inserer_modele_echelle' => 'Масштаб',
+       'label_inserer_modele_fullscreen' => 'Переход в полноэкранный режим',
+       'label_inserer_modele_gpx' => 'GPX файл для наложения',
+       'label_inserer_modele_hauteur_carte' => 'Высота карта',
+       'label_inserer_modele_identifiant' => 'ID',
+       'label_inserer_modele_identifiant_opt' => 'ID (не обязательно)',
+       'label_inserer_modele_identifiant_placeholder' => 'id_gis',
+       'label_inserer_modele_kml' => 'KML файл для наложения',
+       'label_inserer_modele_kml_gpx' => 'id_document или url',
+       'label_inserer_modele_largeur_carte' => 'Ширина карты',
+       'label_inserer_modele_limite' => 'Максимальное количество точек',
+       'label_inserer_modele_localiser_visiteur' => 'Центрировать по посетителю',
+       'label_inserer_modele_mini_carte' => 'Мини карта',
+       'label_inserer_modele_molette' => 'Отключить прокрутку колесиком мышки',
+       'label_inserer_modele_mots' => 'связано с ключами',
+       'label_inserer_modele_objets' => 'Виды точек',
+       'label_inserer_modele_point_gis' => 'записана одиночная точка',
+       'label_inserer_modele_point_libre' => 'свободная точка',
+       'label_inserer_modele_points' => 'Спрятать точки',
+       'label_inserer_modele_rubriques' => 'связано с разделами',
+       'label_inserer_modele_sites' => 'связано с сайтами',
+       'label_inserer_modele_titre_carte' => 'Название карты',
+       'label_pays' => 'Страна',
+       'label_rechercher_address' => 'Искать по адресу',
+       'label_rechercher_point' => 'Найти точку',
+       'label_region' => 'Область',
+       'label_ville' => 'Город',
+       'lat' => 'Широта',
+       'libelle_logo_gis' => 'Лого точки',
+       'lien_ajouter_gis' => 'Добавить точку',
+       'lon' => 'Долгота',
+
+       // T
+       'telecharger_gis' => 'Скачать в @format@ формате',
+       'texte_ajouter_gis' => 'Добавить точку на карте',
+       'texte_creer_associer_gis' => 'Создать точку и связать ее',
+       'texte_creer_gis' => 'Создать точку',
+       'texte_modifier_gis' => 'Изменить точку',
+       'texte_voir_gis' => 'Показать точку на карте',
+       'titre_bloc_creer_point' => 'Новая точка на карте',
+       'titre_bloc_points_lies' => 'Связанные точки',
+       'titre_bloc_rechercher_point' => 'Найти существующую точку',
+       'titre_nombre_utilisation' => 'Используется 1 раз',
+       'titre_nombre_utilisations' => 'используется @nb@ раз',
+       'titre_nouveau_point' => 'Новая точка',
+       'titre_objet' => 'Название',
+
+       // Z
+       'zoom' => 'Zoom'
+);
+
+?>
diff --git a/www/plugins/gis/lang/gis_sk.php b/www/plugins/gis/lang/gis_sk.php
new file mode 100644 (file)
index 0000000..c3b4b4c
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/gis?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'aucun_gis' => 'Žiaden bod',
+       'aucun_objet' => 'Žiaden objekt',
+
+       // B
+       'bouton_lier' => 'Prepojiť tento bod',
+       'bouton_supprimer_gis' => 'Natrvalo odstrániť tento bod',
+       'bouton_supprimer_lien' => 'Odstrániť tento odkaz',
+
+       // C
+       'cfg_descr_gis' => 'Geografický informačný systém.<br /><a href="http://www.spip-contrib.net/3887" class="spip_out">Prejsť na dokumentáciu.</a>',
+       'cfg_inf_adresse' => 'Zobrazí ďalšie polia adresy (krajinu, mesto, štát, adresu a pod.)',
+       'cfg_inf_bing' => 'Vrstva Bing Aerial si vyžaduje, aby ste <a href=\'@url@\' class="spip_out">na stránke vyhľadávača Bing</a> vytvorili kľúč.',
+       'cfg_inf_cloudmade' => 'Táto aplikácia potrebuje kľúč na vytvorenie <a href=\'@url@\' class="spip_out">stránky v Cloude.</a>',
+       'cfg_inf_geocoder' => 'Aktivovať funkciu geokódera (vyhľadávanie z jednej adresy, zistenie adresy zo súradníc).',
+       'cfg_inf_geolocaliser_user_html5' => 'Ak to povoľuje prehliadač používateľa, na určenie predvolenej polohy pri vytváraní nového bodu sa ukladá približná geografická poloha používateľa.',
+       'cfg_inf_google' => 'Táto aplikácia potrebuje kľúč, ktorý si treba vytvoriť na <a href=\'@url@\' class="spip_out">stránke GoogleMaps.</a>',
+       'cfg_inf_yandex' => 'Táto aplikácia potrebuje kľúč na vytvorenie <a href=\'@url@\' class="spip_out">stránky v Yandexe.</a>',
+       'cfg_lbl_activer_objets' => 'Aktivovať geolokalizáciu obsahu:',
+       'cfg_lbl_adresse' => 'Zobraziť polia adresy',
+       'cfg_lbl_api' => 'Geolokačná API',
+       'cfg_lbl_api_cloudmade' => 'CloudMade',
+       'cfg_lbl_api_google' => 'Google Maps v2',
+       'cfg_lbl_api_googlev3' => 'Google Maps v3',
+       'cfg_lbl_api_key_bing' => 'Kľúč pre Bing',
+       'cfg_lbl_api_key_cloudmade' => 'Kľúč CloudMade',
+       'cfg_lbl_api_key_google' => 'Kľúč GoogleMaps',
+       'cfg_lbl_api_key_yandex' => 'Kľúč Yandex',
+       'cfg_lbl_api_mapquest' => 'MapQuest',
+       'cfg_lbl_api_microsoft' => 'Microsoft Bing',
+       'cfg_lbl_api_openlayers' => 'OpenLayers',
+       'cfg_lbl_api_ovi' => 'Ovi Nokia',
+       'cfg_lbl_api_yandex' => 'Yandex',
+       'cfg_lbl_geocoder' => 'Geocoder',
+       'cfg_lbl_geolocaliser_user_html5' => 'Pri vytváraní vycentrujte mapu na polohe používateľa',
+       'cfg_lbl_layer_defaut' => 'Predvolená vrstva',
+       'cfg_lbl_layers' => 'Navrhované vrstvy',
+       'cfg_lbl_maptype' => 'Základná mapa',
+       'cfg_lbl_maptype_carte' => 'Mapa',
+       'cfg_lbl_maptype_hybride' => 'Zmiešaná',
+       'cfg_lbl_maptype_relief' => 'Reliéf',
+       'cfg_lbl_maptype_satellite' => 'Satelitná',
+       'cfg_titre_gis' => 'GIS',
+
+       // E
+       'editer_gis_editer' => 'Upraviť tento bod',
+       'editer_gis_explication' => 'Táto stránka uvádza všetky geolokalizované body na webe.',
+       'editer_gis_nouveau' => 'Vytvoriť nový bod',
+       'editer_gis_titre' => 'Geolokalizované body',
+       'erreur_recherche_pas_resultats' => 'Vyhľadávania sa netýka žiaden bod.',
+       'erreur_xmlrpc_lat_lon' => 'Zemepisná šírka a dĺžka musia byť odovzdané ako parameter',
+       'explication_api_forcee' => 'Túto aplikáciu používa iný zásuvný modul alebo iná šablóna.',
+       'explication_import' => 'Nahrá súbor vo formáte GPX alebo KML.',
+       'explication_layer_forcee' => 'Vrstvu zaviedol iný zásuvný modul alebo iná šablóna.',
+       'explication_maptype_force' => 'Základnú mapu si vyžaduje iný zásuvný modul alebo šablóna.',
+
+       // F
+       'formulaire_creer_gis' => 'Vytvoriť geolokalizovaný bod:',
+       'formulaire_modifier_gis' => 'Upraviť geolokalizovaný bod:',
+
+       // G
+       'gis_pluriel' => 'Geolokalizované body',
+       'gis_singulier' => 'Geolokalizovaný bod',
+
+       // I
+       'icone_gis_tous' => 'Geolokalizované body',
+       'info_1_gis' => 'Jeden geolokalizovaný bod',
+       'info_1_objet_gis' => '1 objekt prepojený s týmto bodom',
+       'info_aucun_gis' => 'Žiaden geolokalizovaný bod',
+       'info_aucun_objet_gis' => 'Žiaden objekt prepojený s týmto bodom',
+       'info_geolocalisation' => 'Geolokalizácia',
+       'info_id_objet' => 'Č.',
+       'info_liste_gis' => 'Geolokalizované body',
+       'info_nb_gis' => '@nb@ geolokalizovaných bodov',
+       'info_nb_objets_gis' => '@nb@ objektov prepojených s týmto bodom',
+       'info_numero_gis' => 'Bod číslo',
+       'info_objet' => 'Objekt',
+       'info_recherche_gis_zero' => 'Žiadne výsledky pre "@cherche_gis@".',
+       'info_supprimer_lien' => 'Zrušiť prepojenie',
+       'info_supprimer_liens' => 'Zrušiť všetky body',
+       'info_voir_fiche_objet' => 'Prejsť na stránku',
+
+       // L
+       'label_adress' => 'Adresa',
+       'label_code_postal' => 'PSČ',
+       'label_import' => 'Nahrať',
+       'label_inserer_modele_articles' => 'liés aux articles', # NEW
+       'label_inserer_modele_articles_sites' => 'liés aux articles + sites', # NEW
+       'label_inserer_modele_auteurs' => 'liés aux auteurs', # NEW
+       'label_inserer_modele_centrer_auto' => 'Pas de centrage auto', # NEW
+       'label_inserer_modele_centrer_fichier' => 'Ne pas centrer la carte sur les fichiers KLM/GPX', # NEW
+       'label_inserer_modele_controle' => 'Cacher les contrôles', # NEW
+       'label_inserer_modele_controle_type' => 'Cacher les types', # NEW
+       'label_inserer_modele_description' => 'Description', # NEW
+       'label_inserer_modele_documents' => 'liés aux documents', # NEW
+       'label_inserer_modele_echelle' => 'Echelle', # NEW
+       'label_inserer_modele_fullscreen' => 'Bouton plein écran', # NEW
+       'label_inserer_modele_gpx' => 'Fichier GPX à superposer', # NEW
+       'label_inserer_modele_hauteur_carte' => 'Hauteur de la carte', # NEW
+       'label_inserer_modele_identifiant' => 'Identifiant', # NEW
+       'label_inserer_modele_identifiant_opt' => 'Identifiant (optionnel)', # NEW
+       'label_inserer_modele_identifiant_placeholder' => 'id_gis', # NEW
+       'label_inserer_modele_kml' => 'Fichier KML à superposer', # NEW
+       'label_inserer_modele_kml_gpx' => 'id_document ou url', # NEW
+       'label_inserer_modele_largeur_carte' => 'Largeur de la carte', # NEW
+       'label_inserer_modele_limite' => 'Nombre de points maximum', # NEW
+       'label_inserer_modele_localiser_visiteur' => 'Centrer sur le visiteur', # NEW
+       'label_inserer_modele_mini_carte' => 'Mini carte de situation', # NEW
+       'label_inserer_modele_molette' => 'Désactiver la molette', # NEW
+       'label_inserer_modele_mots' => 'liés aux mots', # NEW
+       'label_inserer_modele_objets' => 'Type de point(s)', # NEW
+       'label_inserer_modele_point_gis' => 'point unique enregistré', # NEW
+       'label_inserer_modele_point_libre' => 'point unique libre', # NEW
+       'label_inserer_modele_points' => 'Cacher les points', # NEW
+       'label_inserer_modele_rubriques' => 'liés aux rubriques', # NEW
+       'label_inserer_modele_sites' => 'liés aux sites', # NEW
+       'label_inserer_modele_titre_carte' => 'Titre de la carte', # NEW
+       'label_pays' => 'Krajina',
+       'label_rechercher_address' => 'Vyhľadať adresu',
+       'label_rechercher_point' => 'Vyhľadať bod',
+       'label_region' => 'Región (kraj)',
+       'label_ville' => 'Mesto',
+       'lat' => 'Zemepisná šírka',
+       'libelle_logo_gis' => 'LOGO BODU',
+       'lien_ajouter_gis' => 'Pridať tento bod',
+       'lon' => 'Zemepisná dĺžka',
+
+       // T
+       'telecharger_gis' => 'Stiahnuť vo formáte @format@',
+       'texte_ajouter_gis' => 'Pridať geolokalizovaný bod',
+       'texte_creer_associer_gis' => 'Vytvoriť a prepojiť geolokalizovaný bod',
+       'texte_creer_gis' => 'Vytvoriť geolokalizovaný bod',
+       'texte_modifier_gis' => 'Upraviť geolokalizovaný bod',
+       'texte_voir_gis' => 'Zobraziť geolokalizovaný bod',
+       'titre_bloc_creer_point' => 'Prepojiť nový bod',
+       'titre_bloc_points_lies' => 'Prepojené body',
+       'titre_bloc_rechercher_point' => 'Vyhľadať bod',
+       'titre_nombre_utilisation' => 'Jedno použitie',
+       'titre_nombre_utilisations' => '@nb@ použití',
+       'titre_nouveau_point' => 'Nový bod',
+       'titre_objet' => 'Názov',
+
+       // Z
+       'zoom' => 'Lupa'
+);
+
+?>
diff --git a/www/plugins/gis/lang/paquet-gis.xml b/www/plugins/gis/lang/paquet-gis.xml
new file mode 100644 (file)
index 0000000..10e313f
--- /dev/null
@@ -0,0 +1,15 @@
+<traduction module="paquet-gis" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/gis/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/gis/lang/paquet-gis_en.php b/www/plugins/gis/lang/paquet-gis_en.php
new file mode 100644 (file)
index 0000000..9a87053
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // G
+       'gis_description' => 'This plugin allows you to create location-based points that can be attached to SPIP objects to display them on maps in the pages of your site. They can use the tiles from different maps vendors through the Leaflet library.',
+       'gis_slogan' => 'Geographic Information System'
+);
+
+?>
diff --git a/www/plugins/gis/lang/paquet-gis_es.php b/www/plugins/gis/lang/paquet-gis_es.php
new file mode 100644 (file)
index 0000000..c433e2f
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // G
+       'gis_description' => 'Este plugin permite crear puntos geolocalizados que pueden adjuntarse a los objetos de SPIP a fin de mostrarlos en los mapas de las páginas de su sitio web. Éstos útlimos pueden utilizar las tejas de diferentes proveedores gracias a la librería Leaflet. ',
+       'gis_slogan' => 'Sistema de información geográfica'
+);
+
+?>
diff --git a/www/plugins/gis/lang/paquet-gis_fr.php b/www/plugins/gis/lang/paquet-gis_fr.php
new file mode 100644 (file)
index 0000000..8440ef5
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/gis/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // G
+       'gis_description' => 'Ce plugin permet de créer des points géolocalisés qui peuvent être attachés aux objets de SPIP afin de les afficher sur des cartes dans les pages de votre site. Ces dernières peuvent utiliser les tuiles de différents fournisseurs grâce à la librairie Leaflet.',
+       'gis_slogan' => 'Système d\'information géographique'
+);
+
+?>
diff --git a/www/plugins/gis/lang/paquet-gis_ru.php b/www/plugins/gis/lang/paquet-gis_ru.php
new file mode 100644 (file)
index 0000000..5a85d3b
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // G
+       'gis_description' => 'Плагин GIS позволяет создавать элементы на карте и привязвать их к существующим объектам SPIP. Вы можете использовать созданные карты на страницах своего сайта. Могут использовать разные карты, доступ к которым обеспечивается при помощи библиотеки Leaflet.',
+       'gis_slogan' => 'Географическая  Информационная Система (GIS)'
+);
+
+?>
diff --git a/www/plugins/gis/lang/paquet-gis_sk.php b/www/plugins/gis/lang/paquet-gis_sk.php
new file mode 100644 (file)
index 0000000..50cfd09
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-gis?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // G
+       'gis_description' => 'Tento zásuvný modul umožňuje vytvárať zemepisné body, ktoré môžete pripojiť k objektom SPIPu, aby sa dali zobraziť na mapách na stránkach vášho webu. Vďaka knižnici Leaflet môžete používať rozhranie od rôznych výrobcov.',
+       'gis_slogan' => 'Geografický informačný systém'
+);
+
+?>
diff --git a/www/plugins/gis/modeles/carte_gis.html b/www/plugins/gis/modeles/carte_gis.html
new file mode 100644 (file)
index 0000000..a9cc086
--- /dev/null
@@ -0,0 +1,131 @@
+[(#REM)\r
+\r
+Modele carte_gis\r
+----------------\r
+\r
+Parametres possibles :\r
+\r
+- id_map|id_carte_gis = 1          id de la carte\r
+- lat|latit|latitude = 48.3        latitude du centre de la carte\r
+- lon|lonxit|longitude = -4.7      longitude du centre de la carte\r
+- zoom = 5                         zoom de la carte\r
+- maxZoom = 13                     zoom maximum autorisé\r
+\r
+- sw_lat = lat - 10°               latitude du sud-ouest de la bounding box\r
+- sw_lon = lon - 10°               longitude du sud-ouest de la bounding box\r
+- ne_lat = lat + 10°               latitude du nord-est de la bounding box\r
+- ne_lon = lon + 10°               longitude du nord-est de la bounding box\r
+\r
+- width|largeur = 100%             largeur de la carte, 100% par defaut\r
+- height|hauteur = 400px           hauteur de la carte, 400px par defaut\r
+- style = non                      ne pas styler la carte\r
+\r
+- fullscreen = oui                     afficher un bouton pour passer la carte en plein écran\r
+- zoom_molette|zoom_wheel = non        désactiver le zoom avec la molette de la souris, actif par defaut\r
+- control_type|controle_type = non     ne pas afficher les controles de changement de type\r
+- no_control|aucun_controle = oui      ne pas afficher les controles de la carte\r
+- scale = oui                          afficher l'échelle de la carte\r
+- overview = oui                       afficher une mini carte de situation\r
+\r
+- autocenterandzoom|centrer_auto = oui        centrer et zoomer la carte automatiquement pour afficher tous les marqueurs\r
+- localize_visitor|localiser_visiteur = oui   centrer la carte sur la position du visiteur (API geolocation HTML5)\r
+- id_a_ouvrir                                 id_gis de l'infobulle à afficher au chargement(marqueur uniquement)\r
+\r
+- objets = gis                     type d'objets à afficher (fichier json/gis_xx qui génère la source de donnees)\r
+- limit|limite = 500               nombre max de marqueurs à afficher, 500 par defaut\r
+- kml = 12                         kml à superposer à la carte (id_document ou url ou liste d'url)\r
+- gpx = 12                         gpx à superposer à la carte (id_document ou url ou liste d'url)\r
+- centrer_fichier = non            permet de ne pas centrer la carte automatiquement sur les fichiers kml/gpx surperposés\r
+- point = non                      si elle vaut "non" cette option n'affichera pas de points du tout (utile pour n'afficher qu'un kml par exemple)\r
+\r
+- media = non                      permet de passer le critère 'media' (pour les documents)\r
+- mots = #LISTE{1,4,7}             plugin critere {mots} http://contrib.spip.net/Critere-mots\r
+- path_styles=#ARRAY{color,#fff}   options de style des éléments de la couche GeoJSON (voir http://leafletjs.com/reference.html#path-options)\r
+\r
+Uniquement si objets = point_libre :\r
+- icone = chemin/vers/image        image utilisée pour le marker\r
+- titre                            titre du point\r
+- description                      description du point\r
+\r
+Clustering (regroupement de points proches) :\r
+- cluster = oui                    Active le clustering\r
+- clusterMaxZoom = 11              Regroupe les points jusque à ce zoom, mais pas au delà\r
+- clusterShowCoverageOnHover = 0   1 pour afficher un dessin au survol de la zone couvertes par les points regroupés\r
+]\r
+\r
+[(#SET{width,#ENV{width,#ENV{largeur,100%}}})]\r
+[(#SET{height,#ENV{height,#ENV{hauteur,400px}}})]\r
+[(#SET{id,#ENV{id_carte_gis,#ENV{id_map,#ENV{id,1}}}})]\r
+[(#REM) -- compat gis v1 -- ]\r
+[(#SET{lat,#ENV{lat,#ENV{latit,#ENV{latitude,#CONFIG{gis/lat,0}}}}})]\r
+[(#SET{lon,#ENV{lon,#ENV{lonxit,#ENV{longitude,#CONFIG{gis/lon,0}}}}})]\r
+[(#REM) On utilise la bounding box seulement si le centre n'a pas été donné et si les quatre valeurs de la bounding box sont renseignées\r
+    les valeurs par defaut sont "centre +/- 10°", ce qui est naze, mais c'est un cas normalement impossible\r
+]\r
+[(#ENV{lat}|ou{#ENV{lon}}|non|et{#ENV{sw_lat}}|et{#ENV{sw_lon}}|et{#ENV{ne_lat}}|et{#ENV{ne_lon}})\r
+       #SET{utiliser_bb, oui}\r
+       #SET{sw_lat,#ENV{sw_lat,#GET{lat}|moins{10}}}\r
+       #SET{sw_lon,#ENV{sw_lon,#GET{lon}|moins{10}}}\r
+       #SET{ne_lat,#ENV{ne_lat,#GET{lat}|plus{10}}}\r
+       #SET{ne_lon,#ENV{ne_lon,#GET{lon}|plus{10}}}\r
+]\r
+\r
+<div id="map[(#GET{id})]" class="carte_gis"[(#ENV{style}|!={'non'}|?{' '})style="[width:(#GET{width});][ height:(#GET{height});]"]></div>\r
+\r
+<script type="text/javascript">/*<!\[CDATA\[*/\r
+var map[(#GET{id})];\r
+if (typeof map_cfg=="undefined") var map_cfg = {};\r
+map_cfg["[(#GET{id})]"] = {\r
+"mapid":"map[(#GET{id})]",\r
+"scrollWheelZoom": [(#ENV{zoom_molette,#ENV{zoom_wheel}}|=={non}|?{false,true})],\r
+"zoomControl": [(#ENV{no_control,#ENV{aucun_controle}}|!={oui}|?{true,false})][,\r
+"maxZoom": (#ENV{maxZoom})],\r
+"utiliser_bb":[(#GET{utiliser_bb}|?{true,false})],\r
+"lat":[(#GET{lat})][,\r
+"sw_lat":(#GET{sw_lat})][,\r
+"ne_lat":(#GET{ne_lat})],\r
+"lon":[(#GET{lon})][,\r
+"sw_lon":(#GET{sw_lon})][,\r
+"ne_lon":(#GET{ne_lon})],\r
+"zoom":[(#ENV{zoom,#CONFIG{gis/zoom,0}})],\r
+"default_layer":"[(#REM|gis_layer_defaut)]",\r
+"layers":#EVAL{json_encode($GLOBALS['gis_layers'])},\r
+"affiche_layers":[(#CONFIG{gis/layers,#ARRAY}|json_encode)],\r
+"control_type":[(#ENV{control_type,#ENV{controle_type}}|=={non}|?{false,true})],\r
+"no_control":[(#ENV{no_control,#ENV{aucun_controle}}|=={oui}|?{true,false})],\r
+"scale":[(#ENV{scale}|=={oui}|?{true,false})],\r
+"overview":[(#ENV{overview}|=={oui}|?{true,false})],\r
+"fullscreen":[(#ENV{fullscreen}|=={oui}|?{true,false})],\r
+"cluster":[(#ENV{cluster}|=={oui}|?{true,false})],\r
+"clusterMaxZoom":[(#ENV{clusterMaxZoom, #ENV{maxZoom}|?{#ENV{maxZoom}|moins{2},0}})],\r
+"clusterShowCoverageOnHover":[(#ENV{clusterShowCoverageOnHover}|?{true,false})],\r
+"path_styles":[(#ENV*{path_styles}|json_encode)],\r
+"autocenterandzoom":[(#ENV{autocenterandzoom,#ENV{centrer_auto}}|?{true,false})],\r
+"open_id":"[(#ENV{id_a_ouvrir,''})]",\r
+"affiche_points":[(#ENV{point,''}|=={non}|?{false,true})],\r
+"json_points":{\r
+       "url":"[(#URL_PAGE{gis_json}|url_absolue)]"[,\r
+       "objets":"(#ENV{objets,#ENV{class}}|trim)"],\r
+       "limit":[(#ENV{limit,#ENV{limite,500}}|trim)],\r
+       "env":[(#ENV*{args,#ENV*}|gis_modele_url_json_env|json_encode)][,\r
+       "titre" : (#ENV{titre}|json_encode)][,\r
+       "description" : (#ENV{description}|json_encode)][,\r
+       "icone" : (#ENV{icone}|json_encode)]\r
+       },\r
+"localize_visitor":[(#ENV{localize_visitor,#ENV{localiser_visiteur}}|?{true,false})],\r
+"centrer_fichier":[(#ENV{centrer_fichier,oui}|=={oui}|?{true,false})],\r
+"kml":[(#ENV{kml,''}|?{[(#ENV{kml}|is_array|?{#ENV{kml},#LISTE{#ENV{kml}}}|gis_kml_to_urls|json_encode)],false})],\r
+"gpx":[(#ENV{gpx,''}|?{[(#ENV{gpx}|is_array|?{#ENV{gpx},#LISTE{#ENV{gpx}}}|gis_kml_to_urls|json_encode)],false})]\r
+};\r
+\r
+// Charger le javascript de GIS et initialiser la carte (des que DOM ready)\r
+jQuery.getScript('[(#PRODUIRE{fond=javascript/gis.js,cluster=#ENV{cluster,non}})]',function(){\r
+       jQuery(function(){\r
+               if (typeof(callback_map[(#GET{id})]) === "function") {\r
+                       map_cfg["[(#GET{id})]"]['callback']=callback_map[(#GET{id})];\r
+               }\r
+               gis_init_map(map_cfg["[(#GET{id})]"]);\r
+       });\r
+});\r
+/*\]\]>*/\r
+</script>\r
diff --git a/www/plugins/gis/modeles/carte_gis.yaml b/www/plugins/gis/modeles/carte_gis.yaml
new file mode 100644 (file)
index 0000000..7ccf033
--- /dev/null
@@ -0,0 +1,278 @@
+nom: <:gis:info_1_gis:>
+logo: 'prive/themes/spip/images/gis-24.png'
+icone_barre: 'gis.png'
+traiter: 'gis_inserer_modeles_traiter'
+parametres:
+  -
+    saisie: 'hidden'
+    options:
+      nom: 'modele'
+      defaut: 'carte_gis'
+  -
+    saisie: 'selection'
+    options:
+      nom: 'objets'
+      label: <:gis:label_inserer_modele_objets:>
+      defaut: 'point_libre' #pas pris en compte ?
+      cacher_option_intro: 'oui'
+      datas:
+        '': <:gis:label_inserer_modele_point_gis:>
+        point_libre: <:gis:label_inserer_modele_point_libre:>
+        articles: <:gis:label_inserer_modele_articles:>
+        sites: <:gis:label_inserer_modele_sites:>
+        articles_plus_sites: <:gis:label_inserer_modele_articles_sites:>
+        rubriques: <:gis:label_inserer_modele_rubriques:>
+        documents: <:gis:label_inserer_modele_documents:>
+        mots: <:gis:label_inserer_modele_mots:>
+        auteurs: <:gis:label_inserer_modele_auteurs:>
+  # IDENTIFIANTS
+  -
+    saisie: 'input'
+    options:
+      nom: 'id_gis'
+      label: <:gis:label_inserer_modele_identifiant:>
+      placeholder: <:gis:label_inserer_modele_identifiant_placeholder:>
+      afficher_si: '@objets@ == ""'
+  -
+    saisie: 'input'
+    options:
+      nom: 'id_article'
+      label: <:gis:label_inserer_modele_identifiant_opt:>
+      placeholder: 'id_article'
+      afficher_si: '@objets@ == "articles" || @objets@ == "articles_plus_sites"'
+  -
+    saisie: 'input'
+    options:
+      nom: 'id_rubrique'
+      label: <:gis:label_inserer_modele_identifiant_opt:>
+      placeholder: 'id_rubrique'
+      afficher_si: '@objets@ == "rubriques"'
+  -
+    saisie: 'input'
+    options:
+      nom: 'id_document'
+      label: <:gis:label_inserer_modele_identifiant_opt:>
+      placeholder: 'id_document'
+      afficher_si: '@objets@ == "documents"'
+  -
+    saisie: 'input'
+    options:
+      nom: 'id_mot'
+      label: <:gis:label_inserer_modele_identifiant_opt:>
+      placeholder: 'id_mot'
+      afficher_si: '@objets@ == "mots"'
+  -
+    saisie: 'input'
+    options:
+      nom: 'id_site'
+      label: <:gis:label_inserer_modele_identifiant_opt:>
+      placeholder: 'id_site'
+      afficher_si: '@objets@ == "sites"'
+  -
+    saisie: 'input'
+    options:
+      nom: 'id_auteur'
+      label: <:gis:label_inserer_modele_identifiant_opt:>
+      placeholder: 'id_auteur'
+      afficher_si: '@objets@ == "auteurs"'
+#
+# === POINT LIBRE ===
+#
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'field_point_libre'
+      afficher_si: '@objets@ == "point_libre"'
+    saisies:
+      -
+        saisie: 'carte'
+        options:
+          nom: 'carte'
+          hauteur: '200px'
+      -
+        saisie: 'input'
+        options:
+          nom: 'titre'
+          label: <:gis:titre_objet:>
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'description'
+          label: <:gis:label_inserer_modele_description:>
+          rows: '2'
+      -
+        saisie: 'hidden'
+        options:
+          nom: 'lat'
+      -
+        saisie: 'hidden'
+        options:
+          nom: 'lon'
+      -
+        saisie: 'hidden'
+        options:
+          nom: 'zoom'
+      -
+        saisie: 'input'
+        options:
+          nom: 'adresse'
+          placeholder: <:gis:label_adress:>
+          readonly: 'oui'
+      -
+        saisie: 'input'
+        options:
+          nom: 'code_postal'
+          placeholder: <:gis:label_code_postal:>
+          readonly: 'oui'
+      -
+        saisie: 'input'
+        options:
+          nom: 'ville'
+          placeholder: <:gis:label_ville:>
+          readonly: 'oui'
+      -
+        saisie: 'input'
+        options:
+          nom: 'pays'
+          placeholder: <:gis:label_pays:>
+          readonly: 'oui'
+#
+# === OPTIONS ===
+#
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'field_options'
+      pliable: 'oui'
+      plie: 'oui'
+      label: 'options'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'titre_carte'
+          label: <:gis:label_inserer_modele_titre_carte:>
+      -
+        saisie: 'input'
+        options:
+          nom: 'largeur'
+          label: <:gis:label_inserer_modele_largeur_carte:>
+          placeholder: '100%'
+      -
+        saisie: 'input'
+        options:
+          nom: 'hauteur'
+          label: <:gis:label_inserer_modele_hauteur_carte:>
+          placeholder: '400px'
+#      -
+#        saisie: 'case'
+#        options:
+#          nom: 'style'
+#          label_case: 'ne pas styler la carte'
+#          defaut: ''
+#          valeur_oui: 'non'
+#          valeur_non: ''
+      -
+        saisie: 'input'
+        options:
+          nom: 'limit'
+          label:  <:gis:label_inserer_modele_limite:>
+          afficher_si: '@objets@ != "gis" || @objets@ != "point_unique"'
+          placeholder: '500'
+      -
+        saisie: 'case'
+        options:
+          nom: 'scale'
+          label_case: <:gis:label_inserer_modele_echelle:>
+          defaut: ''
+          valeur_oui: 'oui'
+          valeur_non: ''
+      -
+        saisie: 'case'
+        options:
+          nom: 'fullscreen'
+          label_case: <:gis:label_inserer_modele_fullscreen:>
+          defaut: ''
+          valeur_oui: 'oui'
+          valeur_non: ''
+      -
+        saisie: 'case'
+        options:
+          nom: 'overview'
+          label_case: <:gis:label_inserer_modele_mini_carte:>
+          defaut: ''
+          valeur_oui: 'oui'
+          valeur_non: ''
+      -
+        saisie: 'case'
+        options:
+          nom: 'zoom_molette'
+          label_case: <:gis:label_inserer_modele_molette:>
+          defaut: ''
+          valeur_oui: 'non'
+          valeur_non: ''
+      -
+        saisie: 'case'
+        options:
+          nom: 'aucun_controle'
+          label_case: <:gis:label_inserer_modele_controle:>
+          defaut: ''
+          valeur_oui: 'oui'
+          valeur_non: ''
+      -
+        saisie: 'case'
+        options:
+          nom: 'controle_type'
+          label_case: <:gis:label_inserer_modele_controle_type:>
+          defaut: ''
+          valeur_oui: 'non'
+          valeur_non: ''
+      -
+        saisie: 'case'
+        options:
+          nom: 'localize_visitor'
+          label_case: <:gis:label_inserer_modele_localiser_visiteur:>
+          defaut: ''
+          valeur_oui: 'oui'
+          valeur_non: ''
+      -
+        saisie: 'case'
+        options:
+          nom: 'centrer_auto'
+          label_case: <:gis:label_inserer_modele_centrer_auto:>
+          defaut: 'oui'
+          valeur_oui: ''
+          valeur_non: 'oui'
+          afficher_si: '@objets@ != "gis" || @objets@ != "point_unique"'
+      -
+        saisie: 'input'
+        options:
+          nom: 'kml'
+          label: <:gis:label_inserer_modele_kml:>
+          placeholder: <:gis:label_inserer_modele_kml_gpx:>
+          afficher_si: '@objets@ != "gis" || @objets@ != "point_unique"'
+      -
+        saisie: 'input'
+        options:
+          nom: 'gpx'
+          label: <:gis:label_inserer_modele_gpx:>
+          placeholder: <:gis:label_inserer_modele_kml_gpx:>
+          afficher_si: '@objets@ != "gis" || @objets@ != "point_unique"'
+      -
+        saisie: 'case'
+        options:
+          nom: 'centrer_fichier'
+          label_case: <:gis:label_inserer_modele_centrer_fichier:>
+          valeur_oui: 'oui'
+          valeur_non: ''
+          afficher_si: '@objets@ != "gis" || @objets@ != "point_unique"'
+      -
+        saisie: 'case'
+        options:
+          nom: 'point'
+          label_case: <:gis:label_inserer_modele_points:>
+          #explication: "Utile pour n'afficher que les données kml/gpx"
+          defaut: ''
+          valeur_oui: 'non'
+          valeur_non: ''
+          afficher_si: '@objets@ != "gis" || @objets@ != "point_unique"'
diff --git a/www/plugins/gis/modeles/carte_gis_preview.html b/www/plugins/gis/modeles/carte_gis_preview.html
new file mode 100755 (executable)
index 0000000..dac6e20
--- /dev/null
@@ -0,0 +1,112 @@
+<BOUCLE_gis(GIS){objet ?}{id_objet ?}{id_gis ?}{0,1}>\r
+<div id="map_preview" class="carte_gis" style="width: 100%; height: 150px;"></div>\r
+\r
+<script type="text/javascript">\r
+<!--\r
+(function($){\r
+       var init_map_preview = function() {\r
+               var map_preview;\r
+               var map_preview_container = 'map_preview';\r
+               var marker;\r
+               \r
+               map_preview = new L.Map(map_preview_container);\r
+               \r
+               map_preview.attributionControl.setPrefix('');\r
+               \r
+               var base_layer = [new (#EVAL{$GLOBALS\['gis_layers'\]}|table_valeur{[(#REM|gis_layer_defaut)]/layer})];\r
+               map_preview.addLayer(base_layer);\r
+               \r
+               map_preview.setView(new L.LatLng([(#LAT)],[(#LON)]),[(#ZOOM|sinon{#CONFIG{gis/zoom,0}})]);\r
+               
+               [(#REM) On ajoute les points ou le point unique suivant les params ]\r
+               <B_points>\r
+               var data = {\r
+                       "type": "FeatureCollection",\r
+                       "features": [\r
+               <BOUCLE_points(GIS){id_objet}{objet}{","}>\r
+                               {"type": "Feature",\r
+                                       "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},\r
+                                       "id":"#ID_GIS",\r
+                                       "properties": {\r
+                                               "title":[(#TITRE|supprimer_numero|json_encode)],\r
+                                               "description":[(#DESCRIPTIF|json_encode)][,(#LOGO_GIS|oui)\r
+                                               [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{28,28}|image_recadre{28,28}|image_recadre{32,32,center}|image_aplatir{jpg,ffffff}})]\r
+                                               #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}\r
+                                               #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}\r
+                                               ["icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],\r
+                                               "icon_size": \[#GET{icon_w},#GET{icon_h}\],\r
+                                               "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],\r
+                                               "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]\r
+                                       }\r
+                               }\r
+               </BOUCLE_points>\r
+                       ]\r
+               };\r
+               [(#TOTAL_BOUCLE|>{1}|oui) #SET{autocenter,oui} ]\r
+               </B_points>\r
+               <BOUCLE_point(GIS){id_gis}>\r
+               var data = {\r
+                       "type": "FeatureCollection",\r
+                       "features": [\r
+                               {"type": "Feature",\r
+                                       "geometry": {"type": "Point", "coordinates": [#LON, #LAT]},\r
+                                       "id":"#ID_GIS",\r
+                                       "properties": {\r
+                                               "title":[(#TITRE|supprimer_numero|json_encode)],\r
+                                               "description":[(#DESCRIPTIF|json_encode)][,(#LOGO_GIS|oui)\r
+                                               [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{28,28}|image_recadre{28,28}|image_recadre{32,32,center}|image_aplatir{jpg,ffffff}})]\r
+                                               #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}\r
+                                               #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}\r
+                                               ["icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],\r
+                                               "icon_size": \[#GET{icon_w},#GET{icon_h}\],\r
+                                               "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],\r
+                                               "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]\r
+                                       }\r
+                               }]\r
+               };\r
+               </BOUCLE_point>\r
+               <//B_points>\r
+               if (data) {\r
+                       var geojson = new L.geoJson('', {\r
+                               onEachFeature: function (feature, layer) {\r
+                                       if (feature.properties && feature.properties.icon){\r
+                                               layer.setIcon(new L.Icon({\r
+                                                       iconUrl: feature.properties.icon,\r
+                                                       iconSize: new L.Point( feature.properties.icon_size\[0\], feature.properties.icon_size\[1\] ),\r
+                                                       iconAnchor: new L.Point( feature.properties.icon_anchor\[0\], feature.properties.icon_anchor\[1\] ),\r
+                                                       popupAnchor: new L.Point( feature.properties.popup_anchor\[0\], feature.properties.popup_anchor\[1\] )\r
+                                               }));\r
+                                       }\r
+                                       if (feature.properties && feature.properties.title){\r
+                                               var popupContent = '<strong>' + feature.properties.title + '</strong>';\r
+                                               if (feature.properties.description)\r
+                                                       popupContent = popupContent + feature.properties.description;\r
+                                               layer.bindPopup(popupContent);\r
+                                       }\r
+                               }\r
+                       }).addTo(map_preview);\r
+                       geojson.addData(data);\r
+                       [(#GET{autocenter}|oui)\r
+                       map_preview.fitBounds(geojson.getBounds());]\r
+               }\r
+               [(#REM) On ajoute les KML attachés à l'objet ]\r
+               <BOUCLE_kml(DOCUMENTS){tous}{objet}{id_objet}{extension=kml}>\r
+               map_preview.addLayer(new L.KML('[(#URL_DOCUMENT|url_absolue)]', {async: true}));\r
+               </BOUCLE_kml>\r
+               [(#REM) On ajoute les GPX attachés à l'objet ]\r
+               <BOUCLE_gpx(DOCUMENTS){tous}{objet}{id_objet}{extension=kml}>\r
+               map_preview.addLayer(new L.GPX('[(#URL_DOCUMENT|url_absolue)]', {async: true}));\r
+               </BOUCLE_gpx>\r
+       }\r
+\r
+       $(function(){\r
+               jQuery.getScript('[(#PRODUIRE{fond=javascript/gis.js}|compacte)]',function(){\r
+                       init_map_preview();\r
+               });\r
+               //onAjaxLoad(init_map_preview(true));\r
+       });\r
+\r
+})(jQuery);\r
+-->\r
+</script>\r
+</BOUCLE_gis>\r
diff --git a/www/plugins/gis/paquet.xml b/www/plugins/gis/paquet.xml
new file mode 100644 (file)
index 0000000..620ffd5
--- /dev/null
@@ -0,0 +1,89 @@
+<paquet
+       prefix="gis"
+       categorie="divers"
+       version="4.8.9"
+       schema="2.0.3"
+       etat="stable"
+       compatibilite="[3.0.0;3.0.*]"
+       logo="images/gis.png"
+       documentation="http://contrib.spip.net/4189"
+>
+
+       <nom>GIS</nom>
+       <!-- Système d'information géographique -->
+
+       <auteur>b_b</auteur>
+       <auteur lien="http://www.kent1.info">kent1</auteur>
+       <auteur lien="http://www.ldd.fr">Les Développements Durables</auteur>
+       <credit lien="http://leafletjs.com/">Leaflet</credit>
+       <credit lien="https://github.com/shramov/leaflet-plugins">Leaflet plugins</credit>
+       <credit lien="https://github.com/leaflet-extras/leaflet-providers">Leaflet providers</credit>
+       <credit lien="https://github.com/brunob/leaflet.fullscreen">Leaflet fullscreen</credit>
+       <credit lien="https://github.com/Norkart/Leaflet-MiniMap">Leaflet minimap</credit>
+       <copyright>2011-2013</copyright>
+       <licence>GPL v3</licence>
+       <credit lien="http://mattrich.deviantart.com/art/Picnic-101256405">Icône de mattrich sous licence CC BY-NC-SA</credit>
+
+       <traduire module="gis" reference="fr" gestionnaire="salvatore" />
+       <traduire module="paquet-gis" reference="fr" gestionnaire="salvatore" />
+
+       <utilise nom="selecteur_generique" compatibilite="[1.12;]" />
+       <necessite nom="saisies" compatibilite="[1.19.0;]" />
+       <lib nom="leaflet-gis-4.8.7" lien="http://contrib.spip.net/IMG/zip/leaflet-gis-4.8.7.zip" />
+
+       <pipeline
+               nom="declarer_tables_interfaces"
+               inclure="base/gis.php"
+       />
+       <pipeline
+               nom="declarer_tables_objets_sql"
+               inclure="base/gis.php"
+       />
+       <pipeline
+               nom="declarer_tables_auxiliaires"
+               inclure="base/gis.php"
+       />
+       <pipeline
+               nom="insert_head"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="header_prive"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="insert_head_css"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="afficher_contenu_objet"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="post_edition"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="taches_generales_cron"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="autoriser"
+               inclure="gis_autoriser.php"
+       />
+       <pipeline
+               nom="saisies_autonomes"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="xmlrpc_methodes"
+               inclure="gis_pipelines.php"
+       />
+       <pipeline
+               nom="xmlrpc_server_class"
+               inclure="gis_pipelines.php"
+       />      
+       <menu nom="gis_tous" titre="gis:icone_gis_tous" parent="menu_edition" icone="images/gis-16.png" />
+       <menu nom="configurer_gis" titre="gis:cfg_titre_gis" parent="menu_configuration" icone="images/gis-16.png" />
+       <menu nom="gis_nouveau" titre="gis:editer_gis_nouveau" parent="outils_rapides" icone="images/gis-new-16.png" action="gis_edit" parametres="new=oui" />
+</paquet>
diff --git a/www/plugins/gis/prive/contenu/gis_objet.html b/www/plugins/gis/prive/contenu/gis_objet.html
new file mode 100644 (file)
index 0000000..74dbd33
--- /dev/null
@@ -0,0 +1,6 @@
+[(#SET{titre, #VAL{gis:info_geolocalisation}|_T})]
+[(#BOITE_OUVRIR{#CHEMIN_IMAGE{gis-24.png}|balise_img{'',cadre-icone}|concat{#GET{titre}}, 'simple'})]
+<div id="editer_gis_[(#ENV{objet})]_[(#ENV{id_objet})]" class="ajax-action nom_action">
+       [(#INCLURE{fond=prive/inclure/gis_objet_formulaires,env,ajax})]
+</div>
+#BOITE_FERMER
\ No newline at end of file
diff --git a/www/plugins/gis/prive/inclure/gis_objet_formulaires.html b/www/plugins/gis/prive/inclure/gis_objet_formulaires.html
new file mode 100644 (file)
index 0000000..dc6ab9b
--- /dev/null
@@ -0,0 +1,41 @@
+<div class="ajax">
+<BOUCLE_test(GIS){objet}{id_objet}{0,1}> </BOUCLE_test>
+#SET{gis_defaut,nouveau}
+#SET{gis_defaut,glop}
+<//B_test>
+
+#SET{bloc_gis, #ENV{bloc_gis,#GET{gis_defaut}|=={nouveau}|?{editer,lier}}}
+
+<div class="actions onglets_simple second clearfix">
+       <ul>
+       <li>
+       [(#GET{bloc_gis}|=={lier}|?{<strong>,<a href="[(#SELF|parametre_url{bloc_gis,lier}|parametre_url{id_gis,''})]" class="ajax">})]
+               <:gis:titre_bloc_points_lies:>
+       [(#GET{bloc_gis}|=={lier}|?{</strong>,</a>})]
+       </li>
+       <li>
+       [(#GET{bloc_gis}|=={rechercher}|?{<strong>,<a href="[(#SELF|parametre_url{bloc_gis,rechercher}|parametre_url{id_gis,''})]" class="ajax">})]
+               <:gis:titre_bloc_rechercher_point:>
+       [(#GET{bloc_gis}|=={rechercher}|?{</strong>,</a>})]
+       </li>
+       <li>
+       [(#GET{bloc_gis}|=={editer}|?{<strong>,<a href="[(#SELF|parametre_url{bloc_gis,editer}|parametre_url{id_gis,nouveau})]" class="ajax">})]
+               <:gis:titre_bloc_creer_point:>
+       [(#GET{bloc_gis}|=={editer}|?{</strong>,</a>})]
+       </li>
+       </ul>
+</div>
+
+[(#GET{bloc_gis}|=={editer}|oui)
+       #FORMULAIRE_EDITER_GIS{#ENV{id_gis,#GET{gis_defaut}},#ENV{objet},#ENV{id_objet},#SELF,'non',#ENV{options_formulaire_editer_gis}}
+]
+
+[(#GET{bloc_gis}|=={lier}|oui)
+       [(#INCLURE{fond=prive/objets/liste/gis_lies,sinon=<:gis:aucun_gis:>,env})]
+]
+
+<BOUCLE_gis(GIS){0,1}> </BOUCLE_gis>[(#GET{bloc_gis}|=={rechercher}|oui)
+<div class="ajax">
+       #FORMULAIRE_RECHERCHER_GIS{#ENV{objet},#ENV{id_objet},#SELF|parametre_url{bloc_gis,lier}}
+</div>]</B_gis>
+</div>
diff --git a/www/plugins/gis/prive/objets/contenu/gis.html b/www/plugins/gis/prive/objets/contenu/gis.html
new file mode 100644 (file)
index 0000000..5fcdb96
--- /dev/null
@@ -0,0 +1,20 @@
+<BOUCLE_gis(GIS){id_gis=#ID}>
+       <div class="champ contenu_descriptif[(#DESCRIPTIF|non)vide]">
+               #DESCRIPTIF
+       </div>
+       <div class="champ contenu_adresse[(#ADRESSE|non)vide]">
+               #ADRESSE
+       </div>
+       <div class="champ contenu_region[(#REGION|non)vide]">
+               #REGION
+       </div>
+       <div class="champ contenu_code_postal[(#CODE_POSTAL|non)vide]">
+               #CODE_POSTAL
+       </div>
+       <div class="champ contenu_ville[(#VILLE|non)vide]">
+               #VILLE
+       </div>
+       <div class="champ contenu_pays[(#PAYS|non)vide]">
+               #PAYS [((#CODE_PAYS))]
+       </div>
+</BOUCLE_gis>
diff --git a/www/plugins/gis/prive/objets/infos/gis.html b/www/plugins/gis/prive/objets/infos/gis.html
new file mode 100644 (file)
index 0000000..0a1a982
--- /dev/null
@@ -0,0 +1,18 @@
+<BOUCLE_gis(GIS){id_gis=#ENV{id}}>
+
+       <div class='infos'>
+               <div class='numero'><:gis:info_numero_gis:><p>#ID_GIS</p></div>
+
+               #INCLURE{fond=prive/objets/liste/objets_gis_simple, id_gis=#ID_GIS, env}
+
+        [(#AUTORISER{supprimer,gis,#ID_GIS}|oui)
+            [(#URL_ACTION_AUTEUR{
+                supprimer_gis,
+                #ID_GIS,
+                #URL_ECRIRE{gis_tous}
+                               }|icone_horizontale{<:gis:bouton_supprimer_gis:>,gis-24,del}
+            )]
+        ]
+
+    </div>
+</BOUCLE_gis>
diff --git a/www/plugins/gis/prive/objets/liste/gis.html b/www/plugins/gis/prive/objets/liste/gis.html
new file mode 100644 (file)
index 0000000..a4f6e6c
--- /dev/null
@@ -0,0 +1,40 @@
+[(#SET{defaut_tri,#ARRAY{
+       multi titre,1,
+       multi pays,1,
+       multi ville,1,
+       id_gis,1,
+       points,-1
+}})
+]
+<B_liste_gis>
+#ANCRE_PAGINATION
+<div class="liste-objets gis">
+<table class='spip liste'>
+[<caption><strong class="caption">(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{gis:info_1_gis,gis:info_nb_gis}})</strong></caption>]
+       <thead>
+               <tr class='first_row'>
+                       <th class='titre' scope='col'>[(#TRI{multi titre,<:info_titre:>,ajax})]</th>
+                       <th class='pays' scope='col'>[(#TRI{multi pays,<:gis:label_pays:>,ajax})]</th>
+                       <th class='ville' scope='col'>[(#TRI{multi ville,<:gis:label_ville:>,ajax})]</th>
+                       <th class='id_gis' scope='col'>[(#TRI{id_gis,<:info_numero_abbreviation:>,ajax})]</th>
+               </tr>
+       </thead>
+       <tbody>
+       <BOUCLE_liste_gis(GIS){id_gis ?}{id_rubrique ?}{id_article ?}{id_breve ?}{id_document ?}{id_mot ?}{id_auteur ?}{id_syndic ?}{where?}{recherche?}{tri #ENV{par,multi titre},#GET{defaut_tri}}{pagination #ENV{nb,10}}>
+               <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})][(#ID_GIS|=={#ENV{id_lien_ajoute}}|oui)append]">
+                       <td class='titre principale'>[(#LOGO_GIS|image_reduire{20,20})]<a href="[(#ID_GIS|generer_url_entite{gis})]"
+                               title="<:gis:texte_voir_gis:>">[(#TITRE|sinon{<:ecrire:info_sans_titre:>})]</a></td>
+                       <td class='pays'>#PAYS</td>
+                       <td class='ville'>#VILLE</td>
+                       <td class='id_gis'><a href="[(#ID_GIS|generer_url_entite{gis})]"
+                               title="<:gis:texte_voir_gis:>">#ID_GIS</a></td>
+               </tr>
+       </BOUCLE_liste_gis>
+       </tbody>
+</table>
+[<p class='pagination'>(#PAGINATION{prive})</p>]
+</div>
+</B_liste_gis>
+[
+<div class="liste-objets gis caption-wrap"><strong class="caption">(#ENV*{sinon,''})</strong></div>
+]<//B_liste_gis>
\ No newline at end of file
diff --git a/www/plugins/gis/prive/objets/liste/gis_associer.html b/www/plugins/gis/prive/objets/liste/gis_associer.html
new file mode 100644 (file)
index 0000000..ff8a6f7
--- /dev/null
@@ -0,0 +1,55 @@
+[(#SET{defaut_tri,#ARRAY{
+       multi titre,1,
+}})
+]
+#SET{exclus,#ENV{objet_source}|lister_objets_lies{#ENV{objet},#ENV{id_objet},#ENV{_objet_lien}}}
+#SET{debut,#ENV{debutgisa,#EVAL{_request("debutgisa");}}}
+<input type="hidden" name="debutgisa" value="#GET{debut}" />
+<B_liste_gis>
+[(#REM) En cas de pagination indirecte @32, il faut refaire le set car la boucle
+a mis a jour la valeur avec la page reelle]
+#SET{debut,#ENV{debutgisa,#EVAL{_request("debutgisa");}}}
+#ANCRE_PAGINATION
+[<h3><:info_resultat_recherche:> &laquo;(#ENV{recherche})&raquo;</h3>]
+<div class="liste-objets liste-objets-associer gis">
+<table class='spip liste'>
+[<caption><span class="caption"><strong>(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{gis:info_1_gis,gis:info_nb_gis}})</strong>
+<span class="recherche">
+       <label for="recherche-#ENV{id}"><:info_rechercher_02:></label>
+       <input type="text" class="recherche" name="recherche" id="recherche-#ENV{id}" value="#ENV{recherche}" />
+       <input type="submit" class="tout_voir" name="tout_voir" value="<:info_tout_afficher:>" />
+</span>
+</span>
+</caption>]
+       <thead>
+               <tr class='first_row'>
+            <th class='picto' scope='col'></th>
+            <th class='titre' scope='col'>[(#TRI{multi titre,<:info_titre:>,ajax})]</th>
+            <th class='action' scope='col'>&nbsp;</th>
+               </tr>
+       </thead>
+       <tbody>
+       <BOUCLE_liste_gis(GIS){!id_gis IN #GET{exclus}}{tout}{where?}{recherche?}{tri #ENV{par,multi titre},#GET{defaut_tri}}{pagination #ENV{nb,5} gisa}>
+               <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
+                       <td class='picto'>[(#CHEMIN_IMAGE{gis-16.png}|balise_img)]</td>
+                       <td class='titre principale'>[(#LOGO_GIS|image_reduire{20,20})]<a href="[(#ID_GIS|generer_url_entite{gis})]"
+                               title="<:gis:texte_voir_gis:>">[(#TITRE|sinon{<:ecrire:info_sans_titre:>})]</a></td>
+                       <td class='action'><button class="button" name="ajouter_lien[gis-#ID_GIS-#OBJET-#ID_OBJET]" value="+"><:gis:lien_ajouter_gis:> [(#CHEMIN_IMAGE{ajouter-12.png}|balise_img{'+'})]</button></td>
+               </tr>
+       </BOUCLE_liste_gis>
+       </tbody>
+</table>
+[<p class='pagination'>(#PAGINATION{prive})</p>]
+</div>
+</B_liste_gis>
+[(#ENV{recherche}|oui)
+<div class="liste-objets liste-objets-associer gis caption-wrap">
+<span class="caption"><strong>[(#VAL{gis:info_recherche_gis_zero}|_T{#ARRAY{cherche_gis,#ENV{recherche}}})]</strong>
+<span class="recherche">
+       <label for="recherche-#ENV{id}"><:info_rechercher_02:></label>
+       <input type="text" class="recherche" name="recherche" id="recherche-#ENV{id}" value="#ENV{recherche}" />
+       <input type="submit" class="tout_voir" name="tout_voir" value="<:info_tout_afficher:>" />
+</span>
+</span>
+</div>
+]<//B_liste_gis>
diff --git a/www/plugins/gis/prive/objets/liste/gis_associer_fonctions.php b/www/plugins/gis/prive/objets/liste/gis_associer_fonctions.php
new file mode 100644 (file)
index 0000000..891b756
--- /dev/null
@@ -0,0 +1,3 @@
+<?php
+include_spip('inc/filtres_ecrire');
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/prive/objets/liste/gis_lies.html b/www/plugins/gis/prive/objets/liste/gis_lies.html
new file mode 100644 (file)
index 0000000..e73d30c
--- /dev/null
@@ -0,0 +1,44 @@
+[(#SET{defaut_tri,#ARRAY{
+       multi titre,1,
+       id_gis,1
+}})
+]
+#SET{selection,#VAL{gis}|lister_objets_lies{#ENV{objet},#ENV{id_objet},#ENV{_objet_lien}}}
+<input type="hidden" name="debutgisl" value='#ENV{debutgisl,#EVAL{_request("debutgisl");}}' />
+<B_liste_gis>
+#ANCRE_PAGINATION
+<div class="liste-objets liste-objets-lies gis">
+<table class='spip liste'>
+[<caption><strong class="caption">(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{gis:info_1_gis,gis:info_nb_gis}})</strong></caption>]
+       <thead>
+               <tr class='first_row'>
+                       <th class='picto' scope='col'></th>
+                       <th class='titre' scope='col'>[(#TRI{multi titre,<:info_titre:>,ajax})]</th>
+                       <th class='action' scope='col'>&nbsp;</th>
+               </tr>
+       </thead>
+       <tbody>
+       <BOUCLE_liste_gis(GIS){id_gis IN #GET{selection}}{where?}{tri #ENV{par,multi titre},#GET{defaut_tri}}{pagination #ENV{nb,10} gisl}{!lang_select}>
+               <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})][(#ID_GIS|=={#ENV{id_lien_ajoute}}|oui)append]">
+                       <td class='picto'>[(#CHEMIN_IMAGE{gis-16.png}|balise_img)]</td>
+                       <td class='titre principale'>[(#LOGO_GIS|image_reduire{20,20})]<a href="[(#ID_GIS|generer_url_entite{gis})]"
+                               title="<:gis:texte_voir_gis:>">[(#TITRE|sinon{<:ecrire:info_sans_titre:>})]</a></td>
+                       <td class='action'>
+                [(#BOUTON_ACTION{
+                    <:gis:info_supprimer_lien:>  [(#CHEMIN_IMAGE{supprimer-12.png}|balise_img{'X'})],
+                    #URL_ACTION_AUTEUR{editer_lien_gis,delier/#ID_GIS/#OBJET/#ID_OBJET,#SELF},
+                    ajax})]
+                       </td>
+               </tr>
+       </BOUCLE_liste_gis>
+       </tbody>
+</table>
+[<p class='pagination'>(#PAGINATION{prive})</p>]
+[(#GRAND_TOTAL|>{3}|oui)<div class="action"><button class="button link" name="supprimer_lien#EVAL{chr(91)}gis-*-#OBJET-#ID_OBJET#EVAL{chr(93)}" value="X"><:gis:info_supprimer_liens:> [(#CHEMIN_IMAGE{supprimer-12.png}|balise_img{'X'})]</button></div>]
+[(#INCLURE{fond=modeles/carte_gis_preview,id_objet,objet})]
+</div>
+</B_liste_gis>
+<div class="liste-objets liste-objets-lies gis caption-wrap">
+<strong class="caption">[(#ENV*{titre,<:gis:info_aucun_gis:>}) ]</strong>
+</div>
+<//B_liste_gis>
diff --git a/www/plugins/gis/prive/objets/liste/gis_lies_fonctions.php b/www/plugins/gis/prive/objets/liste/gis_lies_fonctions.php
new file mode 100644 (file)
index 0000000..891b756
--- /dev/null
@@ -0,0 +1,3 @@
+<?php
+include_spip('inc/filtres_ecrire');
+?>
\ No newline at end of file
diff --git a/www/plugins/gis/prive/objets/liste/gis_tous.html b/www/plugins/gis/prive/objets/liste/gis_tous.html
new file mode 100644 (file)
index 0000000..c5eee52
--- /dev/null
@@ -0,0 +1,39 @@
+<B_gis>
+[(#ANCRE_PAGINATION)]
+<div class="menu points">
+<ul class="liste_items">
+       <BOUCLE_gis(GIS){par titre}{pagination #ENV{nb,5}}>
+       <li class="item">
+               <h3 class="titre">
+                       <a href="[(#URL_ECRIRE{gis,id_gis=#ID_GIS})]">#TITRE</a>
+                       [<span class="numero">N° (#ID_GIS)</span>]
+               </h3>
+               [<div class="description">
+                       (#DESCRIPTIF|couper{200})
+               </div>]
+               <div class="geo">
+                       [<abbr class="latitude" title="(#LAT)">[[(#LAT|>{0}|?{'N','S'})] (#LAT|dec_to_dms)]</abbr> - ]
+                       [<abbr class="longitude" title="(#LON)">[[(#LON|>{0}|?{'E','W'})] (#LON|dec_to_dms)]</abbr>]
+               </div>
+               <p class='actions'>
+                       <span class="afficher" id="afficher_[(#ID_GIS)]">&#91;<a href="[(#URL_ECRIRE{gis,id_gis=#ID_GIS})]">Afficher</a>&#93;</span>
+                       [(#AUTORISER{modifier,gis,#ID_GIS}|oui)
+                       <span class='lien_modifier'>&#91;<a href='[(#URL_ECRIRE{gis_edit}|parametre_url{id_gis,#ID_GIS}|parametre_url{redirect,#SELF|url_absolue})]'><:gis:editer_gis_editer:></a>&#93;</span>]
+               </p>
+       </li>
+       </BOUCLE_gis>
+</ul>
+[<p class="pagination">(#PAGINATION)</p>]
+<script type="text/javascript">
+(function($){
+       $(function(){
+               $('.afficher').css('cursor','pointer').click(function(){
+                       var id_marker = $(this).attr('id').replace('afficher_','');
+                       gis_focus_marker(id_marker,'_all');
+                       return false;
+               });
+       });
+})(jQuery);
+</script>
+</B_gis>
+</div>
diff --git a/www/plugins/gis/prive/objets/liste/objets_gis.html b/www/plugins/gis/prive/objets/liste/objets_gis.html
new file mode 100644 (file)
index 0000000..d0a22cb
--- /dev/null
@@ -0,0 +1,41 @@
+[(#SET{defaut_tri,#ARRAY{
+       objet,#ENV{objet_sens,-1},
+       id_objet,1
+}})
+]<B_liste_objets>
+#ANCRE_PAGINATION
+<div class="liste-objets objets_gis">
+<table class='spip liste'>
+[<caption><strong class="caption">(#ENV*{titre,#GRAND_TOTAL|singulier_ou_pluriel{gis:info_1_objet_gis,gis:info_nb_objets_gis}})</strong></caption>]
+       <thead>
+               <tr class='first_row'>
+            <th class='picto' scope='col'></th>
+                       <th class='objet' scope='col'>[(#TRI{objet,<:gis:info_objet:>,ajax})]</th>
+                       <th class='id_objet' scope='col'>[(#TRI{id_objet,<:gis:info_id_objet:>,ajax})]</th>
+                       <th class='titre principale' scope='col'><:gis:titre_objet:></th>
+                       <th></th>
+               </tr>
+       </thead>
+       <tbody>
+       <BOUCLE_liste_objets(GIS gis_liens){id_gis}{tri #ENV{order,objet},#GET{defaut_tri}}{pagination #ENV{nb,10}}{!lang_select}>
+               <tr class="[(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
+                       <td class='picto'>[(#OBJET|objet_icone{16})]</td>
+                       <td class='objet'>[(#OBJET|objet_info{texte_objet}|_T)]</td>
+                       <td class='id_objet'>[(#ID_OBJET)]</td>
+            <td class='titre principale'><a href="[(#ID_OBJET|generer_url_entite{#OBJET})]"
+                               title="<:gis:info_voir_fiche_objet:> <:info_numero_abbreviation|attribut_html:> #ID_OBJET">#INFO_TITRE{#OBJET,#ID_OBJET}</a></td>
+                       <td class='action'>
+                               [(#BOUTON_ACTION{
+                                       <:gis:info_supprimer_lien:>  [(#CHEMIN_IMAGE{supprimer-12.png}|balise_img{'X'})],
+                                       #URL_ACTION_AUTEUR{editer_lien_gis,delier/#ID_GIS/#OBJET/#ID_OBJET,#SELF},
+                                       ajax})]
+                       </td>
+               </tr>
+       </BOUCLE_liste_objets>
+       </tbody>
+</table>
+[<p class='pagination'>(#PAGINATION{prive})</p>]
+</div>
+</B_liste_objets>[
+<div class="liste-elements objets_gis"><strong class="caption">(#ENV*{sinon,''})</strong></div>
+]<//B_liste_objets>
diff --git a/www/plugins/gis/prive/objets/liste/objets_gis_simple.html b/www/plugins/gis/prive/objets/liste/objets_gis_simple.html
new file mode 100644 (file)
index 0000000..688e540
--- /dev/null
@@ -0,0 +1,16 @@
+<B_liste_objets>
+
+#ANCRE_PAGINATION
+<div class="liste-elements objets_gis">
+#SET{total,#GRAND_TOTAL}
+<h3>[(#GET{total}|singulier_ou_pluriel{gis:info_1_objet_gis,gis:info_nb_objets_gis})]</h3>
+<ul class="liste_items">
+    <BOUCLE_liste_objets(GIS gis_liens){id_gis}{tri #ENV{order,objet},#GET{defaut_tri}}{pagination #ENV{nb,10}}{!lang_select}>
+        <li class="item #OBJET">
+            <a href="[(#ID_OBJET|generer_url_entite{#OBJET})]">[(#INFO_TITRE{#OBJET,#ID_OBJET}) ]([(#OBJET|objet_info{texte_objet}|_T)] <:info_numero_abbreviation|attribut_html:>#ID_OBJET)</a>
+        </li>
+    </BOUCLE_liste_objets>
+</ul>
+[<p class='pagination'>(#PAGINATION{prive})</p>]
+</div>
+</B_liste_objets>
diff --git a/www/plugins/gis/prive/squelettes/contenu/configurer_gis.html b/www/plugins/gis/prive/squelettes/contenu/configurer_gis.html
new file mode 100644 (file)
index 0000000..7c3b5c2
--- /dev/null
@@ -0,0 +1,6 @@
+[(#AUTORISER{configurer,gis}|sinon_interdire_acces)]
+<h1 class="grostitre"><:gis:cfg_titre_gis:></h1>
+
+<div class="ajax">
+#FORMULAIRE_CONFIGURER_GIS
+</div>
diff --git a/www/plugins/gis/prive/squelettes/contenu/gis.html b/www/plugins/gis/prive/squelettes/contenu/gis.html
new file mode 100644 (file)
index 0000000..e6322cb
--- /dev/null
@@ -0,0 +1,23 @@
+<BOUCLE_gis(GIS){id_gis}{tout}{si #ENV{exec}|=={gis}}>
+[(#BOITE_OUVRIR{[
+       [(#AUTORISER{modifier,gis,#ID_GIS})
+       [(#URL_ECRIRE{gis_edit,id_gis=#ID_GIS}|icone_verticale{<:gis:texte_modifier_gis:>,gis,edit,right ajax preload})]
+       ]
+       <h1>(#TITRE|sinon{<:info_sans_titre:>})[(#CHEMIN_IMAGE{gis-24.png}|balise_img{gis,cadre-icone})]</h1>
+],simple fiche_objet})]
+
+[(#INCLURE{fond=modeles/carte_gis_preview,id_gis})]
+
+<div id="wysiwyg">
+<INCLURE{fond=prive/objets/contenu/gis,id=#ID_GIS} />
+</div>
+
+<INCLURE{fond=prive/objets/liste/objets_gis,sinon=<:gis:aucun_objet:>,env,ajax} />
+
+#BOITE_FERMER
+
+#PIPELINE{afficher_complement_objet,#ARRAY{args,#ARRAY{type,gis,id,#ID_GIS},data,'<div class="nettoyeur"></div>'}}
+
+</BOUCLE_gis>
+[(#ENV**{exec}|=={gis_edit}|?{#INCLURE{fond=prive/squelettes/contenu/gis_edit,redirect='',env,retourajax=oui},#REM|sinon_interdire_acces})]
+<//B_gis>
diff --git a/www/plugins/gis/prive/squelettes/contenu/gis_edit.html b/www/plugins/gis/prive/squelettes/contenu/gis_edit.html
new file mode 100644 (file)
index 0000000..6f0c67f
--- /dev/null
@@ -0,0 +1,36 @@
+[(#ID_GIS|oui)
+       [(#AUTORISER{modifier,gis,#ID_GIS}|sinon_interdire_acces)]
+][(#ID_GIS|non)
+       [(#AUTORISER{creer,gis,#ID_GIS,'','',#ARRAY{associer_objet,#ENV{associer_objet}}}|sinon_interdire_acces)]
+]
+#SET{redirect,#ENV{redirect,#ENV{id_gis}|?{#URL_ECRIRE{gis,id_gis=#ID_GIS},#URL_ECRIRE{gis_tout}}}}
+
+#SET{objet, #ENV{objet, ''}}
+#SET{id_objet, #ENV{id_objet, 0}}
+[(#ENV{associer_objet}|oui)
+       [(#SET{array_objet, #ENV{associer_objet}|explode{'|'}})]
+       #SET{objet, #GET{array_objet}|table_valeur{0}}
+       #SET{id_objet, #GET{array_objet}|table_valeur{1}}
+]
+<div class='cadre-formulaire-editer'>
+<div class="entete-formulaire">
+       [(#ID_GIS|oui)
+       [(#GET{redirect}|icone_verticale{<:icone_retour:>,gis,'',left retour[(#ENV{retourajax,''}|oui)ajax preload]})]
+       ]
+       [
+               [(#ID_GIS|?{<:gis:texte_modifier_gis:>,<:gis:texte_creer_gis:>})]
+               <h1>(#ENV{titre,#INFO_TITRE{gis,#ID_GIS}|sinon{<:gis:titre_nouveau_point:>}})</h1>
+       ]
+</div>
+
+#SET{redirect,#ENV{redirect,#ID_GIS|generer_url_entite{gis}}}
+[(#ENV{retourajax,''}|oui)
+       #SET{redirect,'javascript:if (window.jQuery) jQuery(".entete-formulaire .retour a").followLink();'}
+       <div class="ajax">
+]
+               [(#FORMULAIRE_EDITER_GIS{#ENV{id_gis,oui},#GET{objet},#GET{id_objet},#GET{redirect},'',#ENV{associer_objet}})]
+[(#ENV{retourajax,''}|oui)
+       </div>
+       <script type="text/javascript">/*<!\[CDATA\[*/reloadExecPage('#ENV{exec}','#navigation,#chemin');/*\]\]>*/</script>
+]
+</div>
\ No newline at end of file
diff --git a/www/plugins/gis/prive/squelettes/contenu/gis_tous.html b/www/plugins/gis/prive/squelettes/contenu/gis_tous.html
new file mode 100644 (file)
index 0000000..bb5621a
--- /dev/null
@@ -0,0 +1,15 @@
+<h1 class="grostitre"><:gis:editer_gis_titre:></h1>
+
+[(#REM)<p><:gis:editer_gis_explication:></p>]
+
+#FORMULAIRE_RECHERCHE_ECRIRE{#SELF,ajax}
+<div class="nettoyeur"></div>
+
+<BOUCLE_gis(GIS){recherche ?}{pagination 1}>
+<h3>[(#GRAND_TOTAL|singulier_ou_pluriel{gis:info_1_gis,gis:info_nb_gis})]</h3>
+</BOUCLE_gis>
+<h3><:gis:info_aucun_gis:></h3>
+<//B_gis>
+
+
+[(#INCLURE{fond=modeles/carte_gis,id_carte_gis=_all,recherche,objets=tous_avec_liens_espace_prive})]
diff --git a/www/plugins/gis/prive/squelettes/extra/gis.html b/www/plugins/gis/prive/squelettes/extra/gis.html
new file mode 100644 (file)
index 0000000..74dad10
--- /dev/null
@@ -0,0 +1,4 @@
+#BOITE_OUVRIR{'','info'}
+[(#URL_PAGE{gis_download}|parametre_url{id_gis,#ENV{id_gis}}|parametre_url{format,kml}|icone_horizontale{<:gis:telecharger_gis{format=KML}:>,telecharger-16})]
+[(#URL_PAGE{gis_download}|parametre_url{id_gis,#ENV{id_gis}}|parametre_url{format,gpx}|icone_horizontale{<:gis:telecharger_gis{format=GPX}:>,telecharger-16})]
+#BOITE_FERMER
\ No newline at end of file
diff --git a/www/plugins/gis/prive/squelettes/hierarchie/gis.html b/www/plugins/gis/prive/squelettes/hierarchie/gis.html
new file mode 100644 (file)
index 0000000..ddd24d5
--- /dev/null
@@ -0,0 +1,8 @@
+<a href="#URL_ECRIRE{gis_tous}">
+       <:gis:gis_pluriel:>
+</a> &gt;
+<BOUCLE_point(GIS){id_gis}{0,1}>
+       <strong class="on">#TITRE</strong>
+</BOUCLE_point>
+       <strong class="on"><:gis:titre_nouveau_point:></strong>
+<//B_point>
diff --git a/www/plugins/gis/prive/squelettes/hierarchie/gis_edit.html b/www/plugins/gis/prive/squelettes/hierarchie/gis_edit.html
new file mode 100644 (file)
index 0000000..f17f81d
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=prive/squelettes/hierarchie/gis,env} />
\ No newline at end of file
diff --git a/www/plugins/gis/prive/squelettes/navigation/gis_edit.html b/www/plugins/gis/prive/squelettes/navigation/gis_edit.html
new file mode 100644 (file)
index 0000000..91a9d56
--- /dev/null
@@ -0,0 +1,9 @@
+[(#ID_GIS|oui)
+#BOITE_OUVRIR{'','info'}
+#PIPELINE{boite_infos,#ARRAY{data,'',args,#ARRAY{'type','gis','id',#ID_GIS}}}
+#BOITE_FERMER
+
+<div class="ajax">
+#FORMULAIRE_EDITER_LOGO{'gis',#ID_GIS,'',#ENV**}
+</div>
+]
diff --git a/www/plugins/gis/prive/squelettes/navigation/gis_tous.html b/www/plugins/gis/prive/squelettes/navigation/gis_tous.html
new file mode 100644 (file)
index 0000000..66c8916
--- /dev/null
@@ -0,0 +1,5 @@
+#INCLURE{fond=prive/objets/liste/gis_tous,env}
+
+#BOITE_OUVRIR{'',raccourcis}
+[(#URL_ECRIRE{gis_edit,nouveau=oui}|icone_horizontale{<:gis:editer_gis_nouveau:>,gis,new})]
+#BOITE_FERMER
diff --git a/www/plugins/gis/prive/style_prive_plugin_gis.html b/www/plugins/gis/prive/style_prive_plugin_gis.html
new file mode 100644 (file)
index 0000000..130a35d
--- /dev/null
@@ -0,0 +1,20 @@
+#CACHE{3600*100,cache-client}
+#HTTP_HEADER{Content-Type: text/css; charset=iso-8859-15}
+#HTTP_HEADER{Vary: Accept-Encoding}
+
+#SET{claire,##ENV{couleur_claire,edf3fe}}
+#SET{foncee,##ENV{couleur_foncee,3874b0}}
+#SET{left,#ENV{ltr}|choixsiegal{left,left,right}}
+#SET{right,#ENV{ltr}|choixsiegal{left,right,left}}
+
+/* liste des points exec=gis_tous */
+
+.points .liste_items .titre { font-size: small; }
+.points .liste_items .titre .numero { float: right; }
+.points .liste_items .description,
+.points .liste_items .geo { margin: 5px 0 0; color: #666; }
+.points .liste_items .geo abbr { border: 0; }
+.points .liste_items p.actions { font-size: 0.9em; margin: 5px 0 0; }
+
+/* Avec OpenLayer, le menu deroulant de spip passe dessous la carte... */
+.olMap .olMapViewport {z-index:0;}
diff --git a/www/plugins/gis/prive/themes/spip/images/gis-16.png b/www/plugins/gis/prive/themes/spip/images/gis-16.png
new file mode 100644 (file)
index 0000000..b0e5a4c
Binary files /dev/null and b/www/plugins/gis/prive/themes/spip/images/gis-16.png differ
diff --git a/www/plugins/gis/prive/themes/spip/images/gis-24.png b/www/plugins/gis/prive/themes/spip/images/gis-24.png
new file mode 100755 (executable)
index 0000000..6cb9f54
Binary files /dev/null and b/www/plugins/gis/prive/themes/spip/images/gis-24.png differ
diff --git a/www/plugins/gis/prive/themes/spip/images/gis-new-16.png b/www/plugins/gis/prive/themes/spip/images/gis-new-16.png
new file mode 100644 (file)
index 0000000..e84098a
Binary files /dev/null and b/www/plugins/gis/prive/themes/spip/images/gis-new-16.png differ
diff --git a/www/plugins/gis/saisies/carte.html b/www/plugins/gis/saisies/carte.html
new file mode 100644 (file)
index 0000000..e86d9ec
--- /dev/null
@@ -0,0 +1,250 @@
+[(#REM)
+
+       Saisie carte
+
+       Parametres optionnels:
+
+       - lat = 48.3                    latitude du centre de la carte
+       - lon = -4.7                    longitude du centre de la carte
+       - zoom = 5                      zoom de la carte
+       - sw_lat = lat - 10°            latitude du sud-ouest de la bounding box
+       - sw_lon = lon - 10°            longitude du sud-ouest de la bounding box
+       - ne_lat = lat + 10°            latitude du nord-est de la bounding box
+       - ne_lon = lon + 10°            longitude du nord-est de la bounding box
+       - largeur = 100%
+       - hauteur = 350px
+
+]
+
+[(#SET{init_lat,#ENV{lat,#CONFIG{gis/lat,0}}})]
+[(#SET{init_lon,#ENV{lon,#CONFIG{gis/lon,0}}})]
+[(#SET{init_zoom,#ENV{zoom,#CONFIG{gis/zoom,0}}})]
+[(#REM) On utilise la bounding box seulement si le centre n'a pas été donné et si les quatre valeurs de la bounding box sont renseignées
+        Les valeurs par defaut sont "centre +/- 10°", ce qui est naze, mais c'est un cas normalement impossible
+]
+[(#ENV{lat}|ou{#ENV{lon}}|non|et{#ENV{sw_lat}}|et{#ENV{sw_lon}}|et{#ENV{ne_lat}}|et{#ENV{ne_lon}})
+       #SET{utiliser_bb, oui}
+       #SET{init_sw_lat,#ENV{sw_lat,#GET{lat}|moins{10}}}
+       #SET{init_sw_lon,#ENV{sw_lon,#GET{lon}|moins{10}}}
+       #SET{init_ne_lat,#ENV{ne_lat,#GET{lat}|plus{10}}}
+       #SET{init_ne_lon,#ENV{ne_lon,#GET{lon}|plus{10}}}
+]
+
+<li class="pleine_largeur editer editer_[(#ENV{nom})][ (#ENV{li_class})][ saisie_(#ENV{type_saisie})]"[ data-id="(#ENV{id_saisie})"]>
+#ENV*{inserer_debut}
+<div id="map_[(#ENV{nom})]" name="formMap" class="formMap" style="width: #ENV{largeur,100%}; height: #ENV{hauteur,350px}"></div>
+<script type="text/javascript">
+<!--
+var form_map;
+var annuler_geocoder = 0;
+[(#ENV{recherche}|!={non}|oui|et{#CONFIG{gis/geocoder}|oui})
+[(#SET{geocoder,oui})]
+var geocoder;]
+
+(function($){
+       var champ_lat = $('#champ_#ENV{champ_lat,lat}');
+       var champ_lon = $('#champ_#ENV{champ_lon,lon}');
+       var champ_zoom = $('#champ_#ENV{champ_zoom,zoom}');
+       var champ_adresse = $('#champ_#ENV{champ_adresse,adresse}');
+       var champ_code_postal = $('##ENV{champ_code_postal,code_postal}');
+       var champ_ville = $('#champ_#ENV{champ_ville,ville}');
+       var champ_region = $('#champ_#ENV{champ_region,region}');
+       var champ_pays = $('#champ_#ENV{champ_pays,pays}');
+       
+       var marker;
+       
+       var maj_inputs = function(map,data,action) {
+               [(#GET{geocoder}|oui)
+               if (action != 'geocoding') {
+                       var f = geocoder.geocode(data);
+               }]
+               var zoom = map.getZoom();
+               $('#champ_#ENV{champ_zoom,zoom}').val(zoom);
+               if(action == 'click'){
+                       $('#champ_#ENV{champ_lat,lat}').val(data.lat);
+                       $('#champ_#ENV{champ_lon,lon}').val(data.lng);
+                       annuler_geocoder = 1;
+                       form_map.panTo(data);
+                       marker.setLatLng(data);
+               }
+               else if(annuler_geocoder != 1){
+                       if(data.point == 'undefined'){
+                               $('#champ_#ENV{champ_lat,lat}').val(data.lat);
+                               $('#champ_#ENV{champ_lon,lon}').val(data.lng);
+                               form_map.panTo(data);
+                               marker.setLatLng(data);
+                       }else{
+                               $('#champ_#ENV{champ_lat,lat}').val(data.point.lat);
+                               $('#champ_#ENV{champ_lon,lon}').val(data.point.lng);
+                               form_map.panTo(data.point);
+                               marker.setLatLng(data.point);
+                       }
+               }
+               if (!marker._map)
+                       form_map.addLayer(marker);
+       }
+       
+       [(#GET{geocoder}|oui)
+       function geocode(query) {
+               $('#champ_#ENV{champ_adresse,adresse}').val(query.street);
+               $('#champ_#ENV{champ_code_postal,code_postal}').val(query.postcode);
+               $('#champ_#ENV{champ_ville,ville}').val(query.locality);
+               $('#champ_#ENV{champ_region,region}').val(query.region);
+               $('#champ_#ENV{champ_pays,pays}').val(query.country);
+               maj_inputs(form_map,query,'geocoding');
+       }]
+       
+       var init_map = function(callback) {
+               // creer la carte
+               var map_container = 'map_[(#ENV{nom})]';
+               form_map = new L.Map(map_container);
+               
+               // appeler l'éventuelle fonction de callback
+               if (callback && typeof(callback) === "function") {
+                       form_map.on('load',function(e){
+                               callback(e.target);
+                       });
+               }
+               form_map.attributionControl.setPrefix('');
+               
+               marker = new L.Marker(new L.LatLng(#ENV{lat,0}, #ENV{lon,0}), {draggable: true});
+               
+               //default layer
+               #SET{layer_defaut,#REM|gis_layer_defaut} #SET{layers,#EVAL{$GLOBALS['gis_layers']}}
+               var [(#GET{layer_defaut})] = [new (#GET{layers}|table_valeur{#GET{layer_defaut}/layer})];
+               form_map.addLayer([(#GET{layer_defaut})]);
+               
+               <B_layers>
+               var layers_control = new L.Control.Layers();
+               layers_control.addBaseLayer([(#GET{layer_defaut})],["(#GET{layers}|table_valeur{#GET{layer_defaut}/nom})"]);
+               <BOUCLE_layers(DATA){source table, #GET{layers}}{si #ENV{control_type,#ENV{controle_type}}|!={non}|et{#ENV{no_control,#ENV{aucun_controle}}|!={oui}}|et{#CONFIG{gis/layers,#ARRAY}|count|>{1}|oui}|oui}>[
+               (#CLE|!={#GET{layer_defaut}}|oui|et{#CLE|in_array{#CONFIG{gis/layers,#ARRAY}}|oui}|oui)
+               layers_control.addBaseLayer([new (#VALEUR|table_valeur{layer})],"[(#VALEUR|table_valeur{nom})]");]
+               </BOUCLE_layers>
+               form_map.addControl(layers_control);
+               // ajouter l'objet du controle de layers à la carte pour permettre d'y accéder depuis le callback
+               form_map.layersControl = layers_control;
+               // classe noajax sur le layer_control pour éviter l'ajout de hidden par SPIP
+               $(layers_control._form).addClass('noajax');
+               </B_layers>
+               
+               [(#GET{utiliser_bb}|non)
+               form_map.setView(new L.LatLng([(#GET{init_lat})], [(#GET{init_lon})]), [(#GET{init_zoom})]); 
+               ]
+               [(#GET{utiliser_bb}|oui)
+               form_map.fitBounds(
+                       new L.LatLngBounds(
+                               new L.LatLng([(#GET{init_sw_lat})], [(#GET{init_sw_lon})]),
+                               new L.LatLng([(#GET{init_ne_lat})], [(#GET{init_ne_lon})])
+                       )
+               );
+               // mettre à jour les champs de latitude et longitude quand la carte est chargée
+               // a voir si on le fait dans tous les cas, pas seulement pour la boundingbox, comme pour le zoom
+               form_map.on('load', function(e) {
+                       $('#champ_#ENV{champ_lat,lat}').val(e.latlng.lat);
+                       $('#champ_#ENV{champ_lon,lon}').val(e.latlng.lon);
+               });             
+               ]
+               
+               [(#GET{geocoder}|oui)
+               geocoder = new L.Geocoder(geocode);]
+               
+               [(#REM) Ici on utilise #ENV{lat} et #ENV{lon}, et pas les valeurs
+                       d'initialisation #GET{init_lat} et #GET{init_lon} qui sont toujours remplies]
+               [(#ENV{lat}|et{#ENV{lon}}|oui)
+               var data = {
+                       "type": "FeatureCollection",
+                       "features": \[
+                               {"type": "Feature",
+                                       "geometry": {"type": "Point", "coordinates": \[#ENV{lon}, #ENV{lat}\]},
+                                       "id":"#ENV{id_gis,oui}",
+                                       "properties": {
+                                               "title":[(#ENV{titre,''}|supprimer_numero|json_encode)],
+                                               "description":[(#ENV{descriptif,''}|json_encode)][,(#LOGO_GIS|oui)
+                                               [(#SET{logo_doc,#LOGO_GIS|image_passe_partout{32,32}|image_recadre{32,32}})]
+                                               #SET{icon_w,#GET{logo_doc}|extraire_attribut{src}|largeur}
+                                               #SET{icon_h,#GET{logo_doc}|extraire_attribut{src}|hauteur}
+                                               ["icon": (#GET{logo_doc}|extraire_attribut{src}|url_absolue|json_encode)],
+                                               "icon_size": \[#GET{icon_w},#GET{icon_h}\],
+                                               "icon_anchor": \[[(#GET{icon_w}|div{2})],[(#GET{icon_h})]\],
+                                               "popup_anchor": \[1,[-(#GET{icon_h}|div{1.2})]\]]
+                                       }
+                               }\]
+               }
+               
+               var geojson = new L.geoJson('', {
+                       onEachFeature: function (feature, layer) {
+                               marker = layer;
+                               layer.options.draggable = true;
+                               if (feature.properties && feature.properties.icon){
+                                       layer.setIcon(new L.Icon({
+                                               iconUrl: feature.properties.icon,
+                                               iconSize: new L.Point( feature.properties.icon_size\[0\], feature.properties.icon_size\[1\] ),
+                                               iconAnchor: new L.Point( feature.properties.icon_anchor\[0\], feature.properties.icon_anchor\[1\] ),
+                                               popupAnchor: new L.Point( feature.properties.popup_anchor\[0\], feature.properties.popup_anchor\[1\] )
+                                       }));
+                               }
+                               if (feature.properties && feature.properties.title){
+                                       layer.bindPopup(feature.properties.title);
+                               }
+                       }
+               }).addTo(form_map);
+               geojson.addData(data);]
+               
+               // mettre a jour les coordonnees quand on clique la carte
+               form_map.on('click', function(e) {
+                       annuler_geocoder = 0;
+                       maj_inputs(form_map,e.latlng,'click');
+               });
+               
+               marker.on("dragend", function(e){
+                       maj_inputs(form_map,e.target._latlng,'click');
+               });
+               
+               // mettre à jour le zoom quand on le modifie
+               form_map.on('zoomend', function(e) {
+                       $('#champ_#ENV{champ_zoom,zoom}').val(e.target._zoom);
+               });
+               
+               [(#GET{geocoder}|oui)
+               // geocoder si clic...
+               $('a##ENV{nom}_rechercher_geocodage').css("cursor","pointer").click(function(){
+                       var address = $("#champ_#ENV{nom}_geocoder").attr("value");
+                       annuler_geocoder = 0;
+                       geocoder.geocode(address);
+               });
+
+               // ne pas soumettre le formulaire si on presse Entree depuis le champ de recherche
+               $('#champ_#ENV{nom}_geocoder').keypress(function(e){
+                       if (e.which == 13) {
+                               $('a##ENV{nom}_rechercher_geocodage').trigger("click");
+                               return false;
+                       }
+               });]
+               
+               [(#ENV{id_gis}|non|ou{#ENV{id_gis}|=={oui}}|et{#CONFIG{gis/geolocaliser_user_html5}|=={on}}|oui)
+               form_map.locate({setView: true, maxZoom: [(#GET{init_zoom})]});]
+               
+       };
+
+       $(function(){
+               jQuery.getScript('[(#PRODUIRE{fond=javascript/gis.js}|compacte)]',function(){
+                       if (typeof(callback_form_map) === "function") {
+                               init_map(callback_form_map);
+                       } else {
+                               init_map();
+                       }
+               });
+       });
+       
+})(jQuery);
+-->
+</script>
+#ENV*{inserer_fin}
+</li>
+[(#GET{geocoder}|oui)
+<li class="rechercher_adresse editer_[(#ENV{nom})]">
+       <label for="champ_#ENV{nom}_geocoder"><:gis:label_rechercher_address:></label>
+       <input type="text" class="text" name="champ_#ENV{nom}_geocoder" id="champ_#ENV{nom}_geocoder" value="" />
+       <a id="#ENV{nom}_rechercher_geocodage"><:info_rechercher:></a>
+</li>]
diff --git a/www/plugins/gis/svn.revision b/www/plugins/gis/svn.revision
new file mode 100644 (file)
index 0000000..15e4891
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/gis/trunk
+Revision: 73835
+Dernier commit: 2013-06-24 20:00:11 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/gis/trunk</origine>
+<revision>73835</revision>
+<commit>2013-06-24 20:00:11 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/gis/tests/gis_connect_sql.php b/www/plugins/gis/tests/gis_connect_sql.php
new file mode 100644 (file)
index 0000000..b40ee7e
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+       // attention avant de lancer ce test !
+       // le dossier du plugin ne doit pas être un lien symbolique dans /plugins
+       // sous peine de générer un timeout...
+       
+       $test = 'gis_connect_sql';
+
+       $remonte = "../";
+       while (!is_dir($remonte."ecrire"))
+               $remonte = "../$remonte";
+       require $remonte.'tests/test.inc';
+       find_in_path("./base/connect_sql.php",'',true);
+
+
+       // Les tests
+       $essais['table_objet'] = array(
+       array('gis','gis'),
+       );
+
+       $essais['table_objet_sql'] = array(
+       array('spip_gis','gis'),
+       );
+
+       $essais['id_table_objet'] = array(
+       array('id_gis','gis'),
+       );
+
+
+       $essais['objet_type'] = array(
+       array('gis','gis'),
+       );
+
+       // hop ! on y va
+       $err = array();
+       foreach($essais as $f=>$essai)
+               $err = array_merge(tester_fun($f, $essai),$err);
+       
+       // si le tableau $err est pas vide ca va pas
+       if ($err) {
+               echo ('<dl>' . join('', $err) . '</dl>');
+       } else {
+               echo "OK";
+       }
+
+?>
\ No newline at end of file
diff --git a/www/plugins/menus_1/action/editer_menu.php b/www/plugins/menus_1/action/editer_menu.php
new file mode 100644 (file)
index 0000000..b93b43e
--- /dev/null
@@ -0,0 +1,144 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Action de création / Modification d'un menu
+ * @param unknown_type $arg
+ * @return unknown_type
+ */
+function action_editer_menu_dist($arg=null) {
+
+       if (is_null($arg)){
+               $securiser_action = charger_fonction('securiser_action', 'inc');
+               $arg = $securiser_action();
+       }
+
+       // si id_menu n'est pas un nombre, c'est une creation
+       if (!$id_menu = intval($arg)) {
+               $id_menu = insert_menu();
+       }
+
+       // Enregistre l'envoi dans la BD
+       if ($id_menu > 0) $err = menu_set($id_menu);
+
+       // S'il y a un fichier on tente d'importer son contenu
+       if ($_FILES['import']){
+               $fichier = $_FILES['import']['tmp_name'];
+               $yaml = '';
+               lire_fichier($fichier, $yaml);
+               // Si on a bien recupere une chaine on tente de la decoder
+               if ($yaml){
+                       include_spip('inc/yaml');
+                       $entrees = yaml_decode($yaml);
+                       // Si le decodage marche on importe alors le contenu
+                       if (is_array($entrees)){
+                               menus_importer($entrees, $id_menu);
+                       }
+               }
+       }
+
+       if (_request('redirect')) {
+               $redirect = parametre_url(urldecode(_request('redirect')),
+                       'id_menu', $id_menu, '&') . $err;
+
+               include_spip('inc/headers');
+               redirige_par_entete($redirect);
+       }
+       else
+               return array($id_menu,$err);
+}
+
+/**
+ * Appelle la fonction de modification d'un menu
+ *
+ * @param int $id_menu
+ * @param unknown_type $set
+ * @return $err
+ */
+function menu_set($id_menu, $set=null) {
+       $err = '';
+
+       $c = array();
+       foreach (array(
+               'titre',
+               'identifiant',
+               'css'
+       ) as $champ)
+               $c[$champ] = _request($champ,$set);
+
+       include_spip('inc/modifier');
+       revision_menu($id_menu, $c);
+
+       return $err;
+}
+
+/**
+ * Crée un nouveau menu et retourne son ID
+ *
+ * @return int id_menu
+ */
+function insert_menu() {
+       $champs = array('titre'=>''); // eviter le bug de req/sqlite < 2.1.3
+       // Envoyer aux plugins
+       $champs = pipeline('pre_insertion',
+               array(
+                       'args' => array(
+                               'table' => 'spip_menus',
+                       ),
+                       'data' => $champs
+               )
+       );
+       $id_menu = sql_insertq("spip_menus");
+
+       return $id_menu;
+}
+
+/**
+ * Enregistre une révision de menu
+ *
+ * @param int $id_menu
+ * @param array $c
+ * @return
+ */
+function revision_menu ($id_menu, $c=false) {
+       $invalideur = "id='id_menu/$id_menu'";
+
+       modifier_contenu('menu', $id_menu,
+               array(
+                       'nonvide' => array('titre' => _T('info_sans_titre')),
+                       'invalideur' => $invalideur
+               ),
+               $c);
+
+       return ''; // pas d'erreur
+}
+
+function menus_importer($entrees, $id_menu){
+       // On lit chaque entree de premier niveau
+       foreach ($entrees as $cle => $entree){
+               // On ajoute cette entree
+               $id_menus_entree = sql_insertq(
+                       'spip_menus_entrees',
+                       array(
+                               'id_menu' => $id_menu,
+                               'rang' => ($cle+1),     // les entrees sont dans l'ordre des rangs
+                               'type_entree' => $entree['type_entree'],
+                               'parametres' => serialize($entree['parametres'])
+                       )
+               );
+
+               // S'il existe un sous-menu pour cette entree on le cree
+               if (is_array($entree['sous_menu'])){
+                       $id_sous_menu = sql_insertq(
+                               'spip_menus',
+                               array(
+                                       'id_menus_entree' => $id_menus_entree
+                               )
+                       );
+                       // Puis dedans on importe les entrees correspondantes
+                       menus_importer($entree['sous_menu'], $id_sous_menu);
+               }
+       }
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/menus_1/action/editer_menus_entree.php b/www/plugins/menus_1/action/editer_menus_entree.php
new file mode 100644 (file)
index 0000000..8219c83
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Action de création / Modification d'une entrée de menu
+ * @param unknown_type $arg
+ * @return unknown_type
+ */
+function action_editer_menus_entree_dist($arg=null) {
+
+       $securiser_action = charger_fonction('securiser_action', 'inc');
+       $arg = $securiser_action();
+
+       // si id_menus_entree n'est pas un nombre, c'est une creation
+       if (!$id_menus_entree = intval($arg)) {
+               $id_menu = _request('id_menu_nouvelle_entree') ? _request('id_menu_nouvelle_entree') : _request('id_menu');
+               if(intval($id_menu)){
+                       $id_menus_entree = insert_menus_entree($id_menu);
+               }
+       }
+
+       // Enregistre l'envoi dans la BD
+       if ($id_menus_entree > 0)
+               $err = menus_entree_set($id_menus_entree);
+
+       if (_request('redirect')) {
+               $redirect = parametre_url(urldecode(_request('redirect')),
+                       'id_menus_entree', $id_menus_entree, '&') . $err;
+
+               include_spip('inc/headers');
+               redirige_par_entete($redirect);
+       }
+       else
+               return array($id_menus_entree,$err);
+}
+
+/**
+ * Crée une nouvelle entree de menu et retourne son ID
+ *
+ * @return int id_menus_entree
+ */
+function insert_menus_entree($id_menu) {
+       // Envoyer aux plugins
+       $champs = pipeline('pre_insertion',
+               array(
+                       'args' => array(
+                               'table' => 'spip_menus_entrees',
+                       ),
+                       'data' => $champs
+               )
+       );
+
+       $id_menus_entree = sql_insertq("spip_menus_entrees",array('id_menu'=>$id_menu));
+
+       return $id_menus_entree;
+}
+
+/**
+ * Appelle la fonction de modification d'une entrée de menu
+ *
+ * @param int $id_menu_entree
+ * @param unknown_type $set
+ * @return $err
+ */
+function menus_entree_set($id_menus_entree, $set=null) {
+       $err = '';
+
+       $c = array();
+       $c['id_menu'] = _request('id_menu_nouvelle_entree');
+
+       foreach (array(
+               'rang',
+               'type_entree',
+               'parametres'
+       ) as $champ)
+               $c[$champ] = _request($champ, $set);
+
+       $c['parametres'] = is_array($c['parametres']) ? $c['parametres'] : array();
+       $c['parametres'] = serialize($c['parametres']);
+
+       include_spip('inc/menus');
+       $entrees = menus_lister_disponibles();
+       $infos = $entrees[$c['type_entree']];
+
+       include_spip('inc/modifier');
+       revision_menus_entree($id_menus_entree, $c);
+
+       return $err;
+}
+
+/**
+ * Enregistre une révision d'entree de menu
+ *
+ * @param int $id_menus_entree
+ * @param array $c
+ * @return
+ */
+function revision_menus_entree ($id_menus_entree, $c=false) {
+       $invalideur = "id='id_menus_entree/$id_menus_entree'";
+
+       modifier_contenu('menus_entree', $id_menus_entree,
+               array(
+                       'invalideur' => $invalideur
+               ),
+               $c);
+
+       return ''; // pas d'erreur
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/menus_1/action/exporter_menu.php b/www/plugins/menus_1/action/exporter_menu.php
new file mode 100644 (file)
index 0000000..b24f21a
--- /dev/null
@@ -0,0 +1,72 @@
+<?php 
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_exporter_menu_dist(){
+       
+       $securiser_action = charger_fonction('securiser_action', 'inc');
+       $arg = $securiser_action();
+       $id_menu = intval($arg);
+       $export = '';
+       
+       if ($id_menu > 0){
+               include_spip('base/abstract_sql');
+               include_spip('inc/yaml');
+               
+               // On récupère l'identifiant du menu pour le nom de fichier
+               $identifiant = sql_getfetsel(
+                       'identifiant',
+                       'spip_menus',
+                       'id_menu = '.$id_menu
+               );
+               
+               // On calcule le tableau des entrees
+               $entrees = exporter_menu_recursif($id_menu);
+               
+               // On envode en yaml
+               $export = yaml_encode($entrees);
+       }
+       
+       Header("Content-Type: text/x-yaml;");
+       Header("Content-Disposition: attachment; filename=menu-$identifiant.yaml");
+       Header("Content-Length: ".strlen($export));
+       echo $export;
+       exit();
+       
+}
+
+function exporter_menu_recursif($id_menu){
+       $entrees = sql_allfetsel(
+               'id_menus_entree, type_entree, parametres',
+               'spip_menus_entrees',
+               'id_menu = '.$id_menu,
+               '',
+               'rang'
+       );
+       
+       // Pour chaque entree on nettoie et on ajoute le sous-menu eventuel
+       foreach ($entrees as $cle => $entree){
+               // On remet au propre les parametres
+               $entrees[$cle]['parametres'] = unserialize($entree['parametres']);
+               
+               // On regarde s'il existe un sous-menu
+               $id_sous_menu = intval(sql_getfetsel(
+                       'id_menu',
+                       'spip_menus',
+                       'id_menus_entree = '.$entree['id_menus_entree']
+               ));
+               
+               // Si le menu existe, il faut l'ajouter au tableau
+               if ($id_sous_menu > 0){
+                       $entrees[$cle]['sous_menu'] = exporter_menu_recursif($id_sous_menu);
+               }
+               
+               // On enleve id_menus_entree car on en a pas besoin
+               unset($entrees[$cle]['id_menus_entree']);
+       }
+       
+       return $entrees;
+}
+
+?>
diff --git a/www/plugins/menus_1/action/supprimer_menu.php b/www/plugins/menus_1/action/supprimer_menu.php
new file mode 100644 (file)
index 0000000..086fea4
--- /dev/null
@@ -0,0 +1,19 @@
+<?php 
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_supprimer_menu_dist(){
+       
+       $securiser_action = charger_fonction('securiser_action', 'inc');
+       $arg = $securiser_action();
+       $id_menu = intval($arg);
+       
+       if ($id_menu > 0){
+               include_spip('inc/menus');
+               menus_supprimer_menu($id_menu);
+       }
+       
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/menus_1/balise/menus_afficher_entree.php b/www/plugins/menus_1/balise/menus_afficher_entree.php
new file mode 100644 (file)
index 0000000..81ac857
--- /dev/null
@@ -0,0 +1,26 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function balise_MENUS_AFFICHER_ENTREE_dist($p) {
+       
+       $contexte = interprete_argument_balise(1,$p);
+       $id_menus_entree = champ_sql('id_menus_entree', $p);
+       $type_entree = champ_sql('type_entree', $p);
+       $parametres = champ_sql('parametres', $p);
+       
+       // Par défaut ça affiche le mode du menu public
+       if ($contexte != "'appel_formulaire'")
+               $contexte = "'appel_menu'";
+       
+       $p->code =  "(!$id_menus_entree) ? _T('zbug_champ_hors_motif', array('champ'=>'AFFICHER_ENTREE', 'motif'=>'MENUS_ENTREES')) : recuperer_fond(
+               'menus/'.$type_entree,
+               array_merge(unserialize($parametres), array($contexte=>true, env=>\$Pile[0]))
+       )";
+       
+       return $p;
+    
+}
+
+?>
diff --git a/www/plugins/menus_1/base/menus_tables.php b/www/plugins/menus_1/base/menus_tables.php
new file mode 100644 (file)
index 0000000..0bca5d4
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function menus_declarer_tables_interfaces($interface){
+       // 'spip_' dans l'index de $tables_principales
+       $interface['table_des_tables']['menus']='menus';
+       $interface['table_des_tables']['menus_entrees']='menus_entrees';
+       
+       // Titres
+       $interface['table_titre']['menus'] = 'titre, "" as lang';
+       
+       return $interface;
+}
+
+function menus_declarer_tables_principales($tables_principales){
+       //-- Table menus -----------------------------------------------------------
+       $menus = array(
+               "id_menu" => "bigint(21) NOT NULL",
+               "id_menus_entree" => "bigint(21) DEFAULT '0' NOT NULL",
+               "titre" => "text DEFAULT '' NOT NULL",
+               "identifiant" => "varchar(255) default '' not null",
+               "css" => "tinytext DEFAULT '' NOT NULL"
+       );
+       
+       $menus_cles = array(
+               "PRIMARY KEY" => "id_menu",
+               "KEY id_menus_entree" => "id_menus_entree"
+       );
+       
+       $tables_principales['spip_menus'] = array(
+               'field' => &$menus,
+               'key' => &$menus_cles
+       );
+       
+       // Table menus_elements ----------------------------------------------------
+       $menus_entrees = array(
+               "id_menus_entree" => "bigint(21) NOT NULL",
+               "id_menu" => "bigint(21) DEFAULT '0' NOT NULL",
+               "rang" => "smallint DEFAULT '1' NOT NULL",
+               "type_entree" => "tinytext DEFAULT '' NOT NULL",
+               "parametres" => "text DEFAULT '' NOT NULL"
+       );
+       
+       $menus_entrees_cles = array(
+               "PRIMARY KEY" => "id_menus_entree",
+               "KEY id_menu" => "id_menu"
+       );
+       
+       $tables_principales['spip_menus_entrees'] = array(
+               'field' => &$menus_entrees,
+               'key' => &$menus_entrees_cles
+       );
+
+       return $tables_principales;
+}
+
+?>
diff --git a/www/plugins/menus_1/css/menuspip.css b/www/plugins/menus_1/css/menuspip.css
new file mode 100644 (file)
index 0000000..eeaa285
--- /dev/null
@@ -0,0 +1,58 @@
+
+.formulaire_editer_menu_entrees{
+       position:relative;
+}
+.formulaire_editer_menu_entrees .image_loading{
+       position:absolute;
+       top:50%;
+       left:50%;
+}
+
+.formulaire_spip ul.menus_entrees{
+       clear:both;
+}
+.formulaire_spip ul.menus_entrees ul.menus_entrees{
+       border-left:1px solid #ccc;
+       border-top:1px solid #ccc;
+}
+
+.formulaire_spip ul.menus_entrees li.entree{
+       clear:both;
+       padding-left : 34px;
+       padding-right:0;
+       padding-bottom:0;
+       background-position:5px 10px;
+       background-repeat:no-repeat;
+       border-bottom:1px solid #ccc;
+}
+
+.formulaire_spip ul.menus_entrees .ligne{
+       position:relative;
+}
+
+.formulaire_spip ul.menus_entrees .actions{
+       position:absolute;
+       right:5px;
+       top:5px;
+       text-align:right;
+}
+
+.formulaire_spip ul.menus_entrees .titre{
+       font-weight:bold;
+       line-height:29px;
+}
+.formulaire_spip ul.menus_entrees .infos{
+       font-size:0.9em;
+       margin-bottom:5px;
+}
+
+.formulaire_spip ul.menus_entrees .actions button{
+       border:none;
+       padding:0;
+       margin:0;
+       cursor:pointer;
+
+}
+.formulaire_spip ul.menus_entrees img{
+       vertical-align:middle;
+}
diff --git a/www/plugins/menus_1/formulaires/configurer_menus.html b/www/plugins/menus_1/formulaires/configurer_menus.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/www/plugins/menus_1/formulaires/configurer_menus.php b/www/plugins/menus_1/formulaires/configurer_menus.php
new file mode 100644 (file)
index 0000000..7c82054
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+function formulaires_configurer_menus_saisies_dist(){
+       include_spip('inc/menus');
+       include_spip('inc/config');
+       
+       // Récupérer les entrées existantes
+       $entrees = menus_lister_disponibles();
+       
+       // Trier les entrées par rang
+       uasort($entrees, create_function('$a, $b', '$a = $a["rang"]; $b = $b["rang"]; return ($a==$b)?0:($a<$b?-1:1);'));
+       
+       // Remplir la liste des cases
+       $data = array();
+       foreach ($entrees as $type_entree=>$entree){
+               $data[$type_entree] = '<img src="'.$entree['icone'].'" /> '.$entree['nom'];
+       }
+       
+       $saisies = array(
+               array(
+                       'saisie' => 'checkbox',
+                       'options' => array(
+                               'nom' => 'entrees_masquees',
+                               'explication' => 'Cochez les entrées que vous voulez <strong>masquer</strong> lors de la création d\'un menu.',
+                               'datas' => $data,
+                               'li_class' => 'pleine_largeur',
+                               'defaut' => lire_config('menus/entrees_masquees',array())
+                       )
+               )
+       );
+       
+       return $saisies;
+}
+
+?>
diff --git a/www/plugins/menus_1/formulaires/editer_menu.html b/www/plugins/menus_1/formulaires/editer_menu.html
new file mode 100644 (file)
index 0000000..55e1a0c
--- /dev/null
@@ -0,0 +1,74 @@
+<div class="formulaire_spip formulaire_editer [formulaire_(#ENV{form})][ formulaire_(#ENV{form})-#ENV{id_menu,nouveau}]">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+       [(#ENV{editable})
+               <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div>
+                       [(#REM) declarer les hidden qui declencheront le service du formulaire
+                       parametre : url d'action ]
+                       #ACTION_FORMULAIRE{#ENV{action}}
+
+                       <ul>
+                               <li class="fieldset">
+                                       <fieldset>
+                                               <h3 class="legend"><:menus:formulaire_partie_identification:></h3>
+                                               <ul>
+                                                       #SET{obli,'obligatoire'}
+                                                       #SET{name,titre}
+                                                       #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
+                                                       <li class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
+                                                               <label for="#GET{name}"><:menus:formulaire_titre:></label>
+                                                               [<span class='erreur_message'>(#GET{erreurs})</span>]
+                                                               <input type="text" class="text multilang" name="#GET{name}" id="#GET{name}" size="40" value="#ENV{#GET{name}}" />
+                                                       </li>
+
+                                                       #SET{name,identifiant}
+                                                       #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
+                                                       <li class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
+                                                               <label for="#GET{name}"><:menus:formulaire_identifiant:></label>
+                                                               <div class="explication"><:menus:formulaire_identifiant_explication:></div>
+                                                               [<span class='erreur_message'>(#GET{erreurs})</span>]
+                                                               <input type="text" class="text" name="#GET{name}" id="#GET{name}" size="40" value="#ENV{#GET{name}}" />
+                                                       </li>
+
+                                                       #SET{name,css}
+                                                       #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
+                                                       <li class="editer editer_[(#GET{name})][ (#GET{erreurs}|oui)erreur]">
+                                                               <label for="#GET{name}"><:menus:formulaire_css:></label>
+                                                               <div class="explication"><:menus:formulaire_css_explication:></div>
+                                                               [<span class='erreur_message'>(#GET{erreurs})</span>]
+                                                               <input type="text" class="text" name="#GET{name}" id="#GET{name}" size="40" value="#ENV{#GET{name}}" />
+                                                       </li>
+
+                                                       [(#REM) Seulement si c'est un nouveau et qu'il y a le plugin YAML)]
+                                                       [(#ENV{nouveau}|oui)
+                                                               [(#PLUGIN{yaml}|oui)
+                                                                       #SET{name,import}
+                                                                       #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
+                                                                       <li class="editer editer_[(#GET{name})][ (#GET{erreurs}|oui)erreur]">
+                                                                               <label for="#GET{name}"><:menus:formulaire_importer:></label>
+                                                                               <div class="explication"><:menus:formulaire_importer_explication:></div>
+                                                                               [<span class='erreur_message'>(#GET{erreurs})</span>]
+                                                                               <input type="file" class="file" name="#GET{name}" id="#GET{name}" size="20" value="#ENV{#GET{name}}" />
+                                                                       </li>
+                                                               ]
+                                                       ]
+                                               </ul>
+
+                                               <p class='boutons'>
+                                                       <input type='submit' class='submit' value='<:bouton_enregistrer:>' />
+                                               </p>
+                                       </fieldset>
+                               </li>
+                       </ul>
+               </div></form>
+               ]
+</div>
+<script type="text/javascript">
+       $(function(){
+               $('.formulaire_#ENV{form}'+' .boutons').hide();
+               $('.formulaire_#ENV{form}'+' input')
+                       .change(function(){$('.formulaire_#ENV{form}'+' .boutons').slideDown();})
+                       .keydown(function(){$('.formulaire_#ENV{form}'+' .boutons').slideDown();});
+       });
+</script>
\ No newline at end of file
diff --git a/www/plugins/menus_1/formulaires/editer_menu.php b/www/plugins/menus_1/formulaires/editer_menu.php
new file mode 100644 (file)
index 0000000..66e43b7
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/editer');
+
+function formulaires_editer_menu_charger($id_menu, $nouveau){
+       include_spip('base/abstract_sql');
+       include_spip('inc/autoriser');
+       $contexte = array();
+       $contexte['editable'] = true;
+
+       // Seulement si on a le droit de modifier les menus
+       if (autoriser('modifier', 'menu')){
+               $nouveau = ($nouveau == 'oui') ? true : false;
+               $id_menu = intval($id_menu) ? intval($id_menu) : false;
+
+               // Si on demande un id_menu
+               if ($id_menu){
+                       // On désactive de toute façon le nouveau
+                       $nouveau = false;
+
+                       // On teste si le menu existe bien dans les menus principaux
+                       $id_menu_ok = intval(sql_getfetsel(
+                               'id_menu',
+                               'spip_menus',
+                               array(
+                                       array('=', 'id_menu', $id_menu),
+                                       array('=', 'id_menus_entree', 0)
+                               )
+                       ));
+
+                       // S'il n'existe pas
+                       if (!$id_menu_ok){
+                               $contexte['editable'] = false;
+                               $contexte['message_erreur'] = _T('menus:erreur_menu_inexistant', array('id'=>$id_menu));
+                       }
+               }
+               elseif (!$nouveau){
+                       $contexte['editable'] = false;
+                       $contexte['message_erreur'] = _T('menus:erreur_parametres');
+               }
+
+               // Si on peut bien éditer le menu, on déclare ce qu'il faut
+               if ($contexte['editable']){
+                       $contexte['id_menu'] = $id_menu;
+                       $contexte['nouveau'] = $nouveau;
+
+                       // Les champs du menu principal
+                       $contexte['titre'] = '';
+                       $contexte['identifiant'] = '';
+                       $contexte['css'] = '';
+                       $contexte['import'] = '';
+
+                       $valeurs = formulaires_editer_objet_charger('menu',$id_menu,0,0,'', '', '', '');
+
+                       $contexte = array_merge($contexte, $valeurs);
+
+                       // Déclarer l'action pour SPIP 2.0
+                       $contexte['_action'] = array('editer_menu', $id_menu);
+                       // On sait toujours si on est sur un menu déjà créé ou pas
+                       $contexte['_hidden'] .= '<input type="hidden" name="id_menu" value="'.$id_menu.'" />';
+               }
+       }
+       else{
+               $contexte['editable'] = false;
+               $contexte['message_erreur'] = _T('menus:erreur_autorisation');
+       }
+
+       return $contexte;
+}
+
+function formulaires_editer_menu_verifier($id_menu, $nouveau){
+       include_spip('base/abstract_sql');
+       $erreurs = array();
+
+       $oblis = array('titre','identifiant');
+       $erreurs = formulaires_editer_objet_verifier('menu',$id_menu,$oblis);
+
+       $identifiant = _request('identifiant');
+
+       // On vérifie que l'identifiant est bon
+       if (!$erreurs['identifiant'] and !preg_match('/^[\w]+$/', $identifiant))
+               $erreurs['identifiant'] = _T('menus:erreur_identifiant_forme');
+       // On vérifie que l'identifiant n'est pas déjà utilisé
+       if (!$erreurs['identifiant']){
+               $deja = sql_getfetsel(
+                       'id_menu',
+                       'spip_menus',
+                       array(
+                               'identifiant = '.sql_quote($identifiant),
+                               'id_menu > 0',
+                               'id_menu !='.intval(_request('id_menu'))
+                       )
+               );
+               if ($deja)
+                       $erreurs['identifiant'] = _T('menus:erreur_identifiant_deja');
+       }
+
+       return $erreurs;
+}
+
+function formulaires_editer_menu_traiter($id_menu, $nouveau){
+       $res = formulaires_editer_objet_traiter('menu', $id_menu, 0, 0, '', '', '', '');
+
+       // Si ça va pas on errorise
+       if (!$res['id_menu']){
+               $res['message_erreur'] = _T('menus:erreur_mise_a_jour');
+       }
+       else{
+               // Si on est dans l'espace privé on force la redirection
+               if (_request('exec') == 'menus_editer')
+                       $res['redirect'] = generer_url_ecrire('menus_editer', "id_menu=".$res['id_menu']);
+       }
+       // Dans tous les cas le formulaire est toujours éditable
+       $res['editable'] = true;
+
+       return $res;
+}
+
+?>
diff --git a/www/plugins/menus_1/formulaires/editer_menus_entree.html b/www/plugins/menus_1/formulaires/editer_menus_entree.html
new file mode 100644 (file)
index 0000000..5c5b3a1
--- /dev/null
@@ -0,0 +1,40 @@
+<div class="formulaire_spip formulaire_editer [formulaire_(#ENV{form})][ formulaire_(#ENV{form})-#ENV{id_menu,nouveau}]">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+       [(#ENV{editable})
+
+       <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+
+               <ul>
+                       <li class="fieldset">
+                               <fieldset>
+                                       <h3 class="legend"><:menus:formulaire_partie_construction:></h3>
+                                       <input style="display:none;" type="submit" class="submit" name="enregistrer" value="<:bouton_enregistrer:>" />
+
+                                       #INCLURE{fond=formulaires/inc-menus_entrees, env}
+                               </fieldset>
+                       </li>
+               </ul>
+       </div></form>
+
+       ]
+</div>
+
+<script type="text/javascript">
+       $(function(){
+               $('.entree .actions').hide();
+               $('.entree .ligne')
+                       .hover(
+                               function(){
+                                       $(this).find('.actions').show();
+                               },
+                               function(){
+                                       $(this).find('.actions').hide();
+                               }
+                       );
+       });
+</script>
\ No newline at end of file
diff --git a/www/plugins/menus_1/formulaires/editer_menus_entree.php b/www/plugins/menus_1/formulaires/editer_menus_entree.php
new file mode 100644 (file)
index 0000000..474976c
--- /dev/null
@@ -0,0 +1,252 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/menus');
+include_spip('inc/editer');
+include_spip('inc/actions');
+
+function formulaires_editer_menus_entree_charger($id_menu,$id_menus_entree='new'){
+       /**
+        * On vérifie si nous ne sommes pas dans une modification
+        * Sinon c'est une création
+        */
+       $id_menus_entree = intval(_request('modifier_entree')) ? _request('modifier_entree') : $id_menus_entree;
+
+       $valeurs = formulaires_editer_objet_charger('menus_entree',$id_menus_entree,0,0,'', '', '', '');
+
+       $valeurs['id_menu'] = $id_menu;
+
+       // Les champs pour les entrées
+
+       $valeurs['parametres'] = array();
+
+       // Des champs pour controler le formulaire
+       $valeurs['demander_nouvelle_entree'] = '';
+       $valeurs['id_menu_nouvelle_entree'] = '';
+       $valeurs['enregistrer'] = '';
+
+       // On a en permanence accès aux infos des types
+       $valeurs['types_entrees'] = menus_lister_disponibles();
+
+       // On sait toujours si on est sur un menu déjà créé ou pas
+       $valeurs['_hidden'] .= '<input type="hidden" name="id_menu" value="'.$id_menu.'" />';
+
+       return $valeurs;
+}
+
+function formulaires_editer_menus_entree_verifier($id_menu,$id_menus_entree='new'){
+       $erreurs = formulaires_editer_objet_verifier('menus_entree',$id_menus_entree,array());
+
+       // Si on demande une nouvelle entree pour un menu --------------------------
+
+       if ($id_menu = intval(_request('demander_nouvelle_entree'))){
+               // S'il n'y a pas encore de type d'entree de choisi
+               if (!($type_entree = _request('type_entree'))){
+                       include_spip('inc/config');
+                       $erreurs['id_menu_nouvelle_entree'] = $id_menu;
+                       // On charge les différents types d'entrées disponibles
+                       $masque = array_flip(lire_config('menus/entrees_masquees', array()));
+                       $erreurs['entrees'] = array_diff_key(menus_lister_disponibles(), $masque);
+                       if (_request('suivant'))
+                               $erreurs['type'] = _T('menus:erreur_type_menu');
+               }
+               // Si on a choisi un type d'entree
+               else{
+                       $erreurs['id_menu_nouvelle_entree'] = $id_menu;
+                       $erreurs['type_entree'] = $type_entree;
+                       // On charge les infos du type choisi
+                       $entrees = menus_lister_disponibles();
+                       $erreurs['infos_'.$type_entree] = $entrees[$type_entree];
+               }
+       }
+
+       // Si on veut modifier une entrée ------------------------------------------
+
+       if ($id_menus_entree = intval(_request('modifier_entree'))){
+               // On va chercher l'existant de cette entrée
+               $entree = sql_fetsel(
+                       'type_entree, parametres',
+                       'spip_menus_entrees',
+                       'id_menus_entree = '.$id_menus_entree
+               );
+               $type_entree = $entree['type_entree'];
+               $parametres = unserialize($entree['parametres']);
+
+               $erreurs = array_merge($erreurs, $parametres);
+               $erreurs['id_menus_entree'] = $id_menus_entree;
+               $erreurs['type_entree'] = $type_entree;
+               // On charge les infos du type choisi
+               $entrees = menus_lister_disponibles();
+               $erreurs['infos_'.$type_entree] = $entrees[$type_entree];
+       }
+
+       // Si on valide une entree pour un menu ------------------------------------
+
+       if (($id_menu = intval(_request('id_menu_nouvelle_entree')) or $id_menus_entree = intval(_request('id_menus_entree'))) and _request('enregistrer')){
+               $type_entree = _request('type_entree');
+               $parametres_envoyes = _request('parametres');
+               $entrees = menus_lister_disponibles();
+               $infos = $entrees[$type_entree];
+               // On teste que chaque paramètre obligatoire est bien renseigné
+               foreach ($infos['parametres'] as $nom=>$parametre){
+                       if ($parametre['obligatoire']){
+                               if (!$parametres_envoyes[$nom]){
+                                       if ($id_menu)
+                                               $erreurs['id_menu_nouvelle_entree'] = $id_menu;
+                                       if ($id_menus_entree)
+                                               $erreurs['id_menus_entree'] = $id_menus_entree;
+                                       $erreurs['type_entree'] = $type_entree;
+                                       $erreurs['infos_'.$type_entree] = $infos;
+                                       $erreurs['parametres'][$nom] = _T('info_obligatoire');
+                               }
+                       }
+               }
+       }
+
+       return $erreurs;
+}
+
+function formulaires_editer_menus_entree_traiter($id_menu,$id_menus_entree='new'){
+       $retours = array();
+
+       // Si on valide une entree pour un menu ------------------------------------
+
+       if (($id_menu = intval(_request('id_menu_nouvelle_entree')) or $id_menus_entree = intval(_request('id_menus_entree'))) and _request('enregistrer')){
+               $res = formulaires_editer_objet_traiter('menus_entree', $id_menus_entree, 0, 0, '', '', '', '');
+               if (!$res['id_menus_entree'])
+                       $retours['message_erreur'] = _T('menus:erreur_mise_a_jour');
+       }
+
+       // Si on demande la supression d'une entrée --------------------------------
+
+       if ($id_menus_entree = intval(_request('supprimer_entree'))){
+               $ok = menus_supprimer_entree($id_menus_entree);
+               if (!$ok)
+                       $retours['message_erreur'] = _T('menus:erreur_mise_a_jour');
+       }
+
+       // Si on demande à déplacer une entrée -------------------------------------
+
+       if ($params = _request('deplacer_entree')){
+               preg_match('/^([\d]+)-(bas|haut)$/', $params, $params);
+               array_shift($params);
+               list($id_menus_entree, $sens) = $params;
+               $id_menus_entree = intval($id_menus_entree);
+
+               // On récupère des infos sur le placement actuel
+               $entree = sql_fetsel(
+                       'id_menu, rang',
+                       'spip_menus_entrees',
+                       'id_menus_entree = '.$id_menus_entree
+               );
+               $id_menu = intval($entree['id_menu']);
+               $rang_actuel = intval($entree['rang']);
+
+               // On teste si ya une entrée suivante
+               $dernier_rang = intval(sql_getfetsel(
+                       'rang',
+                       'spip_menus_entrees',
+                       'id_menu = '.$id_menu,
+                       '',
+                       'rang desc',
+                       '0,1'
+               ));
+
+               // Tant qu'on ne veut pas faire de tour complet
+               if (!($sens == 'bas' and $rang_actuel == $dernier_rang) and !($sens == 'haut' and $rang_actuel == 1)){
+                       // Alors on ne fait qu'échanger deux entrées
+                       $rang_echange = ($sens == 'bas') ? ($rang_actuel + 1) : ($rang_actuel - 1);
+                       $ok = sql_updateq(
+                               'spip_menus_entrees',
+                               array(
+                                       'rang' => $rang_actuel
+                               ),
+                               'id_menu = '.$id_menu.' and rang = '.$rang_echange
+                       );
+                       if ($ok)
+                               $ok = sql_updateq(
+                                       'spip_menus_entrees',
+                                       array(
+                                               'rang' => $rang_echange
+                                       ),
+                                       'id_menus_entree = '.$id_menus_entree
+                               );
+               }
+               // Sinon on fait un tour complet en déplaçant tout
+               else{
+                       if ($sens == 'bas'){
+                               // Tout le monde descend d'un rang
+                               $ok = sql_update(
+                                       'spip_menus_entrees',
+                                       array(
+                                               'rang' => 'rang + 1'
+                                       ),
+                                       'id_menu = '.$id_menu
+                               );
+                               // L'entrée passe tout en haut
+                               if ($ok)
+                                       $ok = sql_updateq(
+                                               'spip_menus_entrees',
+                                               array(
+                                                       'rang' => 1
+                                               ),
+                                               'id_menus_entree = '.$id_menus_entree
+                                       );
+                       }
+                       else{
+                               // Tout le monde monte d'un rang
+                               $ok = sql_update(
+                                       'spip_menus_entrees',
+                                       array(
+                                               'rang' => 'rang - 1'
+                                       ),
+                                       'id_menu = '.$id_menu
+                               );
+                               // L'entrée passe tout en bas
+                               if ($ok)
+                                       $ok = sql_updateq(
+                                               'spip_menus_entrees',
+                                               array(
+                                                       'rang' => $dernier_rang
+                                               ),
+                                               'id_menus_entree = '.$id_menus_entree
+                                       );
+                       }
+               }
+               if (!$ok) $retours['message_erreur'] = _T('menus:erreur_mise_a_jour');
+       }
+
+       // Si on veut faire un sous-menu -------------------------------------------
+
+       if ($id_menus_entree = intval(_request('demander_sous_menu'))){
+               $id_menu = sql_insertq(
+                       'spip_menus',
+                       array(
+                               'id_menus_entree' => $id_menus_entree
+                       )
+               );
+               if (!$id_menu) $retours['message_erreur'] = _T('menus:erreur_mise_a_jour');
+       }
+
+       // Si on veut supprimer un menu --------------------------------------------
+
+       if ($id_menu = intval(_request('supprimer_menu'))){
+               // Est-ce un menu ou un sous-menu ?
+               $sous_menu = intval(sql_getfetsel(
+                       'id_menus_entree',
+                       'spip_menus',
+                       'id_menu = '.$id_menu
+               ));
+               $ok = menus_supprimer_menu($id_menu);
+               if (!$ok) $retours['message_erreur'] = _T('menus:erreur_mise_a_jour');
+               if ($ok and !$sous_menu) $retours['redirect'] = generer_url_ecrire('menus_tous');
+       }
+
+       $retours['editable'] = true;
+
+       return $retours;
+}
+
+?>
diff --git a/www/plugins/menus_1/formulaires/inc-menus_entrees.html b/www/plugins/menus_1/formulaires/inc-menus_entrees.html
new file mode 100644 (file)
index 0000000..c1a4008
--- /dev/null
@@ -0,0 +1,83 @@
+#SET{rang_suivant,1}\r
+<ul id="menu-#ENV{id_menu}" class="menus_entrees">\r
+       <BOUCLE_entrees(MENUS_ENTREES){id_menu}{par rang}>\r
+       <li class="entree"[ style="background-repeat:no-repeat;background-position:5px 10px;background-image:url((#ENV{types_entrees}|table_valeur{#TYPE_ENTREE}|table_valeur{icone}|image_reduire{24}|extraire_attribut{src}))"]>\r
+               <BOUCLE_test_modifier(CONDITION){si #ENV{erreurs}|table_valeur{id_menus_entree}|=={#ID_MENUS_ENTREE}|non}>\r
+               <div class="ligne">\r
+                       <div class="description arial2">\r
+                               #SET{supprimer_seulement,non}\r
+                               [(#CHEMIN{menus/#TYPE_ENTREE.html}|oui)\r
+                               #MENUS_AFFICHER_ENTREE{appel_formulaire}]\r
+                               [(#CHEMIN{menus/#TYPE_ENTREE.html}|non)\r
+                               #SET{supprimer_seulement,oui}\r
+                               #INCLURE{fond=formulaires/inc-menus_entrees_inexistantes,appel_formulaire=oui,titre=#TYPE_ENTREE}\r
+                               ]\r
+                       </div>\r
+                       <div class="actions">\r
+                               [(#REM) S'il y a déjà un sous-menu on ne l'affiche pas ?)]\r
+                               <BOUCLE_sous_menu_test(MENUS){id_menus_entree}>\r
+                               [(#REM) Rien]\r
+                               </BOUCLE_sous_menu_test>\r
+                               [(#GET{supprimer_seulement}|=={non}|oui)\r
+                               [(#ENV{types_entrees}|table_valeur{#TYPE_ENTREE}|table_valeur{refuser_sous_menu}|non)\r
+                               <button name="demander_sous_menu" value="#ID_MENUS_ENTREE" title="<:menus:formulaire_ajouter_sous_menu:>">\r
+                                       [<img height="24" width="24" src="(#CHEMIN{images/menus-24.png})" alt="" />]\r
+                               </button>\r
+                               ]]\r
+                               <//B_sous_menu_test>\r
+                               [(#GET{supprimer_seulement}|=={non}|oui)\r
+                               <button name="modifier_entree" value="#ID_MENUS_ENTREE" title="<:menus:formulaire_modifier_entree:>">\r
+                                       [<img height="24" width="24" src="(#CHEMIN{images/menus_action_modifier.png})" alt="" />]\r
+                               </button>]\r
+                               <button name="supprimer_entree" value="#ID_MENUS_ENTREE" title="<:menus:formulaire_supprimer_entree:>"\r
+                               onclick="return confirm('<:menus:confirmer_supprimer_entree:>')">\r
+                                       [<img height="24" width="24" src="(#CHEMIN{images/menus_action_supprimer.png})" alt="" />]\r
+                               </button>\r
+                               [(#GET{supprimer_seulement}|=={non}|oui)\r
+                               <button name="deplacer_entree" value="#ID_MENUS_ENTREE-bas" title="<:menus:formulaire_deplacer_bas:>">\r
+                                       [<img height="24" width="24" src="(#CHEMIN{images/menus_action_bas.png})" alt="" />]\r
+                               </button>]\r
+                               [(#GET{supprimer_seulement}|=={non}|oui)\r
+                               <button name="deplacer_entree" value="#ID_MENUS_ENTREE-haut" title="<:menus:formulaire_deplacer_haut:>">\r
+                                       [<img height="24" width="24" src="(#CHEMIN{images/menus_action_haut.png})" alt="" />]\r
+                               </button>]\r
+                       </div>\r
+                       <div class="nettoyeur"></div>\r
+               </div>\r
+               </BOUCLE_test_modifier>\r
+               #INCLURE{fond=formulaires/inc-nouvelle_entree-2, env, id_menus_entree=#ID_MENUS_ENTREE}\r
+               <//B_test_modifier>\r
+\r
+               [(#REM) Est-ce qu'il y a un sous-menu ?)]\r
+               <BOUCLE_sous_menu(MENUS){id_menus_entree}>\r
+                       #INCLURE{fond=formulaires/inc-menus_entrees, env, id_menu, sous_menu=oui}\r
+               </BOUCLE_sous_menu>\r
+       </li>\r
+       #SET{rang_suivant,(#RANG|plus{1})}\r
+       </BOUCLE_entrees>\r
+       <li class="editer_entree fieldset">\r
+               #SET{id_menu_nouvelle_entree, (#ENV{erreurs}|table_valeur{id_menu_nouvelle_entree})}\r
+               #SET{type_entree, (#ENV{erreurs}|table_valeur{type_entree})}\r
+\r
+               <BOUCLE_pas_demande_entree(CONDITION){si #GET{id_menu_nouvelle_entree}|=={#ENV{id_menu}}|non}>\r
+                       <div class="boutons">\r
+                       [(#ENV{sous_menu}|non)<span class="image_loading"></span>]\r
+                       [<button type="submit" class="submit link" name="supprimer_menu" value="#ENV{id_menu}">\r
+                               [<img src="(#CHEMIN{images/menus_action_supprimer.png})" alt="" />]\r
+                               (#ENV{sous_menu}|?{<:menus:formulaire_supprimer_sous_menu:>,''})\r
+                       </button>]\r
+                       <button type="submit" class="submit" name="demander_nouvelle_entree" value="#ENV{id_menu}">\r
+                               [<img src="(#CHEMIN{images/menus_action_ajouter.png})" alt="" />]\r
+                               <:menus:formulaire_ajouter_entree:>\r
+                       </button>\r
+                       </div>\r
+               </BOUCLE_pas_demande_entree>\r
+                       [(#GET{type_entree}|non)\r
+                               #INCLURE{fond=formulaires/inc-nouvelle_entree-1, env, id_menu_nouvelle_entree=#GET{id_menu_nouvelle_entree}}\r
+                       ]\r
+                       [(#GET{type_entree}|oui)\r
+                               #INCLURE{fond=formulaires/inc-nouvelle_entree-2, env, id_menu_nouvelle_entree=#GET{id_menu_nouvelle_entree}, rang_suivant=#GET{rang_suivant}}\r
+                       ]\r
+               <//B_pas_demande_entree>\r
+       </li>\r
+</ul>\r
diff --git a/www/plugins/menus_1/formulaires/inc-menus_entrees_inexistantes.html b/www/plugins/menus_1/formulaires/inc-menus_entrees_inexistantes.html
new file mode 100644 (file)
index 0000000..a3aeac3
--- /dev/null
@@ -0,0 +1,11 @@
+[(#SET{titre, <:menus:formulaire_supprimer_entree:>})]
+[(#ENV{titre}|oui)
+       #SET{titre, #ENV*{titre}|typo}
+]
+
+[(#ENV{appel_formulaire}|oui)
+       <div class="erreur_message">
+       <div class="titre">#GET{titre}</div>
+       <div class="infos"><:menus:erreur_type_menu_inexistant:></div>
+       </div>
+]
diff --git a/www/plugins/menus_1/formulaires/inc-nouvelle_entree-1.html b/www/plugins/menus_1/formulaires/inc-nouvelle_entree-1.html
new file mode 100644 (file)
index 0000000..5e47a9f
--- /dev/null
@@ -0,0 +1,23 @@
+
+<ul>
+       <li class="editer pleine_largeur editer_type[(#ENV**{erreurs}|table_valeur{type}|oui)erreur]">
+               <label><:menus:entree_choisir:></label>
+               [<span class='erreur_message'>(#ENV**{erreurs}|table_valeur{type})</span>]
+               <BOUCLE_types_entrees(POUR){tableau #ENV{erreurs}|table_valeur{entrees}}{par rang}>
+               <div class="choix menu_#CLE" id="choix_menu_#CLE" style="padding:3px;border-bottom:1px solid #eee;">
+                       [(#VALEUR|table_valeur{icone}|image_reduire{24})]
+                       <input type="radio" class="radio" name="type_entree" id="#CLE" value="#CLE" style="vertical-align:top;" />
+                       <label for="#CLE">[(#VALEUR|table_valeur{nom})]</label>
+               </div>
+               </BOUCLE_types_entrees>
+               <span class='erreur_message'><:menus:erreur_aucun_type:></span>
+               <//B_types_entrees>
+       </li>
+</ul>
+
+<p class='boutons'>
+       <span class='image_loading'></span>
+       <input type="hidden" name="demander_nouvelle_entree" value="#ENV{id_menu_nouvelle_entree}" />
+       <input type="submit" class="submit link" name="demander_nouvelle_entree" value="<:icone_retour:>" />
+       <input type="submit" class="submit" name="suivant" value="<:bouton_suivant:>" />
+</p>
diff --git a/www/plugins/menus_1/formulaires/inc-nouvelle_entree-2.html b/www/plugins/menus_1/formulaires/inc-nouvelle_entree-2.html
new file mode 100644 (file)
index 0000000..5c20913
--- /dev/null
@@ -0,0 +1,38 @@
+
+#SET{type_entree, (#ENV{erreurs}|table_valeur{type_entree})}
+#SET{infos, (#ENV{erreurs}|table_valeur{infos_#GET{type_entree}})}
+<fieldset>
+<legend class="legend">
+       [(#ENV{id_menus_entree}|non)
+               [(#GET{infos}|table_valeur{icone}|image_reduire{24})]
+       ]
+       [<span style="vertical-align:middle;">(#GET{infos}|table_valeur{nom})</span>]
+</legend>
+<div class="explication">[(#GET{infos}|table_valeur{description})]</div>
+<B_parametres>
+<ul>
+       <BOUCLE_parametres(POUR){tableau #GET{infos}|table_valeur{parametres}}>
+       #SET{erreurs,(#ENV**{erreurs}|table_valeur{parametres}|table_valeur{#CLE})}
+       <li class="editer editer_texte[ (#GET{erreurs}|oui)erreur]">
+               <label for="#CLE">[(#VALEUR|table_valeur{label})] [(#VALEUR|table_valeur{obligatoire}|non)&#91;<:menus:formulaire_facultatif:>&#93;]</label>
+               [<span class='erreur_message'>(#GET{erreurs})</span>]
+               <input type="text" class="text[ (#VALEUR|table_valeur{class})]" name="parametres[#CLE]" value="[(#ENV{parametres}|table_valeur{#CLE}|sinon{#ENV{erreurs}|table_valeur{#CLE}}|entites_html)]" />
+       </li>
+       </BOUCLE_parametres>
+</ul>
+</B_parametres>
+
+<p class='boutons'>
+       <span class='image_loading'></span>
+       [(#ENV{id_menu_nouvelle_entree}|oui)
+               <input type="hidden" name="id_menu_nouvelle_entree" value="#ENV{id_menu_nouvelle_entree}" />
+               <input type="hidden" name="rang" value="#ENV{rang_suivant}" />
+       ]
+       [(#ENV{id_menus_entree}|oui)
+               <input type="hidden" name="id_menus_entree" value="#ENV{id_menus_entree}" />
+       ]
+       <input type="hidden" name="type_entree" value="#GET{type_entree}" />
+       <input type="submit" class="submit link" value="<:bouton_annuler:>" />
+       <input type="submit" class="submit" name="enregistrer" value="<:bouton_enregistrer:>" />
+</p>
+</fieldset>
diff --git a/www/plugins/menus_1/images/export.png b/www/plugins/menus_1/images/export.png
new file mode 100644 (file)
index 0000000..22b6ae3
Binary files /dev/null and b/www/plugins/menus_1/images/export.png differ
diff --git a/www/plugins/menus_1/images/menus-16.png b/www/plugins/menus_1/images/menus-16.png
new file mode 100644 (file)
index 0000000..5ead8f7
Binary files /dev/null and b/www/plugins/menus_1/images/menus-16.png differ
diff --git a/www/plugins/menus_1/images/menus-24.png b/www/plugins/menus_1/images/menus-24.png
new file mode 100644 (file)
index 0000000..563d388
Binary files /dev/null and b/www/plugins/menus_1/images/menus-24.png differ
diff --git a/www/plugins/menus_1/images/menus-48.png b/www/plugins/menus_1/images/menus-48.png
new file mode 100644 (file)
index 0000000..a1bc9f9
Binary files /dev/null and b/www/plugins/menus_1/images/menus-48.png differ
diff --git a/www/plugins/menus_1/images/menus-nouveau-24.png b/www/plugins/menus_1/images/menus-nouveau-24.png
new file mode 100644 (file)
index 0000000..544f450
Binary files /dev/null and b/www/plugins/menus_1/images/menus-nouveau-24.png differ
diff --git a/www/plugins/menus_1/images/menus-nouveau-48.png b/www/plugins/menus_1/images/menus-nouveau-48.png
new file mode 100644 (file)
index 0000000..45cae0b
Binary files /dev/null and b/www/plugins/menus_1/images/menus-nouveau-48.png differ
diff --git a/www/plugins/menus_1/images/menus_accueil.png b/www/plugins/menus_1/images/menus_accueil.png
new file mode 100644 (file)
index 0000000..a2ecb16
Binary files /dev/null and b/www/plugins/menus_1/images/menus_accueil.png differ
diff --git a/www/plugins/menus_1/images/menus_action_ajouter.png b/www/plugins/menus_1/images/menus_action_ajouter.png
new file mode 100644 (file)
index 0000000..8aef295
Binary files /dev/null and b/www/plugins/menus_1/images/menus_action_ajouter.png differ
diff --git a/www/plugins/menus_1/images/menus_action_bas.png b/www/plugins/menus_1/images/menus_action_bas.png
new file mode 100644 (file)
index 0000000..d6df4f6
Binary files /dev/null and b/www/plugins/menus_1/images/menus_action_bas.png differ
diff --git a/www/plugins/menus_1/images/menus_action_haut.png b/www/plugins/menus_1/images/menus_action_haut.png
new file mode 100644 (file)
index 0000000..cff387d
Binary files /dev/null and b/www/plugins/menus_1/images/menus_action_haut.png differ
diff --git a/www/plugins/menus_1/images/menus_action_modifier.png b/www/plugins/menus_1/images/menus_action_modifier.png
new file mode 100644 (file)
index 0000000..a3bbd76
Binary files /dev/null and b/www/plugins/menus_1/images/menus_action_modifier.png differ
diff --git a/www/plugins/menus_1/images/menus_action_supprimer.png b/www/plugins/menus_1/images/menus_action_supprimer.png
new file mode 100644 (file)
index 0000000..cd92b1d
Binary files /dev/null and b/www/plugins/menus_1/images/menus_action_supprimer.png differ
diff --git a/www/plugins/menus_1/images/menus_articles_rubrique.png b/www/plugins/menus_1/images/menus_articles_rubrique.png
new file mode 100644 (file)
index 0000000..c131e9b
Binary files /dev/null and b/www/plugins/menus_1/images/menus_articles_rubrique.png differ
diff --git a/www/plugins/menus_1/images/menus_groupes_mots.png b/www/plugins/menus_1/images/menus_groupes_mots.png
new file mode 100644 (file)
index 0000000..f5388cc
Binary files /dev/null and b/www/plugins/menus_1/images/menus_groupes_mots.png differ
diff --git a/www/plugins/menus_1/images/menus_lien.png b/www/plugins/menus_1/images/menus_lien.png
new file mode 100755 (executable)
index 0000000..60d0d02
Binary files /dev/null and b/www/plugins/menus_1/images/menus_lien.png differ
diff --git a/www/plugins/menus_1/images/menus_logout.png b/www/plugins/menus_1/images/menus_logout.png
new file mode 100644 (file)
index 0000000..4ee9cff
Binary files /dev/null and b/www/plugins/menus_1/images/menus_logout.png differ
diff --git a/www/plugins/menus_1/images/menus_mapage.png b/www/plugins/menus_1/images/menus_mapage.png
new file mode 100644 (file)
index 0000000..5d836e6
Binary files /dev/null and b/www/plugins/menus_1/images/menus_mapage.png differ
diff --git a/www/plugins/menus_1/images/menus_mots.png b/www/plugins/menus_1/images/menus_mots.png
new file mode 100644 (file)
index 0000000..f7988df
Binary files /dev/null and b/www/plugins/menus_1/images/menus_mots.png differ
diff --git a/www/plugins/menus_1/images/menus_objet.png b/www/plugins/menus_1/images/menus_objet.png
new file mode 100644 (file)
index 0000000..8b1f432
Binary files /dev/null and b/www/plugins/menus_1/images/menus_objet.png differ
diff --git a/www/plugins/menus_1/images/menus_page_speciale.png b/www/plugins/menus_1/images/menus_page_speciale.png
new file mode 100644 (file)
index 0000000..74b109b
Binary files /dev/null and b/www/plugins/menus_1/images/menus_page_speciale.png differ
diff --git a/www/plugins/menus_1/images/menus_rubriques.png b/www/plugins/menus_1/images/menus_rubriques.png
new file mode 100644 (file)
index 0000000..3033e6e
Binary files /dev/null and b/www/plugins/menus_1/images/menus_rubriques.png differ
diff --git a/www/plugins/menus_1/images/menus_secteurlangue.png b/www/plugins/menus_1/images/menus_secteurlangue.png
new file mode 100644 (file)
index 0000000..90d1d85
Binary files /dev/null and b/www/plugins/menus_1/images/menus_secteurlangue.png differ
diff --git a/www/plugins/menus_1/images/menus_texte_libre.png b/www/plugins/menus_1/images/menus_texte_libre.png
new file mode 100644 (file)
index 0000000..59e60f7
Binary files /dev/null and b/www/plugins/menus_1/images/menus_texte_libre.png differ
diff --git a/www/plugins/menus_1/inc/menus.php b/www/plugins/menus_1/inc/menus.php
new file mode 100644 (file)
index 0000000..ac7e6ad
--- /dev/null
@@ -0,0 +1,184 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Lister les types d'entrée de menus disponibles dans les dossiers menus/
+ *
+ * @staticvar array $resultats
+ * @param bool $informer
+ * @return array
+ */
+function menus_lister_disponibles($informer=true){
+       static $resultats = null;
+       
+       $plugins_actifs = unserialize($GLOBALS['meta']['plugin']);
+
+       if (is_null($resultats[$informer])){
+               $resultats[$informer] = array();
+               // rechercher les skel du type truc.html
+               $match = ".+[.]html$";
+
+               // lister les entrées disponibles
+               $liste = find_all_in_path('menus/', $match);
+               if (count($liste)){
+                       foreach($liste as $squelette=>$chemin) {
+                               $type = preg_replace(',[.]html$,i', '', $squelette);
+                               $dossier = str_replace($squelette, '', $chemin);
+                               // On ne garde que les squelettes ayant un XML de config
+                               if (file_exists("$dossier$type.xml")
+                                       AND (
+                                               $entree = !$informer OR ($entree = menus_charger_infos($dossier.$type))
+                                       )){
+                                           //on ne garde que les menus repondants aux necessites
+                                       $necessite = true;
+                                           if (! empty($entree['necessites']['plugin'])) {
+                                               /* la globale $plugins liste tout en majuscule */
+                                               $entree['necessites']['plugin'] = array_map("strtoupper", $entree['necessites']['plugin']);
+                                               foreach($entree['necessites']['plugin'] as $plugin) {
+                                                   if ( ! array_key_exists($plugin,$plugins_actifs) )
+                                                       $necessite = false;
+                                               }
+                                           }
+                                           if ($necessite)
+                            $resultats[$informer][$type] = $entree;
+                               }
+                       }
+               }
+               $resultats[$informer] = pipeline('menus_lister_disponibles',array(
+                       'args' => array(),
+                       'data' => $resultats[$informer]
+                       )
+               );
+       }
+       return $resultats[$informer];
+}
+
+/**
+ * Decrire un type de menu
+ *
+ * @staticvar array $infos
+ * @param string $type
+ * @return array
+ */
+function menus_informer($type){
+       static $infos = array();
+       if (!isset($infos[$type])){
+               $fichier = find_in_path("menus/$type.html");
+               $infos[$type] = menus_charger_infos($fichier);
+       }
+       return $infos[$type];
+}
+
+/**
+ * Charger les informations contenues dans le xml d'une entrée de menu
+ *
+ * @param string $type
+ * @param string $info
+ * @return array
+ */
+function menus_charger_infos($type, $info=""){
+               // on peut appeler avec le nom du squelette
+               $fichier = preg_replace(',[.]html$,i','',$type).".xml";
+               include_spip('inc/xml');
+               include_spip('inc/texte');
+               $entree = array();
+               if ($xml = spip_xml_load($fichier, false)){
+                       if (count($xml['entree'])){
+                               $xml = reset($xml['entree']);
+                               $entree['nom'] = _T_ou_typo(spip_xml_aplatit($xml['nom']));
+                               $entree['rang'] = intval(trim(spip_xml_aplatit($xml['rang'])));
+                               $entree['rang'] = ($entree['rang'] ? $entree['rang'] : 1000);
+                               $entree['description'] = isset($xml['description']) ? _T_ou_typo(spip_xml_aplatit($xml['description'])) : '';
+                               $entree['icone'] = isset($xml['icone']) ? find_in_path(reset($xml['icone'])) : '';
+                               $entree['refuser_sous_menu'] = isset($xml['refuser_sous_menu']);
+                               // Décomposition des paramètres
+                               $entree['parametres'] = array();
+                               if (spip_xml_match_nodes(',^parametre,', $xml, $parametres)){
+                                       foreach (array_keys($parametres) as $parametre){
+                                               list($balise, $attributs) = spip_xml_decompose_tag($parametre);
+                                               $entree['parametres'][$attributs['nom']] = array(
+                                                       'label' => (isset($attributs['label']) && $attributs['label']) ? _T($attributs['label']) : $attributs['nom'],
+                                                       'obligatoire' => (isset($attributs['obligatoire']) && $attributs['obligatoire'] == 'oui') ? true : false,
+                                                       'class' => (isset($attributs['class']) && $attributs['class']) ? $attributs['class'] : ''
+                                               );
+                                       }
+                               }
+                               //Décomposition des necessites
+                               if (spip_xml_match_nodes(',^necessite,', $xml, $necessites)){
+                               $entree['necessites']['plugin'] = array();
+                                       foreach (array_keys($necessites) as $necessite){
+                                               list($balise, $attributs) = spip_xml_decompose_tag($necessite);
+                                               array_push($entree['necessites'][$attributs['type']] , $attributs['nom']);
+                                       }
+                               }
+                               
+                       }
+               }
+               if (!$info)
+                       return $entree;
+               else 
+                       return isset($entree[$info]) ? $entree[$info] : "";
+}
+
+// Suprrimer une entrée (et les éventuels sous-menus en cascade)
+function menus_supprimer_entree($id_menus_entree){
+       include_spip('base/abstract_sql');
+       $id_menus_entree = intval($id_menus_entree);
+       
+       // On regarde d'abord s'il y a un sous-menu
+       $id_menu = intval(sql_getfetsel(
+               'id_menu',
+               'spip_menus',
+               'id_menus_entree = '.$id_menus_entree
+       ));
+       
+       // Dans ce cas on le supprime d'abord
+       $ok = true;
+       if ($id_menu)
+               $ok = menus_supprimer_menu($id_menu);
+       
+       // Si c'est bon, on peut alors supprimer l'entrée
+       if ($ok)
+               $ok = sql_delete(
+                       'spip_menus_entrees',
+                       'id_menus_entree = '.$id_menus_entree
+               );
+       
+       return $ok;
+}
+
+// Supprimer un menu (et donc toutes ses entrées aussi)
+function menus_supprimer_menu($id_menu){
+       include_spip('base/abstract_sql');
+       $id_menu = intval($id_menu);
+       
+       // On récupère toutes les entrées
+       $entrees = sql_allfetsel(
+               'id_menus_entree',
+               'spip_menus_entrees',
+               'id_menu = '.$id_menu
+       );
+       if (is_array($entrees))
+               $entrees = array_map('reset', $entrees);
+       
+       // On les supprime
+       $ok = true;
+       if (is_array($entrees))
+               foreach ($entrees as $id_menus_entree){
+                       if ($ok)
+                               $ok = menus_supprimer_entree($id_menus_entree);
+               }
+       
+       // Si tout s'est bien passé on peut enfin supprimer le menu
+       if ($ok)
+               $ok = sql_delete(
+                       'spip_menus',
+                       'id_menu = '.$id_menu
+               );
+       
+       return $ok;
+}
+
+?>
diff --git a/www/plugins/menus_1/inc/menus_autoriser.php b/www/plugins/menus_1/inc/menus_autoriser.php
new file mode 100644 (file)
index 0000000..93afbdd
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function menus_autoriser(){}
+
+function autoriser_menu_modifier_dist($faire, $type, $id, $qui, $opt) {
+       if ($qui['statut'] == '0minirezo' and !$qui['restreint'])
+               return true;
+       else
+               return false;
+}
+
+function autoriser_menus_tous_dist($faire, $type, $id, $qui, $opt) {
+       return autoriser('modifier', 'menu', $id, $qui, $opt);
+}
+
+?>
diff --git a/www/plugins/menus_1/inclure/barre-nav.html b/www/plugins/menus_1/inclure/barre-nav.html
new file mode 100644 (file)
index 0000000..b1d83ab
--- /dev/null
@@ -0,0 +1,7 @@
+[(#REM) 
+       
+       ZPIP 1.x
+       
+]<div class="menu-conteneur navbar-inner">
+#INCLURE{fond=inclure/menu, env, identifiant=barrenav}
+</div>
diff --git a/www/plugins/menus_1/inclure/menu.html b/www/plugins/menus_1/inclure/menu.html
new file mode 100644 (file)
index 0000000..47c755f
--- /dev/null
@@ -0,0 +1,21 @@
+
+<BOUCLE_menu(MENUS){id_menu?}{identifiant?}>
+       
+       <B_entrees>
+       <ul class="menu-liste menu-items nav[ (#CHAMP_SQL{css})]">
+               <BOUCLE_entrees(MENUS_ENTREES){id_menu}{par rang}>
+               #MENUS_AFFICHER_ENTREE
+                       <BOUCLE_sous_menu(MENUS){id_menus_entree}>
+                               #INCLURE{fond=inclure/menu, env, id_menu, identifiant}
+                       </BOUCLE_sous_menu>
+               [(#REM)
+                       On ferme le li si le type d'entrée accepte des sous-menus
+                       et si on a bien quelque chose dans le li (cas des menus sur Balise SESSION)
+               ][(#TYPE_ENTREE|menus_type_refuser_sous_menu|non)
+                       [(#MENUS_AFFICHER_ENTREE|trim|oui)</li>]
+               ]
+               </BOUCLE_entrees>
+       </ul>
+       </B_entrees>
+       
+</BOUCLE_menu>
diff --git a/www/plugins/menus_1/inclure/nav.html b/www/plugins/menus_1/inclure/nav.html
new file mode 100644 (file)
index 0000000..6d39144
--- /dev/null
@@ -0,0 +1,7 @@
+[(#REM) 
+       
+       ZPIP 2.x
+       
+]<div class="menu-conteneur navbar-inner">
+#INCLURE{fond=inclure/menu, env, identifiant=barrenav}
+</div>
diff --git a/www/plugins/menus_1/lang/menus.xml b/www/plugins/menus_1/lang/menus.xml
new file mode 100644 (file)
index 0000000..a497978
--- /dev/null
@@ -0,0 +1,28 @@
+<traduction module="menus" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/menus/trunk/lang/" reference="fr">
+       <langue code="ar" url="http://trad.spip.net/tradlang_module/menus?lang_cible=ar">
+               <traducteur nom="George" lien="http://trad.spip.net/auteur/جورج-قندلفت" />
+       </langue>
+       <langue code="ca" />
+       <langue code="de" url="http://trad.spip.net/tradlang_module/menus?lang_cible=de">
+               <traducteur nom="klaus++" lien="http://trad.spip.net/auteur/klaus" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/menus?lang_cible=en">
+               <traducteur nom="kent1" lien="" />
+               <traducteur nom="Mark" lien="http://trad.spip.net/auteur/mark" />
+               <traducteur nom="RastaPopoulos" lien="" />
+               <traducteur nom="Suske" lien="http://trad.spip.net/auteur/suske" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/menus?lang_cible=es">
+               <traducteur nom="dani" lien="http://trad.spip.net/auteur/dani" />
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+               <traducteur nom="tin" lien="http://trad.spip.net/auteur/tin" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/menus?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="it" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/menus?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/menus_1/lang/menus_ar.php b/www/plugins/menus_1/lang/menus_ar.php
new file mode 100644 (file)
index 0000000..c278df2
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=ar
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'هل تريد فعلاً حذف هذا البند؟',
+
+       // D
+       'description_menu_accueil' => 'رابط الى الصفحة الأساسية في الموقع.',
+       'description_menu_articles_rubrique' => 'عرض لائحة المقالات في قسم.',
+       'description_menu_deconnecter' => 'اذا كان هناك زائر متصل، يضيف بنداً يعرض عليه الخروج.',
+       'description_menu_espace_prive' => 'Lien permettant de se connecter au site si on ne l\'est pas déjà, puis d\'aller dans l\'espace privé si l\'on y est autorisé.', # NEW
+       'description_menu_groupes_mots' => 'Affiche automatiquement un menu listant les mots du groupe et les articles liés. Par défaut, affiche la liste des groupes de mots et les mots liés. Si un squelette groupes_mots.html existe, le lien vers le groupe est utilisé.', # NEW
+       'description_menu_lien' => 'Ajoute un lien arbitraire, en interne (URL relative) ou externe (http://...).', # NEW
+       'description_menu_mapage' => 'Si le visiteur est connecté, ajoute un lien vers sa page auteur.', # NEW
+       'description_menu_mots' => 'Affiche automatiquement un menu listant les articles liés au mot clé.', # NEW
+       'description_menu_objet' => 'Crée un lien vers un objet de SPIP : article, rubrique ou autre. Par défaut, l\'entrée aura le titre de l\'objet.', # NEW
+       'description_menu_page_speciale' => 'Ajoute un lien vers un squelette page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ces pages sont souvent fournies par des plugins.', # NEW
+       'description_menu_page_speciale_zajax' => 'Ajoute un lien vers un bloc d\'une page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ceci nécéssite une squelette de type Z et le plugin <a href="http://www.spip-contrib.net/MediaBox">médiabox</a>.', # NEW
+       'description_menu_rubriques_articles' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques et les articles sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement). Les articles sont placés systématiquement après les rubriques.', # NEW
+       'description_menu_rubriques_completes' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).', # NEW
+       'description_menu_secteurlangue' => 'Cette entrée est spécifique aux sites utilisant un secteur par langue. Elle affiche automatiquement un menu listant les rubriques du secteur correspondant à la langue de la page et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).', # NEW
+       'description_menu_texte_libre' => 'Simplement le texte que vous souhaitez, ou un code de langue SPIP (<:...:>)', # NEW
+
+       // E
+       'editer_menus_editer' => 'تعديل هذه القائمة',
+       'editer_menus_explication' => 'إنشاء قوائم الموقع وإعدادها.',
+       'editer_menus_exporter' => 'نقل هذه القائمة',
+       'editer_menus_nouveau' => 'إنشاء قائمة جديدة',
+       'editer_menus_titre' => 'قوائم الموقع',
+       'entree_afficher_articles' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_afficher_item_suite' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_articles_max' => 'Si oui, afficher les articles seulement si la rubrique contient au maximum xx articles ? (mettre le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_articles_max_affiches' => 'Si oui, limiter le nombre d\'articles listés à xx maximum (suivis d\'un item "... Tous les articles" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_aucun' => 'بدون',
+       'entree_bloc' => 'كتلة Zpip',
+       'entree_choisir' => 'اختر نوع البند الذي تريد إضافته:',
+       'entree_classe_parent' => 'Classe des liens des éléments parents. Cette classe sera rajoutée aux li>a ayant une suite ul/li. Par exemple, si vous saisissez "daddy", cela vous permet d\'utiliser le plugin menu deroulant 2 pour la mise en forme du menu.', # NEW
+       'entree_connexion_objet' => 'Obliger à être connecté (mettre "session") ou déconnecté (mettre "nosession") pour voir l\'objet', # NEW
+       'entree_contenu' => 'المحتوى',
+       'entree_css' => 'Classes CSS de l\'entrée (du conteneur)', # NEW
+       'entree_css_lien' => 'Classes CSS du lien', # NEW
+       'entree_id_groupe' => 'رقم مجموعة المفاتيح',
+       'entree_id_mot' => 'رقم المفتاح',
+       'entree_id_objet' => 'رقم',
+       'entree_id_rubrique' => 'رقم القسم الحاوي',
+       'entree_id_rubrique_ou_courante' => 'Numéro de la rubrique parente ou "courante" si la rubrique parente est la rubrique courante du contexte', # NEW
+       'entree_id_rubriques_exclues' => 'Numéros des rubriques à exclure, séparés par des virgules', # NEW
+       'entree_id_secteur_exclus' => 'Numéros des secteurs à exclure, séparés par des virgules', # NEW
+       'entree_infini' => 'الى ما لا نهاية',
+       'entree_mapage' => 'صفحتي الشخصية',
+       'entree_masquer_articles_uniques' => 'Si oui et si une rubrique contient un seul article, le masquer ? (mettre "oui" pour cela)', # NEW
+       'entree_niveau' => 'مستوى القوائم الفرعية',
+       'entree_nombre_articles' => 'العدد الأقصى للمقالات (صفر افتراضياً)',
+       'entree_page' => 'اسم الصفحة',
+       'entree_parametres' => 'لائحة المتغيرات',
+       'entree_rubriques_max_affichees' => 'Si oui, limiter le nombre de rubriques listés à xx maximum (suivis d\'un item "... Toutes les rubriques" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum de rubriques, laissez vide pour afficher toutes les rubriques)', # NEW
+       'entree_sousrub_cond' => 'N\'afficher que les sous-rubriques de la rubrique en cours (mettre "oui", sinon laisser vide)', # NEW
+       'entree_suivant_connexion' => 'Restreindre cette entrée suivant la connexion (mettre "connecte" pour afficher seulement si le visiteur est connecté, "deconnecte" pour le cas contraire, ou laisser vide pour toujours afficher)', # NEW
+       'entree_suivant_connexion_connecte' => 'اذا متصل فقط',
+       'entree_suivant_connexion_deconnecte' => 'اذا غير متصل فقط',
+       'entree_sur_n_articles' => '@n@ مقال معروض',
+       'entree_sur_n_mots' => '@n@ مفتاح معروض',
+       'entree_sur_n_niveaux' => 'على @n@ مستوى',
+       'entree_titre' => 'العنوان',
+       'entree_titre_connecter' => 'العنوان للوصول الى استمارة التعريف',
+       'entree_titre_prive' => 'العنوان للدخول الى المجال الخاص',
+       'entree_traduction_articles_rubriques' => 'Dans la mesure du possible, afficher les articles de la rubrique dans la langue du contexte (mettre "trad" pour cela)', # NEW
+       'entree_traduction_objet' => 'Dans le cas d\'un article, choisir la traduction en fonction du contexte (mettre "trad" pour cela)', # NEW
+       'entree_tri_alpha' => 'Critère de tri des rubriques (alphabétique). Si vous saisissez "date", le critère ajouté sera {par date} et les rubriques seront triées par date', # NEW
+       'entree_tri_alpha_articles' => 'Critère de tri des articles (alphabétique). Si vous saisissez "date", le critère ajouté sera {par date} et les articles seront triés par date', # NEW
+       'entree_tri_alpha_articles_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_alpha_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num' => 'Critère de tri des rubriques (numérique). Si vous saisissez "titre", le critère ajouté sera {par num titre} et les rubriques seront triées par numéro de titre', # NEW
+       'entree_tri_num_articles' => 'Critère de tri des articles (numérique). Si vous saisissez "titre", le critère ajouté sera {par num titre} et les articles seront triés par numéro de titre', # NEW
+       'entree_tri_num_articles_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_type_objet' => 'نوع العنصر',
+       'entree_url' => 'العنوان',
+       'entree_url_public' => 'Adresse de retour après la connexion', # NEW
+       'erreur_aucun_type' => 'لم يتم العثور على اي نوع بنود.',
+       'erreur_autorisation' => 'غير مسموح لك تعديل القوائم.',
+       'erreur_identifiant_deja' => 'Cet identifiant est déjà utilisé par un menu.', # NEW
+       'erreur_identifiant_forme' => 'L\'identifiant ne doit contenir que des lettres, des chiffres ou le caractère souligné.', # NEW
+       'erreur_menu_inexistant' => 'لا وجود للقائمة رقم @id@ المطلوبة.',
+       'erreur_mise_a_jour' => 'Une erreur s\'est produite pendant la mise à jour de la base de donnée.', # NEW
+       'erreur_parametres' => 'Il y a une erreur dans les paramètres de la page', # NEW
+       'erreur_type_menu' => 'يجب اختيار نوع قوائم',
+       'erreur_type_menu_inexistant' => 'Ce type de menu n\'est pas/plus disponible', # NEW
+
+       // F
+       'formulaire_ajouter_entree' => 'إضافة بند',
+       'formulaire_ajouter_sous_menu' => 'إنشاء قائمة فرعية',
+       'formulaire_css' => 'Classes CSS', # NEW
+       'formulaire_css_explication' => 'Vous pouvez ajouter au menu d\'éventuelles classes CSS supplémentaires.', # NEW
+       'formulaire_deplacer_bas' => 'نقل الى الأسفل',
+       'formulaire_deplacer_haut' => 'نقل الى الأعلى',
+       'formulaire_facultatif' => 'اختياري',
+       'formulaire_identifiant' => 'المعرف',
+       'formulaire_identifiant_explication' => 'Donnez un mot-clé unique qui vous permettra d\'appeler votre menu facilement.', # NEW
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Choisissez quel(s) menu(s) vous souhaitez importer.', # NEW
+       'formulaire_ieconfig_importer' => 'جلب',
+       'formulaire_ieconfig_menu_meme_identifiant' => 'ATTENTION : un menu avec le même identifiant existe déjà sur votre votre site !', # NEW
+       'formulaire_ieconfig_menus_a_exporter' => 'قوائم للنقل:',
+       'formulaire_ieconfig_ne_pas_importer' => 'عدم الجلب',
+       'formulaire_ieconfig_remplacer' => 'Remplacer le menu actuel par le menu importé', # NEW
+       'formulaire_ieconfig_renommer' => 'إعادة تسمية هذه القائمة قبل جلبها',
+       'formulaire_importer' => 'جلب قائمة',
+       'formulaire_importer_explication' => 'Si vous avez exporté un menu dans un fichier, vous pouvez l\'importer maintenant.', # NEW
+       'formulaire_modifier_entree' => 'تعديل هذا البند',
+       'formulaire_modifier_menu' => 'تعديل القائمة',
+       'formulaire_nouveau' => 'قائمة جديدة',
+       'formulaire_partie_construction' => 'بناء قائمة',
+       'formulaire_partie_identification' => 'تعريف القائمة',
+       'formulaire_supprimer_entree' => 'حذف هذا البند',
+       'formulaire_supprimer_menu' => 'حذف القائمة',
+       'formulaire_supprimer_sous_menu' => 'حذف هذه القائمة الفرعية',
+       'formulaire_titre' => 'العنوان',
+
+       // I
+       'info_afficher_articles' => 'Les articles seront inclus dans le menu.', # NEW
+       'info_articles_max' => 'Seulement si la rubrique contient au plus @max@ articles', # NEW
+       'info_articles_max_affiches' => 'Affichage limité à @max@ articles', # NEW
+       'info_classe_parent' => 'Classe des éléments parents : ', # NEW
+       'info_connexion_obligatoire' => 'Connexion obligatoire', # NEW
+       'info_deconnexion_obligatoire' => 'Uniquement déconnecté', # NEW
+       'info_masquer_articles_uniques' => 'Articles uniques masqués', # NEW
+       'info_numero_menu' => 'قائمة رقم:',
+       'info_page_speciale' => 'Lien vers la page « @page@ »', # NEW
+       'info_page_speciale_zajax' => 'Modalbox de la page « @page@ » pour le bloc « @bloc@ &#187', # NEW
+       'info_rubrique_courante' => 'القسم الحالي',
+       'info_rubriques_exclues' => ' / sauf rubrique(s) @id_rubriques@', # NEW
+       'info_rubriques_max_affichees' => 'Affichage limité à @max@ rubriques', # NEW
+       'info_secteur_exclus' => ' / sauf secteur(s) @id_secteur@', # NEW
+       'info_sousrub_cond' => 'Seules les sous-rubriques de la rubriques en cours sont affichées.', # NEW
+       'info_tous_groupes_mots' => 'Tous les groupes de mots', # NEW
+       'info_traduction_recuperee' => 'Le contexte décidera de la traduction choisie', # NEW
+       'info_tri' => 'فرز الأقسام:',
+       'info_tri_alpha' => '(أبجدي)',
+       'info_tri_articles' => 'فرز المقالات:',
+       'info_tri_num' => '(رقمي)',
+
+       // N
+       'noisette_description' => 'Insère un menu défini avec le plugin Menus.', # NEW
+       'noisette_label_afficher_titre_menu' => 'عرض عنوان القائمة؟',
+       'noisette_label_identifiant' => 'Menu à afficher :', # NEW
+       'noisette_nom_noisette' => 'القائمة',
+       'nom_menu_accueil' => 'Accueil', # NEW
+       'nom_menu_articles_rubrique' => 'مقالات قسم',
+       'nom_menu_deconnecter' => 'خروج',
+       'nom_menu_espace_prive' => 'Se connecter / lien vers espace privé', # NEW
+       'nom_menu_groupes_mots' => 'Mots-clés et Articles d\'un Groupes de mots', # NEW
+       'nom_menu_lien' => 'رابط اعتباطي',
+       'nom_menu_mapage' => 'صفحتي',
+       'nom_menu_mots' => 'مقالات مفتاح',
+       'nom_menu_objet' => 'مقال، قسم او أحد عناصر SPIP الأخرى ',
+       'nom_menu_page_speciale' => 'رابط الى صفحة نموذجية',
+       'nom_menu_page_speciale_zajax' => 'Un bloc d\'une page Zpip', # NEW
+       'nom_menu_rubriques_completes' => 'Liste ou arborescence de rubriques et d\'articles (avec beaucoup d\'options)', # NEW
+       'nom_menu_rubriques_evenements' => 'Événements de rubriques', # NEW
+       'nom_menu_secteurlangue' => 'أقسام اللغات',
+       'nom_menu_texte_libre' => 'نص حرّ',
+
+       // T
+       'tous_les_articles' => 'كل المقالات',
+       'toutes_les_rubriques' => 'كل الأقسام'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_ca.php b/www/plugins/menus_1/lang/menus_ca.php
new file mode 100644 (file)
index 0000000..53f4403
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=ca
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'Voulez-vous vraiment supprimer cette entrée ?', # NEW
+
+       // D
+       'description_menu_accueil' => 'Enllaç cap a la pàgina d\'inici del lloc.',
+       'description_menu_articles_rubrique' => 'Mostra la llista d\'articles d\'una secció.',
+       'description_menu_deconnecter' => 'Si el visitant està connectat, afegeix una entrada proposant-li la desconnexió.',
+       'description_menu_espace_prive' => 'Enllaç que permet connectar-se al lloc, si encara no ho estem, i després anar a l\'espai privat sempre i quan estiguem autoritzats a fer-ho.',
+       'description_menu_groupes_mots' => 'Mostra automàticament un menú que llista les paraules del grup i els articles lligats. Per defecte, mostra la llista dels grups de paraules i les paraules lligades. Si un esquelet grups_paraules.html existeix, s\'utilitzarà l\'enllaç cap al grup.',
+       'description_menu_lien' => 'Afegeix un enllaç arbitrari, intern (URL relativa) o extern (http://...).',
+       'description_menu_mapage' => 'Si el visitant està connectat, afegeix un enllaç cap a la pàgina de l\'autor.',
+       'description_menu_mots' => 'Mostra automàticament un menú que llista els articles lligats a la paraula clau.',
+       'description_menu_objet' => 'Crea un enllaç cap a un objecte d\'SPIP: article, secció o un altre. Per defecte, l\'entrada tindrà el títol de l\'objecte.',
+       'description_menu_page_speciale' => 'Afegeix un enllaç cap a un esquelet accessible per un URL del tipus <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Aquestes pàgines sovint són subministrades per connectors.',
+       'description_menu_page_speciale_zajax' => 'Ajoute un lien vers un bloc d\'une page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ceci nécéssite une squelette de type Z et le plugin <a href="http://www.spip-contrib.net/MediaBox">médiabox</a>.', # NEW
+       'description_menu_rubriques_articles' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques et les articles sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement). Les articles sont placés systématiquement après les rubriques.', # NEW
+       'description_menu_rubriques_completes' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).', # NEW
+       'description_menu_secteurlangue' => 'Aquesta entrada és específica pels llocs que utilitzen un sector per llengua. Mostra automàticament un menú que llista les seccions del sector corresponent a la llengua de la pàgina i, si es vol, les subseccions a diferents nivells. Per defecte, mostra totes les seccions des de l\'arrel, ordenades per títol (numèricament i després alfabèticament).',
+       'description_menu_texte_libre' => 'Simplement le texte que vous souhaitez, ou un code de langue SPIP (<:...:>)', # NEW
+
+       // E
+       'editer_menus_editer' => 'Modificar aquest menú',
+       'editer_menus_explication' => 'Creeu i configureu els menús del vostre lloc.',
+       'editer_menus_exporter' => 'Exportar aquest menú',
+       'editer_menus_nouveau' => 'Creeu un nou menú',
+       'editer_menus_titre' => 'Menús del lloc',
+       'entree_afficher_articles' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_afficher_item_suite' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_articles_max' => 'Si oui, afficher les articles seulement si la rubrique contient au maximum xx articles ? (mettre le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_articles_max_affiches' => 'Si oui, limiter le nombre d\'articles listés à xx maximum (suivis d\'un item "... Tous les articles" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_aucun' => 'Cap',
+       'entree_bloc' => 'Bloc Zpip', # NEW
+       'entree_choisir' => 'Escolliu el tipus d\'entrada que voleu afegir:',
+       'entree_classe_parent' => 'Classe des liens des éléments parents. Cette classe sera rajoutée aux li>a ayant une suite ul/li. Par exemple, si vous saisissez "daddy", cela vous permet d\'utiliser le plugin menu deroulant 2 pour la mise en forme du menu.', # NEW
+       'entree_connexion_objet' => 'Obliger à être connecté (mettre "session") ou déconnecté (mettre "nosession") pour voir l\'objet', # NEW
+       'entree_contenu' => 'Contenu', # NEW
+       'entree_css' => 'Classes CSS de l\'entrada', # MODIF
+       'entree_css_lien' => 'Classes CSS du lien', # NEW
+       'entree_id_groupe' => 'Número del grup de paraula clau',
+       'entree_id_mot' => 'Número de la paraula clau',
+       'entree_id_objet' => 'Número',
+       'entree_id_rubrique' => 'Número de la secció pare',
+       'entree_id_rubrique_ou_courante' => 'Numéro de la rubrique parente ou "courante" si la rubrique parente est la rubrique courante du contexte', # NEW
+       'entree_id_rubriques_exclues' => 'Numéros des rubriques à exclure, séparés par des virgules', # NEW
+       'entree_id_secteur_exclus' => 'Numéros des secteurs à exclure, séparés par des virgules', # NEW
+       'entree_infini' => 'Fins l\'infinit',
+       'entree_mapage' => 'La meva pàgina personal',
+       'entree_masquer_articles_uniques' => 'Si oui et si une rubrique contient un seul article, le masquer ? (mettre "oui" pour cela)', # NEW
+       'entree_niveau' => 'Nivell de les subseccions',
+       'entree_nombre_articles' => 'Número d\'articles com a màxim (0 per defecte)',
+       'entree_page' => 'Nom de la pàgina',
+       'entree_parametres' => 'Llista dels paràmetres',
+       'entree_rubriques_max_affichees' => 'Si oui, limiter le nombre de rubriques listés à xx maximum (suivis d\'un item "... Toutes les rubriques" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum de rubriques, laissez vide pour afficher toutes les rubriques)', # NEW
+       'entree_sousrub_cond' => 'N\'afficher que les sous-rubriques de la rubrique en cours (mettre "oui", sinon laisser vide)', # NEW
+       'entree_suivant_connexion' => 'Restreindre cette entrée suivant la connexion (mettre "connecte" pour afficher seulement si le visiteur est connecté, "deconnecte" pour le cas contraire, ou laisser vide pour toujours afficher)', # NEW
+       'entree_suivant_connexion_connecte' => 'seulement si connecté', # NEW
+       'entree_suivant_connexion_deconnecte' => 'seulement si déconnecté', # NEW
+       'entree_sur_n_articles' => '@n@ articles mostrat(s)',
+       'entree_sur_n_mots' => '@n@ paraules mostrada(es)',
+       'entree_sur_n_niveaux' => 'A @n@ nivell(s)',
+       'entree_titre' => 'Títol',
+       'entree_titre_connecter' => 'Títol per l\'accés al formulari d\'identificació',
+       'entree_titre_prive' => 'Títol per accedir a l\'espai privat',
+       'entree_traduction_articles_rubriques' => 'Dans la mesure du possible, afficher les articles de la rubrique dans la langue du contexte (mettre "trad" pour cela)', # NEW
+       'entree_traduction_objet' => 'Dans le cas d\'un article, choisir la traduction en fonction du contexte (mettre "trad" pour cela)', # NEW
+       'entree_tri_alpha' => 'Criteri d\'ordenació (alfabètic)', # MODIF
+       'entree_tri_alpha_articles' => 'Critère de tri des articles (alphabétique). Si vous saisissez "date", le critère ajouté sera {par date} et les articles seront triés par date', # NEW
+       'entree_tri_alpha_articles_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_alpha_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num' => 'Criteri d\'ordenació (numèric)', # MODIF
+       'entree_tri_num_articles' => 'Critère de tri des articles (numérique). Si vous saisissez "titre", le critère ajouté sera {par num titre} et les articles seront triés par numéro de titre', # NEW
+       'entree_tri_num_articles_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_type_objet' => 'Tipus d\'objecte',
+       'entree_url' => 'Adreça',
+       'entree_url_public' => 'Adresse de retour après la connexion', # NEW
+       'erreur_aucun_type' => 'No s\'ha trobat cap entrada.',
+       'erreur_autorisation' => 'No estàs autoritzat per modificar els menús.',
+       'erreur_identifiant_deja' => 'Aquest identificador ja es utilitzat per un menú.',
+       'erreur_identifiant_forme' => 'L\'identificador només pot contenir lletres, xifres o el caràcter subratllat.',
+       'erreur_menu_inexistant' => 'El menú demanat número @id@ no existeix.',
+       'erreur_mise_a_jour' => 'S\'ha produït un error durant l\'actualització de la base de dades .',
+       'erreur_parametres' => 'Hi ha un error en els paràmetres de la pàgina',
+       'erreur_type_menu' => 'Has d\'escollir un tipus de menú',
+       'erreur_type_menu_inexistant' => 'Ce type de menu n\'est pas/plus disponible', # NEW
+
+       // F
+       'formulaire_ajouter_entree' => 'Afegir una entrada',
+       'formulaire_ajouter_sous_menu' => 'Crear un submenú',
+       'formulaire_css' => 'Classes CSS',
+       'formulaire_css_explication' => 'Podeu afegir al menú eventuals classes CSS suplementàries.',
+       'formulaire_deplacer_bas' => 'Desplaçar avall',
+       'formulaire_deplacer_haut' => 'Desplaçar amunt',
+       'formulaire_facultatif' => 'Facultatiu',
+       'formulaire_identifiant' => 'Identificador',
+       'formulaire_identifiant_explication' => 'Doneu una paraula clau única que us permetrà cridar fàcilment el vostre menú.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Choisissez quel(s) menu(s) vous souhaitez importer.', # NEW
+       'formulaire_ieconfig_importer' => 'Importer', # NEW
+       'formulaire_ieconfig_menu_meme_identifiant' => 'ATTENTION : un menu avec le même identifiant existe déjà sur votre votre site !', # NEW
+       'formulaire_ieconfig_menus_a_exporter' => 'Menus à exporter :', # NEW
+       'formulaire_ieconfig_ne_pas_importer' => 'Ne pas importer', # NEW
+       'formulaire_ieconfig_remplacer' => 'Remplacer le menu actuel par le menu importé', # NEW
+       'formulaire_ieconfig_renommer' => 'Renommer ce menu avant import', # NEW
+       'formulaire_importer' => 'Importar un menú',
+       'formulaire_importer_explication' => 'Si heu exportar un menú a dins d\'un fitxer, ara el podreu importar.',
+       'formulaire_modifier_entree' => 'Modificar aquesta entrada',
+       'formulaire_modifier_menu' => 'Modificar el menú:',
+       'formulaire_nouveau' => 'Nou menú',
+       'formulaire_partie_construction' => 'Construcció del menú',
+       'formulaire_partie_identification' => 'Identificació del menú',
+       'formulaire_supprimer_entree' => 'Suprimir aquesta entrada',
+       'formulaire_supprimer_menu' => 'Suprimir el menú',
+       'formulaire_supprimer_sous_menu' => 'Suprimir aquest submenú',
+       'formulaire_titre' => 'Títol',
+
+       // I
+       'info_afficher_articles' => 'Les articles seront inclus dans le menu.', # NEW
+       'info_articles_max' => 'Seulement si la rubrique contient au plus @max@ articles', # NEW
+       'info_articles_max_affiches' => 'Affichage limité à @max@ articles', # NEW
+       'info_classe_parent' => 'Classe des éléments parents : ', # NEW
+       'info_connexion_obligatoire' => 'Connexion obligatoire', # NEW
+       'info_deconnexion_obligatoire' => 'Uniquement déconnecté', # NEW
+       'info_masquer_articles_uniques' => 'Articles uniques masqués', # NEW
+       'info_numero_menu' => 'MENÚ NÚMERO:',
+       'info_page_speciale' => 'Enllaç cap a la pàgina «@page@»',
+       'info_page_speciale_zajax' => 'Modalbox de la page « @page@ » pour le bloc « @bloc@ &#187', # NEW
+       'info_rubrique_courante' => 'Rubrique courante', # NEW
+       'info_rubriques_exclues' => ' / sauf rubrique(s) @id_rubriques@', # NEW
+       'info_rubriques_max_affichees' => 'Affichage limité à @max@ rubriques', # NEW
+       'info_secteur_exclus' => ' / sauf secteur(s) @id_secteur@', # NEW
+       'info_sousrub_cond' => 'Seules les sous-rubriques de la rubriques en cours sont affichées.', # NEW
+       'info_tous_groupes_mots' => 'Tots els grups de paraules',
+       'info_traduction_recuperee' => 'Le contexte décidera de la traduction choisie', # NEW
+       'info_tri' => 'Ordena:', # MODIF
+       'info_tri_alpha' => '(alfabètica)',
+       'info_tri_articles' => 'Tri des articles :', # NEW
+       'info_tri_num' => '(numèrica)',
+
+       // N
+       'noisette_description' => 'Insère un menu défini avec le plugin Menus.', # NEW
+       'noisette_label_afficher_titre_menu' => 'Afficher le titre du menu ?', # NEW
+       'noisette_label_identifiant' => 'Menu à afficher :', # NEW
+       'noisette_nom_noisette' => 'Menu', # NEW
+       'nom_menu_accueil' => 'Inici',
+       'nom_menu_articles_rubrique' => 'Articles d\'una secció',
+       'nom_menu_deconnecter' => 'Desconnectar-se',
+       'nom_menu_espace_prive' => 'Connectar-se / enllaç cap a l\'espai privat',
+       'nom_menu_groupes_mots' => 'Paraules clau i Articles d\'un Grup de paraules',
+       'nom_menu_lien' => 'Enllaç arbitrari',
+       'nom_menu_mapage' => 'La meva pàgina',
+       'nom_menu_mots' => 'Articles d\'una Paraula clau',
+       'nom_menu_objet' => 'Article, secció o un altre objecte SPIP',
+       'nom_menu_page_speciale' => 'Enllaç cap a una pàgina esquelet',
+       'nom_menu_page_speciale_zajax' => 'Un bloc d\'une page Zpip', # NEW
+       'nom_menu_rubriques_completes' => 'Liste ou arborescence de rubriques et d\'articles (avec beaucoup d\'options)', # NEW
+       'nom_menu_rubriques_evenements' => 'Esdeveniments de les seccions',
+       'nom_menu_secteurlangue' => 'Sectors de llengua',
+       'nom_menu_texte_libre' => 'Texte libre', # NEW
+
+       // T
+       'tous_les_articles' => '... Tous les articles', # NEW
+       'toutes_les_rubriques' => '... Toutes les rubriques' # NEW
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_de.php b/www/plugins/menus_1/lang/menus_de.php
new file mode 100644 (file)
index 0000000..2a21d00
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'Wollen sie diesen Eintrag wirklich löschen?',
+
+       // D
+       'description_menu_accueil' => 'Link zur Startseite.',
+       'description_menu_articles_rubrique' => 'Artikelliste einer Rubrik anzeigen',
+       'description_menu_deconnecter' => 'Wenn eine Leser angemeldet ist, zeige ihm einen Abmelde-Link.',
+       'description_menu_espace_prive' => 'Link zum Login und zum Redaktionssystem',
+       'description_menu_groupes_mots' => 'Zeige automatisch ein Menü aus Schlagworten und zugehörigen Artikeln. In der Grundeinstellung werden die Schlagwortgruppen mit ihren Schlagworten angezeigt. Wenn ein Skelett mit der Bezeichnung groupes_mots.html existiert, wird der Link zur Schlagwortguppe verwendet.',
+       'description_menu_lien' => 'Fügt eine beliebigen Link hinzu, der entweder intern (rekative URL)oder extern (http://...) sein kann.',
+       'description_menu_mapage' => 'Wenn der Besucher angemeldet ist, füge einen Link zu seiner persönlichen Seite hinzu.',
+       'description_menu_mots' => 'Zeigt automatisch ein Menü, das die Artikel zum Schlagwort anzeigt.',
+       'description_menu_objet' => 'Link zu einem SPIP-Objekt anlegen: Artikel, Rubrik, usw. In der Grundeinstellung trägt der Eintrag den Namen des Objekts.',
+       'description_menu_page_speciale' => 'Fügt einen URL zu einer Skelettseite im Format  <code>spip.php?page=nom&param1=xx&param2=yyy...</code> hinzu. Diese Skelette werden von Plugins bereitgestellt',
+       'description_menu_page_speciale_zajax' => 'Fügt einen Link zu einem Block auf einer Seite hinzu, die über einen URL mit der Syntax <code>spip.php?page=nom¶m1=xx¶m2=yyy...</code> erreichbar ist. Dazu sind ein Skelett des Typs Z und das Plugin <a href="http://www.spip-contrib.net/MediaBox">médiabox</a> Voraussetzung.',
+       'description_menu_rubriques_articles' => 'Zeigt einen Liste der Rubriken und auf Wunsch der Unterrubriken und Artikel als Hierarchie an. In der Grundeinstellung werden alle Rubriken von der obersten Ebene an dargestellt. Sie werden nach Titeln (zuerst numerisch und dann alphabetisch) sortiert. Artikel werden immer hinter den Rubriken angezeigt.',
+       'description_menu_rubriques_completes' => 'Zeigt eine Liste der Rubriken und, wenn gewünscht, der Unterrubriken auf mehreren Ebenen an. Die Standardeinstellung zeigt alle Rubriken sortiert nach Titel an (mit Ordnungszahl nummerierte zuerst).',
+       'description_menu_secteurlangue' => 'Dieser Eintrag bezieht sich aud die Sites, welche pro Sprache ein Hauptrubrik verwenden. Er zeigt ein Menü mit allen Rubriken des Sektors, die mit der Sprache übereinstimmen, wenn erfordelich auf über mehrere Niveaus. In der Grundeinstelung werden alle Rubriken ab der obersten Ebene nach Titel (numerisch und anschließend alphanumerisch) sortiert angezeigt.',
+       'description_menu_texte_libre' => 'Ein beliebiger Text oder ein Sprachcode von SPIP im Format <:...:>',
+
+       // E
+       'editer_menus_editer' => 'Menü bearbeiten',
+       'editer_menus_explication' => 'Gestalten und konfigurieren sie hier die Menüs ihrer Website.',
+       'editer_menus_exporter' => 'Menü exportieren',
+       'editer_menus_nouveau' => 'Neues Menü anlegen',
+       'editer_menus_titre' => 'Menüs der Website',
+       'entree_afficher_articles' => 'Artikel in das Menü einbeziehen? ("oui" eintragen wenn gewünscht)',
+       'entree_afficher_item_suite' => 'Artikel in das Menü einbeziehen? ("oui" eintragen wenn gewünscht)',
+       'entree_articles_max' => 'Wenn ja, Artikel nur anzeigen, wenn die Rubrik maximal xx Artikel enthält. (Obergrenze eintragen, leer lassen um alle anzuzeigen)',
+       'entree_articles_max_affiches' => 'Wenn ja, Anzahl der angezeigten Artikel auf xx begrenzen; weitere werden durch den Eintrag "... alle Artikel" ersetzt. (Obergrenze eintragen, leer lassen um alle anzuzeigen)',
+       'entree_aucun' => 'Keiner',
+       'entree_bloc' => 'ZPIP Block',
+       'entree_choisir' => 'Wählen sie die Art EIntrag, die sie hinzufügen wollen:',
+       'entree_classe_parent' => 'Klasse der Links zu übergeordneten Objekten. Diese Klasse wird den li>a hinzugefügt, die sich mit ul/li fortsetezn. Wenn Sie z.B. "daddy" erfassen, können Sie das Plugin menu deroulant 2 zur Formatierung des Menüs einsetzen.',
+       'entree_connexion_objet' => 'Objekt wird nur angezeigt, wenn man entweder eingelogt ("session" eintragen) oder nicht eingelogt ist ("nosession" eintragen)',
+       'entree_contenu' => 'Inhalt',
+       'entree_css' => 'CSS-Klassen des Eintrags (des Containers)',
+       'entree_css_lien' => 'CSS-Klassen des Links',
+       'entree_id_groupe' => 'Nummer der Schlagwortgruppe',
+       'entree_id_mot' => 'Nummer des Schlagworts',
+       'entree_id_objet' => 'Nummer',
+       'entree_id_rubrique' => 'Nummer der übergeordeneten Rubrik',
+       'entree_id_rubrique_ou_courante' => 'Nummer der "Elternrubrik" oder der "aktuellen" Rubrik, wenn die Elternrubrik die aktuelle Rubrik des Kontext ist.',
+       'entree_id_rubriques_exclues' => 'Nummern der auszuschließenden Rubriken, getrennt durch Semikolons.',
+       'entree_id_secteur_exclus' => 'Nummern der auszuschließenden Sektoren, getrennt mit Kommata',
+       'entree_infini' => 'Unendlich',
+       'entree_mapage' => 'Meine eigene Seite',
+       'entree_masquer_articles_uniques' => 'Wenn ja und falls die Rubrik nur einen Artikel enthält wird dieser maskiert ("oui" eintragen wenn gewünscht).',
+       'entree_niveau' => 'Tiefe der Unterrubriken',
+       'entree_nombre_articles' => 'Maximale Anzahl Artikel (Standardwert 0)',
+       'entree_page' => 'Name der Seite',
+       'entree_parametres' => 'Parameterliste',
+       'entree_rubriques_max_affichees' => 'Wenn definiert, dann wird die Zahl der gelisteten Rubriken auf xx begrenzt und von einem Eintrag "... alle Rubriken" abgeschlossen. Obergrenze eintragen oder leer lassen, wenn alle angezeigt werden sollen.',
+       'entree_sousrub_cond' => 'Nur Unterrubriken der aktuellen Rubrik anzeigen ("oui" eintragen, falls nicht gewünscht leer lassen)',
+       'entree_suivant_connexion' => 'Verhalten des Eintrags in Abhängigkeit vom Verbindungsstatus: "Verbinden" wird nur angezeigt, wenn der Besucher nicht eingelogt ist, anderenfalls wird "Log-Out" angezeit. Freilassen, um den Eintrag immer anzuzeigen.', # MODIF
+       'entree_suivant_connexion_connecte' => 'nur wenn verbunden',
+       'entree_suivant_connexion_deconnecte' => 'nur wenn nicht verbunden',
+       'entree_sur_n_articles' => '@n@ Artikel angezeigt',
+       'entree_sur_n_mots' => '@n@ Worte angezeigt',
+       'entree_sur_n_niveaux' => 'Auf @n@ Niveau(s)',
+       'entree_titre' => 'Titel',
+       'entree_titre_connecter' => 'Titel für den Zugang zum Anmeldeformular',
+       'entree_titre_prive' => 'Titel für den Redaktionszugang',
+       'entree_traduction_articles_rubriques' => 'Wenn möglich Artikel der Rubrik in der Sprache des Kontext anzeigen ("oui" eintragen wenn gewünscht)',
+       'entree_traduction_objet' => 'Übersetzung von Artikeln in Abhängigkeit vom Sprachkontext auswählen (für diese EInstellung "trad" eintragen)',
+       'entree_tri_alpha' => 'Sortierung der Rubriken (alphanumerisch). Wenn Sie ein Datum angeben, wird das Kriterium {par date} hinzugefügt. und die Rubriken weden nach Datum sortiert.',
+       'entree_tri_alpha_articles' => 'Sortierung der Artikel (alphanumerisch). Wenn Sie ein Datum angeben, wird das Kriterium {par date} hinzugefügt. und die Artikel weden nach Datum sortiert.',
+       'entree_tri_alpha_articles_inverse' => 'Aplphabetische Sortierung umkehren  (dazu "oui" eingeben) ?',
+       'entree_tri_alpha_inverse' => 'Aplphabetische Sortierung umkehren  (dazu "oui" eingeben) ?',
+       'entree_tri_num' => 'Sortierung der Rubriken (numerisch). Wenn Sie einen Titel angeben, wird das Kriterium {par titre} hinzugefügt und die Rubrieken werden nach Titel sortiert angezeigt.',
+       'entree_tri_num_articles' => 'Sortierung der Rubriken (numerisch). Wenn Sie einen Titel angeben, wird das Kriterium {par titre} hinzugefügt und die Rubrieken werden nach Titel sortiert angezeigt.',
+       'entree_tri_num_articles_inverse' => 'Numerische Reihenfolge umkehren (dazu "oui" eingeben) ?',
+       'entree_tri_num_inverse' => 'Numerische Reihenfolge umkehren (dazu "oui" eingeben) ?',
+       'entree_type_objet' => 'Objekttyp',
+       'entree_url' => 'Adresse',
+       'entree_url_public' => 'Zieladresse nach der Anmeldung',
+       'erreur_aucun_type' => 'Kein Eintragstyp gefunden.',
+       'erreur_autorisation' => 'Sie dürfen Menüs nicht ändern.',
+       'erreur_identifiant_deja' => 'Deise Bezeichnung wird bereits von einem Menü verwendet.',
+       'erreur_identifiant_forme' => 'Die Bezeichnung darf nur Buchstaben, Ziffern und den Unterstrich enthalten.',
+       'erreur_menu_inexistant' => 'Das angeforderte Menü existiert nicht.',
+       'erreur_mise_a_jour' => 'Beim Aktualisieren der Datenbank ist ein Fehler aufgetreten.',
+       'erreur_parametres' => 'Fehler in den Seitenparametern',
+       'erreur_type_menu' => 'Sie müssen einen Menütyp wählen',
+       'erreur_type_menu_inexistant' => 'Dieser Menütyp ist nicht verfügbar.',
+
+       // F
+       'formulaire_ajouter_entree' => 'Eintrag hinzufügen',
+       'formulaire_ajouter_sous_menu' => 'Untermenü hinzufügen',
+       'formulaire_css' => 'CSS-Klassen',
+       'formulaire_css_explication' => 'Sie können dem Menü eventuell vorhandene zusätzliche CSS-Klassen zuordnen.',
+       'formulaire_deplacer_bas' => 'Nach unten verschieben',
+       'formulaire_deplacer_haut' => 'Nach oben verschieben',
+       'formulaire_facultatif' => 'Fakultatif',
+       'formulaire_identifiant' => 'Bezeichnung',
+       'formulaire_identifiant_explication' => 'Vergeben sie ein Schlagwort, mit dem sie das Menü leicht aufrufen können..',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Wählen Sie die die zu importierenden Menüs',
+       'formulaire_ieconfig_importer' => 'Importieren',
+       'formulaire_ieconfig_menu_meme_identifiant' => 'ACHTUNG: Ihre Website enthält bereits ein Menü mit der selben ID!',
+       'formulaire_ieconfig_menus_a_exporter' => 'Zu exportierende Menüs:',
+       'formulaire_ieconfig_ne_pas_importer' => 'Nicht importieren',
+       'formulaire_ieconfig_remplacer' => 'Aktuelles Menü durch das zu importierende ersetzen',
+       'formulaire_ieconfig_renommer' => 'Menü vor Import umbenennen',
+       'formulaire_importer' => 'Menü importieren',
+       'formulaire_importer_explication' => 'Wenn sie ein Menü in eine Datei exportiert haben, können sie es jetzt importieren.',
+       'formulaire_modifier_entree' => 'Eintrag bearbeiten',
+       'formulaire_modifier_menu' => 'Menü bearbeiten:',
+       'formulaire_nouveau' => 'Neues Menü',
+       'formulaire_partie_construction' => 'Aufbau des Menüs',
+       'formulaire_partie_identification' => 'Bezeichnung des Menüs',
+       'formulaire_supprimer_entree' => 'Eintrag löschen',
+       'formulaire_supprimer_menu' => 'Menü löschen',
+       'formulaire_supprimer_sous_menu' => 'Untermenü löschen',
+       'formulaire_titre' => 'Titel',
+
+       // I
+       'info_afficher_articles' => 'Artikel werden im Menü angezeigt',
+       'info_articles_max' => 'Nur wenn die Rubrik maximal @max@ Artikel enthält.',
+       'info_articles_max_affiches' => 'Anzeige ist begrenst auf maximal @max@  Artikel.',
+       'info_classe_parent' => 'Klasse der übergeordneten Objekte:',
+       'info_connexion_obligatoire' => 'Login obligatorisch',
+       'info_deconnexion_obligatoire' => 'Nur wenn nicht eingelogt',
+       'info_masquer_articles_uniques' => 'Einzelne Artikel maskieren.',
+       'info_numero_menu' => 'MENÜ NUMMER:',
+       'info_page_speciale' => 'Link zu Seite « @page@ »',
+       'info_page_speciale_zajax' => 'Modale Box der Seite « @page@ » für den Block « @bloc@ »',
+       'info_rubrique_courante' => 'Aktuelle Rubrik',
+       'info_rubriques_exclues' => ' / außer Rubrik(en) @id_rubriques@',
+       'info_rubriques_max_affichees' => 'Auf @max@ Rubriken begrenzen',
+       'info_secteur_exclus' => ' / außer Sektor(en) @id_secteur@',
+       'info_sousrub_cond' => 'Nur die Unterrubriken der aktuellen Rubrik werden angezeigt',
+       'info_tous_groupes_mots' => 'Alle Schlagwortgruppen',
+       'info_traduction_recuperee' => 'Die angezeigte Übersetzung wird je nach Sprachkontext gewählt.',
+       'info_tri' => 'Sortierung der Rubriken:',
+       'info_tri_alpha' => '(alphabetisch)',
+       'info_tri_articles' => 'Sortierung der Artikel',
+       'info_tri_num' => '(numerische)',
+
+       // N
+       'noisette_description' => 'Fügt ein mit dem Plugin "Menus" generiertes Menü ein',
+       'noisette_label_afficher_titre_menu' => 'Titel des Menüs anzeigen?',
+       'noisette_label_identifiant' => 'Dieses Menü anzeigen:',
+       'noisette_nom_noisette' => 'Menü',
+       'nom_menu_accueil' => 'Startseite',
+       'nom_menu_articles_rubrique' => 'Artikel einer Rubrik',
+       'nom_menu_deconnecter' => 'Abmelden',
+       'nom_menu_espace_prive' => 'Einloggen / zum Redaktionssystem',
+       'nom_menu_groupes_mots' => 'Schlagworte und Artikel einer Schlagwortgruppe',
+       'nom_menu_lien' => 'Beliebiger Link',
+       'nom_menu_mapage' => 'Meine Seite',
+       'nom_menu_mots' => 'Artikel eines Schlagworts',
+       'nom_menu_objet' => 'Artikel, Rubrik oder anderes SPIP-Objekt',
+       'nom_menu_page_speciale' => 'Link zu einer HTML-Vorlage',
+       'nom_menu_page_speciale_zajax' => 'Block einer ZPIP-Seite',
+       'nom_menu_rubriques_completes' => 'Listen- oder Baumansicht von Rubriken und Artikeln mit zahlreichen Optionen',
+       'nom_menu_rubriques_evenements' => 'Ereignisse der Rubriken',
+       'nom_menu_secteurlangue' => 'Hauptrubriken nach Sprache',
+       'nom_menu_texte_libre' => 'Freitext',
+
+       // T
+       'tous_les_articles' => '... alle Artikel',
+       'toutes_les_rubriques' => '... alle Rubriken'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_en.php b/www/plugins/menus_1/lang/menus_en.php
new file mode 100644 (file)
index 0000000..ee8adad
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'Do you really want delete this entry?',
+
+       // D
+       'description_menu_accueil' => 'Link to website\'s home page.',
+       'description_menu_articles_rubrique' => 'Display the list of articles in a section.',
+       'description_menu_deconnecter' => 'If the visitor is connected, add an entry offering disconnection.',
+       'description_menu_espace_prive' => 'Link enabling the connection to the site if you aren\'t already connected, and then to enter the private space if you are authorised to do so.',
+       'description_menu_groupes_mots' => 'Automatically show a menu listing the keyword of the group and the linked articles. By default it shows the list of keyword groups and the keywords within them. If a groupes_mots.html template exists, the link to the group is used.',
+       'description_menu_lien' => 'Adds an individually specified link, either an internal one (relative URL), or an external one (http://...).',
+       'description_menu_mapage' => 'If visitors are connected, add a link to their author page.',
+       'description_menu_mots' => 'Automatically shows a menu listing the articles linked to a keyword.',
+       'description_menu_objet' => 'Creates a link to s SPIP object: article, section or other. By default, the entry will bear the the title of the object.',
+       'description_menu_page_speciale' => 'Adds a link to a page template using a URL of the form <code>spip.php?page=name&param1=xx&param2=yyy...</code> Such pages are often used by plugins.',
+       'description_menu_page_speciale_zajax' => 'Add a link to a block in a page accessible by a URL of the type <code>spip.php?page=name&param1=xx&param2=yyy...</code> This requires a Z type template and the <a href="http://www.spip-contrib.net/MediaBox">médiabox</a> plugin.',
+       'description_menu_rubriques_articles' => 'Display a list of sections, optionally including sub-sections and articles nested to several levels. By default, all sections will be displayed starting from the site root and sorted by title (numerically then alphabetically).Articles in a given section will always be listed after any sub-sections.',
+       'description_menu_rubriques_completes' => 'Displays a list of topics and, if you want, sub-sections on many levels. By default, displays all entries from the root, sorted by title (alphabetically and numerically).',
+       'description_menu_secteurlangue' => 'This entry can be used by sites which have one language per sector. It displays a menu which lists the sections of the sector corresponding to the language of the page, and if desired the subsections to several levels. By default, all sections are shown from the site root, sorted by title (numerically then alphabetically).',
+       'description_menu_texte_libre' => 'Just the text that you would like, or a SPIP language code (<:...:>)',
+
+       // E
+       'editer_menus_editer' => 'Edit this menu',
+       'editer_menus_explication' => 'Create and configure menus for your site.',
+       'editer_menus_exporter' => 'Export this menu',
+       'editer_menus_nouveau' => 'Create a new menu',
+       'editer_menus_titre' => 'Site menus',
+       'entree_afficher_articles' => 'Include articles in the menu? (put "oui" for this)',
+       'entree_afficher_item_suite' => 'Include articles in the menu? (put "oui" for this)',
+       'entree_articles_max' => 'If so, show the articles only if the section contains a maximum of xx articles? (put the maximum number of articles, leave blank to display all articles)',
+       'entree_articles_max_affiches' => 'If so, limit the number of articles listed to a maximum of  xx (followed by an item "... All the articles" with a link to the parent section)? (indicate the maximum number of articles, leave blank to display all of them)',
+       'entree_aucun' => 'None',
+       'entree_bloc' => 'Zpip block',
+       'entree_choisir' => 'Choose the type of item you want to add:',
+       'entree_classe_parent' => 'CSS class of the links of the parent elements. This class will be added to the li>a having a subsequent ul / li. For example, if you type "daddy", it allows you to use the plugin "menu deroulant 2" to format the menu.',
+       'entree_connexion_objet' => 'Requires being connected (insert "session") or disconnected (insert "nosession") in order to see the object',
+       'entree_contenu' => 'Content',
+       'entree_css' => 'CSS classes of this (container) item',
+       'entree_css_lien' => 'CSS classes of the link',
+       'entree_id_groupe' => 'Number of the keyword group',
+       'entree_id_mot' => 'Number of the keyword',
+       'entree_id_objet' => 'Number',
+       'entree_id_rubrique' => 'Number of the parent section',
+       'entree_id_rubrique_ou_courante' => 'Parent or "current" section number if the parent section is the current section of the context',
+       'entree_id_rubriques_exclues' => 'Numbers of the sections to be excluded, separated by commas',
+       'entree_id_secteur_exclus' => 'Numbers of the sectors to be excluded, separated by commas',
+       'entree_infini' => 'To infinity',
+       'entree_mapage' => 'My page',
+       'entree_masquer_articles_uniques' => 'If so and if a section contains a only one article, hide it? (put "oui" for this)',
+       'entree_niveau' => 'Sub-sections level',
+       'entree_nombre_articles' => 'Maximum number of articles (0 by default)',
+       'entree_page' => 'Name of the page',
+       'entree_parametres' => 'List of parameters',
+       'entree_rubriques_max_affichees' => 'If so, limit the number of sections listed to a maximum of xx (followed by an item "... All sections" with a link to the parent section)? (indicate the maximum number of sections, leave blank to show all of them)',
+       'entree_sousrub_cond' => 'Only display the subsections for the current section (enter "oui" (yes), otherwise leave it empty)',
+       'entree_suivant_connexion' => 'Restrict this entry according to the connection (put "connecte" to display it only if the visitor is connected, "deconnecte" in the opposite case, put "admin" if the author is administrator or leave blank to always display it)',
+       'entree_suivant_connexion_connecte' => 'only if connected',
+       'entree_suivant_connexion_deconnecte' => 'only if disconnected',
+       'entree_sur_n_articles' => '@n@ article(s) shown',
+       'entree_sur_n_mots' => '@n@ keyword(s) shown',
+       'entree_sur_n_niveaux' => 'On @n@ level(s)',
+       'entree_titre' => 'Title',
+       'entree_titre_connecter' => 'The title for accessing the identification form',
+       'entree_titre_prive' => 'The title for accessing the private zone',
+       'entree_traduction_articles_rubriques' => 'If possible, show the articles of the section in the language of the context (put "trad" for this)',
+       'entree_traduction_objet' => 'For an article, select the translation depending on the context (insert "trad" to accomplish this)',
+       'entree_tri_alpha' => 'Sort criterion of the sections (alphabetical). If you type "date", the added criterion will be {par date} (by date) and the sections will be sorted by date',
+       'entree_tri_alpha_articles' => 'Sort criterion of the articles (alphabetical). If you type "date", the added criterion will be {par date} and the article will be sorted by date',
+       'entree_tri_alpha_articles_inverse' => 'Reverse the sorting alphabetically? (put "oui" for this)',
+       'entree_tri_alpha_inverse' => 'Reverse the alphabetical sorting? (put "oui" for this)',
+       'entree_tri_num' => 'Sort criterion of the sections (digital). If you type "titre" (title), the added criterion will be {par num titre} and the sections will be number of the titles',
+       'entree_tri_num_articles' => 'Sort criterion of the articles (digital). If you type "titre" (title), the added criterion will be {par num titre} and the articles will be sorted by number of title',
+       'entree_tri_num_articles_inverse' => 'Reverse the digital sort order? (put "oui" for this)',
+       'entree_tri_num_inverse' => 'Reverse the digital sort order? (put "oui" for this)',
+       'entree_type_objet' => 'Object type',
+       'entree_url' => 'URL',
+       'entree_url_public' => 'Return address after logging in',
+       'erreur_aucun_type' => 'No item type was found.',
+       'erreur_autorisation' => 'You are not allowed to modify menus.',
+       'erreur_identifiant_deja' => 'This identifier is already used by another menu.',
+       'erreur_identifiant_forme' => 'Identifier must contain only letters, digits or underscores.',
+       'erreur_menu_inexistant' => 'Menu number @id@ doesn\'t exist.',
+       'erreur_mise_a_jour' => 'An error occured during database update.',
+       'erreur_parametres' => 'There is an error in the parameters of the page',
+       'erreur_type_menu' => 'You need to choose a type of menu',
+       'erreur_type_menu_inexistant' => 'This kind of menu is not / no longer available',
+
+       // F
+       'formulaire_ajouter_entree' => 'Add a menu item',
+       'formulaire_ajouter_sous_menu' => 'Create a sub-menu',
+       'formulaire_css' => 'CSS classes',
+       'formulaire_css_explication' => 'You can add to your menu additional CSS classes.',
+       'formulaire_deplacer_bas' => 'Move down',
+       'formulaire_deplacer_haut' => 'Move up',
+       'formulaire_facultatif' => 'Optional',
+       'formulaire_identifiant' => 'Identifier',
+       'formulaire_identifiant_explication' => 'Give a unique keyword which let you call your menu easly.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Select which menu(s) you would like to import.',
+       'formulaire_ieconfig_importer' => 'Import',
+       'formulaire_ieconfig_menu_meme_identifiant' => 'WARNING: there is already a menu with the same name on your site!',
+       'formulaire_ieconfig_menus_a_exporter' => 'Menus to export:',
+       'formulaire_ieconfig_ne_pas_importer' => 'Do not import',
+       'formulaire_ieconfig_remplacer' => 'Overwrite the current menu with the imported menu',
+       'formulaire_ieconfig_renommer' => 'Rename this menu before importing',
+       'formulaire_importer' => 'Import menu',
+       'formulaire_importer_explication' => 'If you exported a menu in a file, you can import now.',
+       'formulaire_modifier_entree' => 'Modify this menu item',
+       'formulaire_modifier_menu' => 'Modify menu:',
+       'formulaire_nouveau' => 'New menu',
+       'formulaire_partie_construction' => 'Menu construction',
+       'formulaire_partie_identification' => 'Menu identification',
+       'formulaire_supprimer_entree' => 'Delete this menu item',
+       'formulaire_supprimer_menu' => 'Delete the menu',
+       'formulaire_supprimer_sous_menu' => 'Delete this sub-menu',
+       'formulaire_titre' => 'Title',
+
+       // I
+       'info_afficher_articles' => 'The articles will be included in the menu.',
+       'info_articles_max' => 'Only if the section contains more than @max@ articles',
+       'info_articles_max_affiches' => 'Display limited to @max@ articles',
+       'info_classe_parent' => 'Class of the parent elements:',
+       'info_connexion_obligatoire' => 'Connection required',
+       'info_deconnexion_obligatoire' => 'Only when disconnected',
+       'info_masquer_articles_uniques' => 'Unique articles hidden',
+       'info_numero_menu' => 'MENU NUMBER:',
+       'info_page_speciale' => 'Link to the page « @page@ »',
+       'info_page_speciale_zajax' => 'Modalbox for the "@page@" page for the "@bloc@" block',
+       'info_rubrique_courante' => 'Current section',
+       'info_rubriques_exclues' => ' / except section(s) @id_rubriques@',
+       'info_rubriques_max_affichees' => 'Display limited to @max@ sections',
+       'info_secteur_exclus' => ' / except sector(s) @id_secteur@',
+       'info_sousrub_cond' => 'Only the subsections of the current section are displayed.',
+       'info_tous_groupes_mots' => 'All keyword groups',
+       'info_traduction_recuperee' => 'The context will determine the selected translation',
+       'info_tri' => 'Sort sections:',
+       'info_tri_alpha' => '(alphabetical)',
+       'info_tri_articles' => 'Sort articles:',
+       'info_tri_num' => '(numerical)',
+
+       // N
+       'noisette_description' => 'Insert a menu defined with the Menus plugin.',
+       'noisette_label_afficher_titre_menu' => 'Show the menu title?',
+       'noisette_label_identifiant' => 'Menu to display:',
+       'noisette_nom_noisette' => 'Menu',
+       'nom_menu_accueil' => 'Home Page',
+       'nom_menu_articles_rubrique' => 'Articles of a section',
+       'nom_menu_deconnecter' => 'Disconnect',
+       'nom_menu_espace_prive' => 'Login / link to the private zone',
+       'nom_menu_groupes_mots' => 'Keywords and Articles of a group of keywords',
+       'nom_menu_lien' => 'Individual link',
+       'nom_menu_mapage' => 'My page',
+       'nom_menu_mots' => 'Articles of a keyword',
+       'nom_menu_objet' => 'Article, section or other SPIP object',
+       'nom_menu_page_speciale' => 'Link to a page template',
+       'nom_menu_page_speciale_zajax' => 'A block in a Zpip page',
+       'nom_menu_rubriques_completes' => 'List or tree of sections and articles (with many options)',
+       'nom_menu_rubriques_evenements' => 'Section-related events',
+       'nom_menu_secteurlangue' => 'Language sectors',
+       'nom_menu_texte_libre' => 'Free text',
+
+       // T
+       'tous_les_articles' => '... All articles',
+       'toutes_les_rubriques' => '... All sections'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_es.php b/www/plugins/menus_1/lang/menus_es.php
new file mode 100644 (file)
index 0000000..dbcaca0
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => '¿Quiere realmente eliminar esta entrada?',
+
+       // D
+       'description_menu_accueil' => 'Enlace a la portada del sitio.',
+       'description_menu_articles_rubrique' => 'Muestra una lista de artículos de una sección.',
+       'description_menu_deconnecter' => 'Si el visitante se conecta, se añade una entrada que propone la desconexión.',
+       'description_menu_espace_prive' => 'Enlace para conectarse al sitio si no está ya conectado, y luego ir a la zona privada, si se tiene autorización.',
+       'description_menu_groupes_mots' => 'Muestra automáticamente un menú con las palabras del grupo y artículos relacionados. De manera predeterminada, muestra la lista de frases y palabras. Si un esqueleto groupes_mots.html existe, el enlace con el grupo es utilizado.',
+       'description_menu_lien' => 'Añade un enlace arbitrario interno (URL relativa) o externo (http://...).',
+       'description_menu_mapage' => 'Si el visitante se conecta, añade un enlace a su página de autor.',
+       'description_menu_mots' => 'Muestra automáticamente un menú que enumera los artículos relacionados con la palabra clave.',
+       'description_menu_objet' => 'Crea un enlace a un objeto de SPIP: artículo, sección u otro. De manera predeterminada, la entrada será el título del objeto.',
+       'description_menu_page_speciale' => 'Añade un enlace a un esqueleto página accesible para una url del tipo <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Estas páginas se proporcionan a menudo por los plugins.',
+       'description_menu_page_speciale_zajax' => 'Añadir un enlace a un bloque de una página accesible por una url del tipo <code>spip.php?page=nom¶m1=xx¶m2=yyy...</code> Esto requiere un esqueleto de tipo Z y el plugin <a href="http://www.spip-contrib.net/MediaBox"> Mediabox</ a>.',
+       'description_menu_rubriques_articles' => 'Muestra una lista de secciones y, si se quiere, subsecciones y artículos en varios niveles. De manera predeterminada, muestra todas las secciones de la raíz, ordenados por título (en orden alfabético y numérico). Los artículos se colocan automáticamente después de las secciones.',
+       'description_menu_rubriques_completes' => 'Muestra una lista de secciones y, si se quiere, las subsecciones en varios niveles. Por defecto, muestra todas las secciones desde la raíz, ordenadas por título (numéricamente, y luego alfabéticamente).',
+       'description_menu_secteurlangue' => 'Esta entrada es específica de los sitios que utilizan un sector para cada idioma. Se muestra automáticamente un menú con las secciones de la zona correspondiente al idioma de la página y, si se quiere, las sub-secciones en varios niveles. De manera predeterminada, muestra todas las secciones de la raíz, ordenados por título (en orden alfabético y numérico).',
+       'description_menu_texte_libre' => 'Simplemente el texto que deseas, o un código de idiomas SPIP (<:...:>)',
+
+       // E
+       'editer_menus_editer' => 'Modificar el menú',
+       'editer_menus_explication' => 'Crear y configurar aquí los menús de su sitio',
+       'editer_menus_exporter' => 'Exportar el menú',
+       'editer_menus_nouveau' => 'Crear un nuevo menú',
+       'editer_menus_titre' => 'Menús del sitio',
+       'entree_afficher_articles' => 'Incluir los artículos en en el menú  ? (escribe "oui" para para que ocurra)',
+       'entree_afficher_item_suite' => 'Incluir los artículos en el menu ? (escribe "oui" para esto)',
+       'entree_articles_max' => 'Si es así, ¿ver los artículos sólo si la sección contiene como máximo xx artículos? (indicar el máximo número de artículos, o bien dejar en blanco para mostrar todos los artículos)',
+       'entree_articles_max_affiches' => 'Si es así, ¿limitar el número de artículos listados en xx máximo (seguidos de un ítem "... Todos los artículos", con un enlace a la sección padre)? (Indique el número máximo de artículos, dejar en blanco para mostrar todos los artículos)',
+       'entree_aucun' => 'Ninguno',
+       'entree_bloc' => 'Bloquear Zpip',
+       'entree_choisir' => 'Seleccione el tipo de entrada que desea añadir:',
+       'entree_classe_parent' => 'Clase de vínculos de elementos primarios. Esta clase se añadirá a li>a asociados a ul/li. Por ejemplo, si escribe "papá", lo que le permite utilizar el plugin "menu deroulant 2" para este menú.',
+       'entree_connexion_objet' => 'Obligar  a estar conectado (poner "session") o desconectado (poner "nosession") para ver el objeto',
+       'entree_contenu' => 'Contenido',
+       'entree_css' => 'Clases css de la entrada (contenedor)',
+       'entree_css_lien' => 'Clases CSS del link',
+       'entree_id_groupe' => 'Número del grupo de palabras clave',
+       'entree_id_mot' => 'Número de palabra clave',
+       'entree_id_objet' => 'Número',
+       'entree_id_rubrique' => 'Número de la sección padre',
+       'entree_id_rubrique_ou_courante' => 'Número de la sección madre o "corriente" si la sección padre es la sección corriente del contexto',
+       'entree_id_rubriques_exclues' => 'Números de secciones a excluir, separadas por coma',
+       'entree_id_secteur_exclus' => 'Números de sectores a excluir, separados por coma',
+       'entree_infini' => 'Al infinito',
+       'entree_mapage' => 'Mi página personal',
+       'entree_masquer_articles_uniques' => 'Si es así y si una sección contiene un solo elemento, se esconde? (Poner "oui" para esto)',
+       'entree_niveau' => 'Niveles de sub-secciones',
+       'entree_nombre_articles' => 'Número de artículos como máximo (0 por defecto)',
+       'entree_page' => 'Nombre de la página',
+       'entree_parametres' => 'Lista de parámetros',
+       'entree_rubriques_max_affichees' => 'Si es así, limitar el número de secciones listadas a xx máximo (seguido por una entrada "... Todos las secciones" con un enlace a la sección padre)? (Especifique el número máximo de secciones, dejar en blanco para mostrarlas todas)',
+       'entree_sousrub_cond' => 'Mostrar sólo subcategorías de la sección actual (poner "oui", de lo contrario dejar en blanco)',
+       'entree_suivant_connexion' => 'Restringir esta entrada según el estado de conexión (poner "connecte" para mostrar sólo si el visitante está conectado, "deconnecte" para el caso contrario, poner "admin" si el autor es administrador o dejar en blanco para mostrar siempre)',
+       'entree_suivant_connexion_connecte' => 'sólo si conectado',
+       'entree_suivant_connexion_deconnecte' => 'sólo si desconectado',
+       'entree_sur_n_articles' => '@n@ artículo(s) mostrado(s)',
+       'entree_sur_n_mots' => '@n@ palabra(s) mostrada(s)',
+       'entree_sur_n_niveaux' => 'En @n@ nivel(es)',
+       'entree_titre' => 'Título',
+       'entree_titre_connecter' => 'Título para acceder al formulario de identificación',
+       'entree_titre_prive' => 'Título para acceder al espacio privado',
+       'entree_traduction_articles_rubriques' => 'Siempre que sea posible, ver los artículos en la categoría en el idioma del contexto (poner "trad" para esto)',
+       'entree_traduction_objet' => 'En el caso de un artículo, seleccione la traducción en función del contexto (poner "trad" para esto)',
+       'entree_tri_alpha' => 'Criterio de orden de secciones (alfabético). Si escribe "date", el criterio será {par date} y los artículos serán ordenados por fecha',
+       'entree_tri_alpha_articles' => 'Criterio de orden de los artículos (alfabético). Si escribe "date", el criterio será {par date} y los artículos serán ordenados por fecha',
+       'entree_tri_alpha_articles_inverse' => 'Invertir el criterio de orden alfabético ? (poner "oui" para esto)',
+       'entree_tri_alpha_inverse' => 'Invertir el criterio de orden alfabético? (poner "oui" para esto)',
+       'entree_tri_num' => 'Criterio de orden de las secciones (numérico). Si escribe "titre", el criterio será {par num titre} y las secciones serán ordenados por fecha',
+       'entree_tri_num_articles' => 'Criterio de orden de los artículos (numérico). Si escribe "titre", el criterio será {par num titre} y los artículos serán ordenados por fecha',
+       'entree_tri_num_articles_inverse' => '¿Invertir el criterio de orden numérico ? (poner "oui" poara esto)',
+       'entree_tri_num_inverse' => '¿Invertir el criterio de orden numérico ? (poner "oui" poara esto)',
+       'entree_type_objet' => 'Tipo de objeto',
+       'entree_url' => 'Dirección',
+       'entree_url_public' => 'Dirección de retorno luego de la conexión',
+       'erreur_aucun_type' => 'Ningún tipo de entrada se encontró.',
+       'erreur_autorisation' => 'No estás autorizado a modificar los menús.',
+       'erreur_identifiant_deja' => 'Este identificador ya es utilizado por un menú.',
+       'erreur_identifiant_forme' => 'El identificador debe contener sólo letras, números o guión bajo.',
+       'erreur_menu_inexistant' => 'El menú con numéro @id@  solicitado no existe.',
+       'erreur_mise_a_jour' => 'Se produjo un error durante la actualización de la base de datos.',
+       'erreur_parametres' => 'Hubo un error en los parámetros de la página',
+       'erreur_type_menu' => 'Debes elegir un tipo de menú',
+       'erreur_type_menu_inexistant' => 'Este tipo de menu no está, o ya no está disponible',
+
+       // F
+       'formulaire_ajouter_entree' => 'Añadir una entrada',
+       'formulaire_ajouter_sous_menu' => 'Crear un submenú',
+       'formulaire_css' => 'Clases CSS',
+       'formulaire_css_explication' => 'Puedes agregar al menú eventuales clases CSS suplementarias.',
+       'formulaire_deplacer_bas' => 'Bajar',
+       'formulaire_deplacer_haut' => 'Subir',
+       'formulaire_facultatif' => 'Opcional',
+       'formulaire_identifiant' => 'Identificador',
+       'formulaire_identifiant_explication' => 'Indique una palabra clave única que le permita nombrar a su menú fácilmente.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Elija el(los) menú(s) que desea importar.',
+       'formulaire_ieconfig_importer' => 'Importar',
+       'formulaire_ieconfig_menu_meme_identifiant' => 'ATENCION : un menú con el mismo identificador ya existe en tu sitio !',
+       'formulaire_ieconfig_menus_a_exporter' => 'Menús a exportar :',
+       'formulaire_ieconfig_ne_pas_importer' => 'No importar',
+       'formulaire_ieconfig_remplacer' => 'Reemplazar el menú actual por el menú importado',
+       'formulaire_ieconfig_renommer' => 'Renombrar el menú antes de importar',
+       'formulaire_importer' => 'Importar un menú',
+       'formulaire_importer_explication' => 'Si ha exportado un menú en un archivo, puede importarlo ahora.',
+       'formulaire_modifier_entree' => 'Modificar esta entrada',
+       'formulaire_modifier_menu' => 'Modificar el menú :',
+       'formulaire_nouveau' => 'Nuevo menú',
+       'formulaire_partie_construction' => 'Construcción del menú',
+       'formulaire_partie_identification' => 'Identificación del menú',
+       'formulaire_supprimer_entree' => 'Eliminar esta entrada',
+       'formulaire_supprimer_menu' => 'Eliminar el menú',
+       'formulaire_supprimer_sous_menu' => 'Eliminar el submenú',
+       'formulaire_titre' => 'Título',
+
+       // I
+       'info_afficher_articles' => 'Los artículos serán incluídos en el menú',
+       'info_articles_max' => 'Sólo si la sección contiene como máximo @max@ artículos',
+       'info_articles_max_affiches' => 'Visualización limitada a un máximo de @max@ artículos',
+       'info_classe_parent' => 'Clase de elementos padre : ',
+       'info_connexion_obligatoire' => 'Conexión obligatoria',
+       'info_deconnexion_obligatoire' => 'Únicamente desconectado',
+       'info_masquer_articles_uniques' => 'Artículos únicos ocultos',
+       'info_numero_menu' => 'MENU NÚMERO :',
+       'info_page_speciale' => 'Link a la página « @page@ »',
+       'info_page_speciale_zajax' => 'Modalbox de la página «@page@» para el bloque «@bloc@» ',
+       'info_rubrique_courante' => 'Sección en curso',
+       'info_rubriques_exclues' => ' / salvo la(s) sección(es) @id_rubriques@',
+       'info_rubriques_max_affichees' => 'Limitado a @max@ secciones',
+       'info_secteur_exclus' => ' / salvo el/los sector(es) @id_secteur@',
+       'info_sousrub_cond' => 'Sólo las subsecciones de las secciones que se muestran.',
+       'info_tous_groupes_mots' => 'Todos los grupos de palabras',
+       'info_traduction_recuperee' => 'El contexto decidirá la traducción elegida',
+       'info_tri' => 'Orden de secciones:',
+       'info_tri_alpha' => '(alfabético)',
+       'info_tri_articles' => 'Orden de artículos :',
+       'info_tri_num' => '(numérico)',
+
+       // N
+       'noisette_description' => 'Inserta un menú definido con el plugin Menús',
+       'noisette_label_afficher_titre_menu' => 'Mostrar el título del menú ?',
+       'noisette_label_identifiant' => 'Menú a mostrar  :',
+       'noisette_nom_noisette' => 'Menú',
+       'nom_menu_accueil' => 'Inicio',
+       'nom_menu_articles_rubrique' => 'Artículos de una sección',
+       'nom_menu_deconnecter' => 'Desconectarse',
+       'nom_menu_espace_prive' => 'Conectarse / link al espacio privado',
+       'nom_menu_groupes_mots' => 'Palabras claves y artículos de un grupo de palabras clave',
+       'nom_menu_lien' => 'Link arbitrario',
+       'nom_menu_mapage' => 'Mi página',
+       'nom_menu_mots' => 'Artículos de una palabra clave',
+       'nom_menu_objet' => 'Artículo, sección u otro objeto de SPIP',
+       'nom_menu_page_speciale' => 'Link a un esqueleto de página',
+       'nom_menu_page_speciale_zajax' => 'Un bloque de una página Zpip',
+       'nom_menu_rubriques_completes' => 'Lista o arborescencia de secciones y de artículos (con varias opciones)',
+       'nom_menu_rubriques_evenements' => 'Eventos de secciones',
+       'nom_menu_secteurlangue' => 'Sectores de idioma',
+       'nom_menu_texte_libre' => 'Texto libre',
+
+       // T
+       'tous_les_articles' => '... Todos los artículos',
+       'toutes_les_rubriques' => '... Todas las secciones'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_fa.php b/www/plugins/menus_1/lang/menus_fa.php
new file mode 100644 (file)
index 0000000..6b9a8b5
--- /dev/null
@@ -0,0 +1,190 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'واقعاً مي‌خواهيد اين مدخل را حذف كنيد؟',
+
+       // D
+       'description_menu_accueil' => 'پيوند به صفحه‌ي پذيرش سايت.',
+       'description_menu_articles_rubrique' => 'نمايش فهرست مقالات يك بخش ',
+       'description_menu_deconnecter' => 'اگر بازديد كننده وصل شد، يك مدخل اضافه كنيد تا قطع شدن را به او ارايه دهد.',
+       'description_menu_espace_prive' => 'پيوندي كه ارتباط با سايت را فعال مي‌كند در صورتي كه قبلاً به سايت وصل نشده باشيد، و بعد وارد قسمت شخصي سايت شويد البته اگر مجاز باشيد.  ',
+       'description_menu_groupes_mots' => 'به طور خودكار گروه‌واژه‌ها و مقالات مرتبط با آن‌ها را فهرست مي‌كند. اين فهرست به صورت پيش‌ گزيده گروه‌‌واژه‌ها و كليدواژه‌هاي تحت آن‌ها را نشان مي‌دهد. اگر اسكلت يك groupes_mots.html وجود داشته باشد، پيوند به آن گروه‌واژه فعال مي‌شود. ',
+       'description_menu_lien' => 'افزودن يك پيوند فرداً تعيين شده، هم دروني (يوآرال نسبي) و هم بروني (http://...)',
+       'description_menu_mapage' => 'اگر بازديد‌كننده متصل است، يك پيوند به صفحه‌ي نويسنده‌‌‌اش اضافه كن.',
+       'description_menu_mots' => 'خودكار يك منوي فهرست تمام مقالات مرتبط با كليدواژه را نشان بده.',
+       'description_menu_objet' => 'ايجاد پيوند به چيزهاي اسپيپي: مقاله، بخش يا چيزهاي ديگر. پيش‌گزيده، هر مدخل تيتر آن چيز را داراست.',
+       'description_menu_page_speciale' => 'افزودن پيوند به صفحه‌ي اسكلت با استفاده از يوآرال اين فرم <code>spip.php?page=nom&param1=xx&param2=yyy...</code>. چنين صفحه‌هايي اغلب توسط پلاگين‌ها استفاده مي‌شوند.  ',
+       'description_menu_page_speciale_zajax' => 'افزودن يك پيوند به يك بلوك در صفحه‌اي قابل دسترس به وسيله‌ي يك يوآرال از نوع <code>spip.php?page=nom&param1=xx&param2=yyy...</code>. اين مستلزم يك استكلت نوع z و يك پلاگين <a href="http://www.spip-contrib.net/MediaBox">médiabox</a> خواهد بود.  ',
+       'description_menu_rubriques_articles' => 'نمايش يك فهرست از بخش‌ها، و اگر مي‌خواهيد، زيربخش‌ها و مقاله‌ها در چندين سطح. 
+به صورت پيش‌گزيده، نمايش تمام بخش‌ها ريشه، مرتب شده بر اساس تيتر(شماره‌اي و بعد الفبايي). مقاله‌ها به طور نظام‌مند بعد از بخش‌ها قرار مي‌گيرند. 
+',
+       'description_menu_rubriques_completes' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).', # NEW
+       'description_menu_secteurlangue' => 'اين مدخل به سايت‌هايي اختصاص دارد كه يك بخش براي زبان دارند. اين مدخل به صورت خودكار منيويي را نشان مي‌دهد كه بخش‌ها آن قسمت منطبق با آن زبان و صفحه، و اگر بخواهند زيربخش‌ها را تا چندين سطح، را فهرست مي‌كنند. به صورت پيش‌گزيده، تمام بخش‌هاي عد از ريشه را، به ترتيب تيتر (طبق شماره و بعد طبق الفا) نشان مي‌دهد. 
+',
+       'description_menu_texte_libre' => 'فقط متني كه دوست داريد، يا يك كد زباني اسپيپ  (<:...:>)',
+
+       // E
+       'editer_menus_editer' => 'اصلاح اين منيو',
+       'editer_menus_explication' => 'منيوهاي سايتتان را اينجا ايجاد و پيكربندي كنيد.',
+       'editer_menus_exporter' => 'صادر سازي اين منيو',
+       'editer_menus_nouveau' => 'ايجاد يك منيوي جديد',
+       'editer_menus_titre' => 'منيوهاي سايت',
+       'entree_afficher_articles' => 'مقاله‌ها در منيو‌ گنجانده شود؟ (براي اين بگذاريد «بله»)',
+       'entree_afficher_item_suite' => 'گنجاندن مقاله‌ها در منيو؟ (براي اين بگذاريد «بله»)',
+       'entree_articles_max' => 'اگر بله، نمايش مقاله‌ها فقط اگر بخش شامل حداكثر ايكس ايكس مقاله است؟ (عدد مربوط به حداكثر مقاله را بگذاريد، براي نمايش تمام مقاله‌ها، خالي بگذاريد)
+',
+       'entree_articles_max_affiches' => 'در اين صورت، تعداد مقاله‌هاي فهرست شده تا حداكثر xx  محدود شود(بعد از يك فقره «...تمام مقاله‌ها» با يك لينك به بخش‌ والد)؟ (تعداد حداكثر مقاله‌ها را مشخص كنيد ، يا خالي بگذاريد تا تمام مقاله‌ها نشان داده شوند)
+',
+       'entree_aucun' => 'هيچي',
+       'entree_bloc' => 'بلاك ازپيپ (Bloc Zpip)',
+       'entree_choisir' => 'نوع مدخلي را كه مي‌خواهيد اضافه كنيد انتخاب نماييد.',
+       'entree_classe_parent' => 'طبقه‌ي پيوند‌هاي عناصر والد. اين طبقه دو باره به li>داراي پيامد  ul / lاضافه خواهد كرد. 
+به عنوان نمونه، اگر شما «ددي» را تايپ كنيد، اين به شما اجازه مي‌دهد تا پلاگين« منيو طوماري 2»» را براي فرمت بخشي به منيو مورد استفاده قرار دهيد. 
+',
+       'entree_connexion_objet' => 'براي ديدن اوبژه وصل بودن («session»وارد كنيد) يا قطع بودن («nosession»وارد كنيد) لازم است',
+       'entree_contenu' => 'محتوا',
+       'entree_css' => 'كلاش‌هاي سي.اس.اس (حامل) مدخل',
+       'entree_css_lien' => 'كلاس‌هاي سي.اس.اس پيوند',
+       'entree_id_groupe' => 'تعداد گروه واژه‌ها',
+       'entree_id_mot' => 'تعداد كليدواژه‌ها',
+       'entree_id_objet' => 'تعداد',
+       'entree_id_rubrique' => 'تعداد بخش‌هاي والد',
+       'entree_id_rubrique_ou_courante' => 'تعداد بخش‌ والد يا «فعلي» اگر بخش‌ والد در متن بخش فعلي باشد.',
+       'entree_id_rubriques_exclues' => 'تعداد بخش‌ها براي كنارگذاري، جداشده با ويرگول',
+       'entree_id_secteur_exclus' => 'تعداد بخش‌ها براي داخل‌ گذاري، جداشده با ويرگول',
+       'entree_infini' => 'تا بي‌نهايت',
+       'entree_mapage' => 'صفحه‌ي شخصي من',
+       'entree_masquer_articles_uniques' => 'در اين صورت و اگر يك بخش فقط يك مقاله دارد، آن را مخفي كند؟ (براي اين كار بگذاريد «بله»)',
+       'entree_niveau' => 'سطح زيربخش‌ها',
+       'entree_nombre_articles' => 'تعداد حداكثر مقاله‌ها (پيش گزيده صفر)',
+       'entree_page' => 'نام صفحه',
+       'entree_parametres' => 'فهرست پارامترها',
+       'entree_rubriques_max_affichees' => 'در اين صورت، تعداد بخش‌هاي فهرست شده تا حداكثر xx محدود شئذ (در پي فقره‌‌ي . . . «تمام بخش‌ها» با پيوند به بخش والد)؟
+(حداكثر تعداد بخش‌ها را تعيين كنيد، براي نشان دادن تمام آن‌ها خالي بگذاريد)
+',
+       'entree_sousrub_cond' => 'فقط نمايش زيربخش‌هاي بخش فعلي (بگذاريد «بله»، در غيراينصورت خالي بگذاريد)',
+       'entree_suivant_connexion' => 'منحصر سازي مدخل بعدي به اتصال (بگذاريد «اتصال» براي نمايش فقط اگر بازديد كننده متصل باشد، بگذاريد «قطع» براي مورد عكس، يا خالي بگذاريد تا هميشه نشان داده شود).
+', # MODIF
+       'entree_suivant_connexion_connecte' => 'فقط اگر متصل باشد',
+       'entree_suivant_connexion_deconnecte' => 'فقط اگر قطع باشد',
+       'entree_sur_n_articles' => '@n@ مقاله‌ي منتشره',
+       'entree_sur_n_mots' => '@n@ كلمه‌هاي منتشره ',
+       'entree_sur_n_niveaux' => 'تحت @n@ سطح',
+       'entree_titre' => 'تيتر',
+       'entree_titre_connecter' => 'تيتر براي دستيابي به فرم شناسايي',
+       'entree_titre_prive' => 'تيتر براي دسترسي به قسمت شخصي',
+       'entree_traduction_articles_rubriques' => 'در صورت امكان، نمايش مقاله‌هاي اين بخش به زبان متن («ترجمه» (trad) را براي اينكار بگذاريد)',
+       'entree_traduction_objet' => 'در مور مقاله، ترجمه را در ارتباط با آن متن انتخاب كنيد (براي آن trad را بگذاريد)',
+       'entree_tri_alpha' => ' معيار مرتب كردن بخش‌ها (الفبايي). اگر «تاريخ»"date" را تايپ كنيد، معيار اضافه شده (طبق تاريخ)‌ {par date}خواهد بدو بخش‌ها طبق ترايخ مرتب خواهند شد
+',
+       'entree_tri_alpha_articles' => 'مرتب‌ سازي معيارهاي مقاله‌ها (الفبايي). اگر «تاريخ» را تايپ كنيد، معيار افزوده شده {طبق تاريخ}خواهد بودو مقاله بر اساس تاريخ مرتب خواهد شد
+
+',
+       'entree_tri_alpha_articles_inverse' => 'معكس سازي مرتب‌سازي الفبايي؟ («بله» را براي آن بگذاريد)',
+       'entree_tri_alpha_inverse' => 'معكوس سازي مرتب‌سازي الفبايي؟ (براي آن «بله» بگذاريد)',
+       'entree_tri_num' => 'معيار مرتب كردن بخش‌ها (رقم). اگر «تيتر» را تايپ كنيد، معيار افزوده شده (طبق تيتر) {par num titre}خواهد بود و بخش‌ها بر اساس شماره تيتر‌ها مرتب خواهند شد
+',
+       'entree_tri_num_articles' => 'مرتب‌سازي مقاله‌ها (شماره‌اي). اگر «تيتر» را تايپ كنيد، معيار افزوده شده {طبق تيتر} خواهد بود و مقاله‌ها طبق شماره‌ي تيتر مرتب خواهند شد',
+       'entree_tri_num_articles_inverse' => 'معكوس سازي مرتب‌سازي بخش‌؟ (براي آن «بله» بگذاريد)',
+       'entree_tri_num_inverse' => 'معكوس سازي مرتب‌سازي شماره‌اي؟ (براي آن «بله» بگذاريد)',
+       'entree_type_objet' => 'نوع اوبژه',
+       'entree_url' => 'نشاني (يو.آر.ال) سايت شما',
+       'entree_url_public' => 'نشاني بازگشت بعد از اتصال ',
+       'erreur_aucun_type' => 'هيچ نوع مدخلي يافت نشد.',
+       'erreur_autorisation' => 'شما مجاز به اصلاح منيوي سايت نيستيد.',
+       'erreur_identifiant_deja' => 'از اين شناسه يك منيوي ديگر استفاده مي‌كند',
+       'erreur_identifiant_forme' => 'شناسه بايد فقط از حروف، رقم، و خط‌ زير تركيب شده باشد.',
+       'erreur_menu_inexistant' => 'منيوي درخواستي شماره @id@ موجود نيست.',
+       'erreur_mise_a_jour' => 'هنگام به هنگام سازي پايگاه داده‌ها خطايي رخ داده است.',
+       'erreur_parametres' => 'در پارامتر‌هاي صفحه خطايي وجود دارد',
+       'erreur_type_menu' => 'بايد نوعي از منيو را انتخاب كنيد',
+       'erreur_type_menu_inexistant' => 'اين نوع مينو فعلا/ديگر در دسترس نيست',
+
+       // F
+       'formulaire_ajouter_entree' => 'يك مدخل اضافه كنيد',
+       'formulaire_ajouter_sous_menu' => 'ايجاد يك زيرمنيو',
+       'formulaire_css' => 'سي.اس.اس طبقات',
+       'formulaire_css_explication' => 'مي‌توانيد به منيوي خود طبقات سي.اس.اس تكميلي اضافه كنيد.',
+       'formulaire_deplacer_bas' => 'حركت به پائين',
+       'formulaire_deplacer_haut' => 'حركت به بالا',
+       'formulaire_facultatif' => 'دلبخواهي ',
+       'formulaire_identifiant' => 'شناسه',
+       'formulaire_identifiant_explication' => 'يك كليدواژه‌ي منحصر به فرد بدهيد تا بتوانيد منيوي خود را به راحتي فرابخوانيد.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'منيو‌هايي را كه مي‌خواهيد صادر كنيد انخاب كنيد',
+       'formulaire_ieconfig_importer' => 'واردات',
+       'formulaire_ieconfig_menu_meme_identifiant' => 'توجه: يك منيو با همين شناسه در سايت شما موجود است!',
+       'formulaire_ieconfig_menus_a_exporter' => 'منيو‌هاي صادراتي:',
+       'formulaire_ieconfig_ne_pas_importer' => 'وارد نكردن',
+       'formulaire_ieconfig_remplacer' => 'جايگزين سازي منيوي موجود با منوي وارداتي',
+       'formulaire_ieconfig_renommer' => 'تجديد نام اين منيو پيش از واردات',
+       'formulaire_importer' => 'واردسازي يك منيو',
+       'formulaire_importer_explication' => 'اگر يك منيو را داخل يك پرونده صادر كرده باشيد، مي‌توانيد آن را اكنون وارد كنيد.',
+       'formulaire_modifier_entree' => 'اصلاح اين مدخل',
+       'formulaire_modifier_menu' => 'اصلاح منيو:',
+       'formulaire_nouveau' => 'منيوي جديد',
+       'formulaire_partie_construction' => 'ساخت منيو',
+       'formulaire_partie_identification' => 'شناسه‌ي منيو',
+       'formulaire_supprimer_entree' => 'حذف اين مدخل
+
+',
+       'formulaire_supprimer_menu' => 'حذف منيو',
+       'formulaire_supprimer_sous_menu' => 'حذف اين زيرمنيو',
+       'formulaire_titre' => 'تيتر',
+
+       // I
+       'info_afficher_articles' => 'مقاله‌ها در منيو گنجانده خواهند شد',
+       'info_articles_max' => 'فقط اگر بخش بيش از @max@مقاله داشته باشد',
+       'info_articles_max_affiches' => 'نمايش محدود به @max@ مقاله ',
+       'info_classe_parent' => 'طبقه‌ي عناصر والد‌:',
+       'info_connexion_obligatoire' => 'اتصال اجباري',
+       'info_deconnexion_obligatoire' => 'فقط هنگام قطعي',
+       'info_masquer_articles_uniques' => 'منحصراً مقاله‌هاي پنهان',
+       'info_numero_menu' => 'منيوي شماره‌ي: ',
+       'info_page_speciale' => 'پيوند به صفحه‌ي  «@page@»',
+       'info_page_speciale_zajax' => 'مدال باكس صفحه‌ي  «@page@» براي بلوك «@bloc@»   ',
+       'info_rubrique_courante' => 'بخش فعلي',
+       'info_rubriques_exclues' => '/به جز بخش‌(هاي)@id_rubriques@ ',
+       'info_rubriques_max_affichees' => 'نمايش محدود به @max@ بخش‌ها',
+       'info_secteur_exclus' => '/به جز بخ‌ش (هاي) @id_secteur@',
+       'info_sousrub_cond' => 'فقط زيربخش‌هاي بخش‌هاي فعلي نمايش داده مي‌شوند.',
+       'info_tous_groupes_mots' => 'تمام گروه‌ واژه‌ها',
+       'info_traduction_recuperee' => 'متن ترجمه‌ي منتخب را تعيين خواهد كرد',
+       'info_tri' => 'ترتيب بخش‌ها:‌',
+       'info_tri_alpha' => '(الفبايي)',
+       'info_tri_articles' => 'مرتب‌ سازي مقاله‌ها:',
+       'info_tri_num' => '(شماره‌اي)',
+
+       // N
+       'noisette_description' => 'گنجاندن منيوي تعريف شده با پلاگين منو‌ها.',
+       'noisette_label_afficher_titre_menu' => 'نمايش تيتر منيو؟',
+       'noisette_label_identifiant' => 'منيو براي نمايش: ',
+       'noisette_nom_noisette' => 'منيو',
+       'nom_menu_accueil' => 'پذيرش',
+       'nom_menu_articles_rubrique' => 'مقاله‌هاي يك بخش',
+       'nom_menu_deconnecter' => 'قطع شدن',
+       'nom_menu_espace_prive' => 'اتصال/ پيوند به قسمت شخصي',
+       'nom_menu_groupes_mots' => 'كليدواژه‌ها و مقاله‌هاي يك گروه‌ واژه',
+       'nom_menu_lien' => 'پيوند دلبخواهي',
+       'nom_menu_mapage' => 'صفحه‌ من',
+       'nom_menu_mots' => 'مقاله‌هاي يك كليد واژه',
+       'nom_menu_objet' => 'مقاله، بخش يا ساير چيزهاي اسپيپي ',
+       'nom_menu_page_speciale' => 'پيوند به يك صفحه‌ي اسكلت',
+       'nom_menu_page_speciale_zajax' => 'يك بلوك از صفحه‌ي ازپيپ',
+       'nom_menu_rubriques_completes' => 'Liste ou arborescence de rubriques et d\'articles (avec beaucoup d\'options)', # NEW
+       'nom_menu_rubriques_evenements' => 'برنامه‌هاي مربوط به بخش‌ها',
+       'nom_menu_secteurlangue' => 'بخش‌هاي زباني ',
+       'nom_menu_texte_libre' => 'متن آزاد',
+
+       // T
+       'tous_les_articles' => '...تمام مقاله‌ها',
+       'toutes_les_rubriques' => '...تمام بخش‌ها'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_fr.php b/www/plugins/menus_1/lang/menus_fr.php
new file mode 100644 (file)
index 0000000..66a59d2
--- /dev/null
@@ -0,0 +1,172 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/menus/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'Voulez-vous vraiment supprimer cette entrée ?',
+
+       // D
+       'description_menu_accueil' => 'Lien vers la page d\'accueil du site.',
+       'description_menu_articles_rubrique' => 'Affiche la liste des articles d\'une rubrique.',
+       'description_menu_deconnecter' => 'Si le visiteur est connecté, ajoute une entrée lui proposant la déconnexion.',
+       'description_menu_espace_prive' => 'Lien permettant de se connecter au site si on ne l\'est pas déjà, puis d\'aller dans l\'espace privé si l\'on y est autorisé.',
+       'description_menu_groupes_mots' => 'Affiche automatiquement un menu listant les mots du groupe et les articles liés. Par défaut, affiche la liste des groupes de mots et les mots liés. Si un squelette groupes_mots.html existe, le lien vers le groupe est utilisé.',
+       'description_menu_lien' => 'Ajoute un lien arbitraire, en interne (URL relative) ou externe (http://...).',
+       'description_menu_mapage' => 'Si le visiteur est connecté, ajoute un lien vers sa page auteur.',
+       'description_menu_mots' => 'Affiche automatiquement un menu listant les articles liés au mot clé.',
+       'description_menu_objet' => 'Crée un lien vers un objet de SPIP : article, rubrique ou autre. Par défaut, l\'entrée aura le titre de l\'objet.',
+       'description_menu_page_speciale' => 'Ajoute un lien vers un squelette page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ces pages sont souvent fournies par des plugins.',
+       'description_menu_page_speciale_zajax' => 'Ajoute un lien vers un bloc d\'une page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ceci nécéssite une squelette de type Z et le plugin <a href="http://www.spip-contrib.net/MediaBox">médiabox</a>.',
+       'description_menu_rubriques_articles' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques et les articles sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement). Les articles sont placés systématiquement après les rubriques.',
+       'description_menu_rubriques_completes' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).',
+       'description_menu_secteurlangue' => 'Cette entrée est spécifique aux sites utilisant un secteur par langue. Elle affiche automatiquement un menu listant les rubriques du secteur correspondant à la langue de la page et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).',
+       'description_menu_texte_libre' => 'Simplement le texte que vous souhaitez, ou un code de langue SPIP (<:...:>)',
+
+       // E
+       'editer_menus_editer' => 'Modifier ce menu',
+       'editer_menus_explication' => 'Créez et configurez ici les menus de votre site.',
+       'editer_menus_exporter' => 'Exporter ce menu',
+       'editer_menus_nouveau' => 'Créer un nouveau menu',
+       'editer_menus_titre' => 'Menus du site',
+       'entree_afficher_articles' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)',
+       'entree_afficher_item_suite' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)',
+       'entree_articles_max' => 'Si oui, afficher les articles seulement si la rubrique contient au maximum xx articles ? (mettre le nombre maximum d\'articles, laissez vide pour afficher tous les articles)',
+       'entree_articles_max_affiches' => 'Si oui, limiter le nombre d\'articles listés à xx maximum (suivis d\'un item "... Tous les articles" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum d\'articles, laissez vide pour afficher tous les articles)',
+       'entree_aucun' => 'Aucun',
+       'entree_bloc' => 'Bloc Zpip',
+       'entree_choisir' => 'Choisissez le type d\'entrée que vous voulez ajouter :',
+       'entree_classe_parent' => 'Classe des liens des éléments parents. Cette classe sera rajoutée aux li>a ayant une suite ul/li. Par exemple, si vous saisissez "daddy", cela vous permet d\'utiliser le plugin menu deroulant 2 pour la mise en forme du menu.',
+       'entree_connexion_objet' => 'Obliger à être connecté (mettre "session") ou déconnecté (mettre "nosession") pour voir l\'objet',
+       'entree_contenu' => 'Contenu',
+       'entree_css' => 'Classes CSS de l\'entrée (du conteneur)',
+       'entree_css_lien' => 'Classes CSS du lien',
+       'entree_id_groupe' => 'Numéro du groupe de mot clé',
+       'entree_id_mot' => 'Numéro du mot clé',
+       'entree_id_objet' => 'Numéro',
+       'entree_id_rubrique' => 'Numéro de la rubrique parente',
+       'entree_id_rubrique_ou_courante' => 'Numéro de la rubrique parente ou "courante" si la rubrique parente est la rubrique courante du contexte',
+       'entree_id_rubriques_exclues' => 'Numéros des rubriques à exclure, séparés par des virgules',
+       'entree_id_secteur_exclus' => 'Numéros des secteurs à exclure, séparés par des virgules',
+       'entree_infini' => 'À l\'infini',
+       'entree_mapage' => 'Ma page perso',
+       'entree_masquer_articles_uniques' => 'Si oui et si une rubrique contient un seul article, le masquer ? (mettre "oui" pour cela)',
+       'entree_niveau' => 'Niveau des sous-rubriques',
+       'entree_nombre_articles' => 'Nombre d\'articles au maximum (0 par défaut)',
+       'entree_page' => 'Nom de la page',
+       'entree_parametres' => 'Liste des paramètres',
+       'entree_rubriques_max_affichees' => 'Si oui, limiter le nombre de rubriques listés à xx maximum (suivis d\'un item "... Toutes les rubriques" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum de rubriques, laissez vide pour afficher toutes les rubriques)',
+       'entree_sousrub_cond' => 'N\'afficher que les sous-rubriques de la rubrique en cours (mettre "oui", sinon laisser vide)',
+       'entree_suivant_connexion' => 'Restreindre cette entrée suivant la connexion (mettre "connecte" pour afficher seulement si le visiteur est connecté, "deconnecte" pour le cas contraire, mettre "admin" si l\'auteur est administrateur ou laisser vide pour toujours afficher)',
+       'entree_suivant_connexion_connecte' => 'seulement si connecté',
+       'entree_suivant_connexion_deconnecte' => 'seulement si déconnecté',
+       'entree_sur_n_articles' => '@n@ articles affiché(s)',
+       'entree_sur_n_mots' => '@n@ mots affiché(s)',
+       'entree_sur_n_niveaux' => 'Sur @n@ niveau(x)',
+       'entree_titre' => 'Titre',
+       'entree_titre_connecter' => 'Titre pour l\'accès au formulaire d\'identification',
+       'entree_titre_prive' => 'Titre pour accéder à l\'espace privé',
+       'entree_traduction_articles_rubriques' => 'Dans la mesure du possible, afficher les articles de la rubrique dans la langue du contexte (mettre "trad" pour cela)',
+       'entree_traduction_objet' => 'Dans le cas d\'un article, choisir la traduction en fonction du contexte (mettre "trad" pour cela)',
+       'entree_tri_alpha' => 'Critère de tri des rubriques (alphabétique). Si vous saisissez "date", le critère ajouté sera {par date} et les rubriques seront triées par date',
+       'entree_tri_alpha_articles' => 'Critère de tri des articles (alphabétique). Si vous saisissez "date", le critère ajouté sera {par date} et les articles seront triés par date',
+       'entree_tri_alpha_articles_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)',
+       'entree_tri_alpha_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)',
+       'entree_tri_num' => 'Critère de tri des rubriques (numérique). Si vous saisissez "titre", le critère ajouté sera {par num titre} et les rubriques seront triées par numéro de titre',
+       'entree_tri_num_articles' => 'Critère de tri des articles (numérique). Si vous saisissez "titre", le critère ajouté sera {par num titre} et les articles seront triés par numéro de titre',
+       'entree_tri_num_articles_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)',
+       'entree_tri_num_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)',
+       'entree_type_objet' => 'Type de l\'objet',
+       'entree_url' => 'Adresse',
+       'entree_url_public' => 'Adresse de retour après la connexion',
+       'erreur_aucun_type' => 'Aucun type d\'entrée n\'a été trouvé.',
+       'erreur_autorisation' => 'Vous n\'êtes pas autorisé à modifier les menus.',
+       'erreur_identifiant_deja' => 'Cet identifiant est déjà utilisé par un menu.',
+       'erreur_identifiant_forme' => 'L\'identifiant ne doit contenir que des lettres, des chiffres ou le caractère souligné.',
+       'erreur_menu_inexistant' => 'Le menu demandé numéro @id@ n\'existe pas.',
+       'erreur_mise_a_jour' => 'Une erreur s\'est produite pendant la mise à jour de la base de donnée.',
+       'erreur_parametres' => 'Il y a une erreur dans les paramètres de la page',
+       'erreur_type_menu' => 'Vous devez choisir un type de menu',
+       'erreur_type_menu_inexistant' => 'Ce type de menu n\'est pas/plus disponible',
+
+       // F
+       'formulaire_ajouter_entree' => 'Ajouter une entrée',
+       'formulaire_ajouter_sous_menu' => 'Créer un sous-menu',
+       'formulaire_css' => 'Classes CSS',
+       'formulaire_css_explication' => 'Vous pouvez ajouter au menu d\'éventuelles classes CSS supplémentaires.',
+       'formulaire_deplacer_bas' => 'Déplacer vers le bas',
+       'formulaire_deplacer_haut' => 'Déplacer vers le haut',
+       'formulaire_facultatif' => 'Facultatif',
+       'formulaire_identifiant' => 'Identifiant',
+       'formulaire_identifiant_explication' => 'Donnez un mot-clé unique qui vous permettra d\'appeler votre menu facilement.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Choisissez quel(s) menu(s) vous souhaitez importer.',
+       'formulaire_ieconfig_importer' => 'Importer',
+       'formulaire_ieconfig_menu_meme_identifiant' => 'ATTENTION : un menu avec le même identifiant existe déjà sur votre votre site !',
+       'formulaire_ieconfig_menus_a_exporter' => 'Menus à exporter :',
+       'formulaire_ieconfig_ne_pas_importer' => 'Ne pas importer',
+       'formulaire_ieconfig_remplacer' => 'Remplacer le menu actuel par le menu importé',
+       'formulaire_ieconfig_renommer' => 'Renommer ce menu avant import',
+       'formulaire_importer' => 'Importer un menu',
+       'formulaire_importer_explication' => 'Si vous avez exporté un menu dans un fichier, vous pouvez l\'importer maintenant.',
+       'formulaire_modifier_entree' => 'Modifier cette entrée',
+       'formulaire_modifier_menu' => 'Modifier le menu :',
+       'formulaire_nouveau' => 'Nouveau menu',
+       'formulaire_partie_construction' => 'Construction du menu',
+       'formulaire_partie_identification' => 'Identification du menu',
+       'formulaire_supprimer_entree' => 'Supprimer cette entrée',
+       'formulaire_supprimer_menu' => 'Supprimer le menu',
+       'formulaire_supprimer_sous_menu' => 'Supprimer ce sous-menu',
+       'formulaire_titre' => 'Titre',
+
+       // I
+       'info_afficher_articles' => 'Les articles seront inclus dans le menu.',
+       'info_articles_max' => 'Seulement si la rubrique contient au plus @max@ articles',
+       'info_articles_max_affiches' => 'Affichage limité à @max@ articles',
+       'info_classe_parent' => 'Classe des éléments parents : ',
+       'info_connexion_obligatoire' => 'Connexion obligatoire',
+       'info_deconnexion_obligatoire' => 'Uniquement déconnecté',
+       'info_masquer_articles_uniques' => 'Articles uniques masqués',
+       'info_numero_menu' => 'MENU NUMÉRO :',
+       'info_page_speciale' => 'Lien vers la page « @page@ »',
+       'info_page_speciale_zajax' => 'Modalbox de la page « @page@ » pour le bloc « @bloc@ &#187',
+       'info_rubrique_courante' => 'Rubrique courante',
+       'info_rubriques_exclues' => ' / sauf rubrique(s) @id_rubriques@',
+       'info_rubriques_max_affichees' => 'Affichage limité à @max@ rubriques',
+       'info_secteur_exclus' => ' / sauf secteur(s) @id_secteur@',
+       'info_sousrub_cond' => 'Seules les sous-rubriques de la rubriques en cours sont affichées.',
+       'info_tous_groupes_mots' => 'Tous les groupes de mots',
+       'info_traduction_recuperee' => 'Le contexte décidera de la traduction choisie',
+       'info_tri' => 'Tri des rubriques :',
+       'info_tri_alpha' => '(alphabétique)',
+       'info_tri_articles' => 'Tri des articles :',
+       'info_tri_num' => '(numérique)',
+
+       // N
+       'noisette_description' => 'Insère un menu défini avec le plugin Menus.',
+       'noisette_label_afficher_titre_menu' => 'Afficher le titre du menu ?',
+       'noisette_label_identifiant' => 'Menu à afficher :',
+       'noisette_nom_noisette' => 'Menu',
+       'nom_menu_accueil' => 'Accueil',
+       'nom_menu_articles_rubrique' => 'Articles d\'une rubrique',
+       'nom_menu_deconnecter' => 'Se déconnecter',
+       'nom_menu_espace_prive' => 'Se connecter / lien vers espace privé',
+       'nom_menu_groupes_mots' => 'Mots-clés et Articles d\'un Groupes de mots',
+       'nom_menu_lien' => 'Lien arbitraire',
+       'nom_menu_mapage' => 'Ma page',
+       'nom_menu_mots' => 'Articles d\'un Mot-clé',
+       'nom_menu_objet' => 'Article, rubrique ou autre objet SPIP',
+       'nom_menu_page_speciale' => 'Lien vers un squelette page',
+       'nom_menu_page_speciale_zajax' => 'Un bloc d\'une page Zpip',
+       'nom_menu_rubriques_completes' => 'Liste ou arborescence de rubriques et d\'articles (avec beaucoup d\'options)',
+       'nom_menu_rubriques_evenements' => 'Événements de rubriques',
+       'nom_menu_secteurlangue' => 'Secteurs de langue',
+       'nom_menu_texte_libre' => 'Texte libre',
+
+       // T
+       'tous_les_articles' => '... Tous les articles',
+       'toutes_les_rubriques' => '... Toutes les rubriques'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_it.php b/www/plugins/menus_1/lang/menus_it.php
new file mode 100644 (file)
index 0000000..a317d1b
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'Voulez-vous vraiment supprimer cette entrée ?', # NEW
+
+       // D
+       'description_menu_accueil' => 'Link verso il pannello di controllo del sito.',
+       'description_menu_articles_rubrique' => 'Mostra la lista degli articoli di una rubrica.',
+       'description_menu_deconnecter' => 'Se il visitatore è connesso, aggiungi un link per proporgli la disconnessione.',
+       'description_menu_espace_prive' => 'Link che permette di connettersi al sito se non lo si è già, e poi di andare in redazione se si è autorizzati.',
+       'description_menu_groupes_mots' => 'Mostra automaticamente un menu che elenca le parole chiave di un gruppo e gli articoli collegati. Normalmente, mostra la lista dei gruppi di parole chiave e le parole collegate. Se un modello groupes_mots.html esiste, il link verso il gruppo verrà utilizzato',
+       'description_menu_lien' => 'Aggiunge un link arbitrario, interno (URL relativo) o esterno (http://...).',
+       'description_menu_mapage' => 'Se il visitatore è connesso, aggiunge un link verso la sua pagina autore.',
+       'description_menu_mots' => 'Mostra automaticamente un menù che elenca gli articoli collegati alla parola chiave.',
+       'description_menu_objet' => 'Crea un link verso un oggetto di SPIP: articolo, rubrica o altro. In maniera predefinita, il link avrà il titolo dell\'oggetto.',
+       'description_menu_page_speciale' => 'Aggiunge un link verso un modello accessibile con un url del tipo <code>spip.php?page=nome&param1=xx&param2=yyy...</code> Queste pagina sono spesso fornite dai plugin.',
+       'description_menu_page_speciale_zajax' => 'Ajoute un lien vers un bloc d\'une page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ceci nécéssite une squelette de type Z et le plugin <a href="http://www.spip-contrib.net/MediaBox">médiabox</a>.', # NEW
+       'description_menu_rubriques_articles' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques et les articles sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement). Les articles sont placés systématiquement après les rubriques.', # NEW
+       'description_menu_rubriques_completes' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).', # NEW
+       'description_menu_secteurlangue' => 'Questa voce è specifica per i siti che utilizzano un settore per lingua. Mostra automaticamente un menù che elenca le rubriche del settore corrispondente alla lingua della pagina e, se si vuole, le sotto rubriche su più livelli. Normalmente, mostra tutte le rubriche dalla radice, ordinate per titolo (numericamente e poi alfabeticamente).',
+       'description_menu_texte_libre' => 'Simplement le texte que vous souhaitez, ou un code de langue SPIP (<:...:>)', # NEW
+
+       // E
+       'editer_menus_editer' => 'Modifica questo menù',
+       'editer_menus_explication' => 'Crea e configura qui i menù del tuo sito',
+       'editer_menus_exporter' => 'Esporta questo menù',
+       'editer_menus_nouveau' => 'Crea un nuovo menù',
+       'editer_menus_titre' => 'Menù del sito',
+       'entree_afficher_articles' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_afficher_item_suite' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_articles_max' => 'Si oui, afficher les articles seulement si la rubrique contient au maximum xx articles ? (mettre le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_articles_max_affiches' => 'Si oui, limiter le nombre d\'articles listés à xx maximum (suivis d\'un item "... Tous les articles" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_aucun' => 'Nessun',
+       'entree_bloc' => 'Bloc Zpip', # NEW
+       'entree_choisir' => 'Scegli il tipo di voce che vuoi aggiungere:',
+       'entree_classe_parent' => 'Classe des liens des éléments parents. Cette classe sera rajoutée aux li>a ayant une suite ul/li. Par exemple, si vous saisissez "daddy", cela vous permet d\'utiliser le plugin menu deroulant 2 pour la mise en forme du menu.', # NEW
+       'entree_connexion_objet' => 'Obliger à être connecté (mettre "session") ou déconnecté (mettre "nosession") pour voir l\'objet', # NEW
+       'entree_contenu' => 'Contenu', # NEW
+       'entree_css' => 'Classi CSS della voce', # MODIF
+       'entree_css_lien' => 'Classes CSS du lien', # NEW
+       'entree_id_groupe' => 'Numero di gruppo della parola chiave',
+       'entree_id_mot' => 'Numero della parola chiave',
+       'entree_id_objet' => 'Numero',
+       'entree_id_rubrique' => 'Numero della rubrica padre',
+       'entree_id_rubrique_ou_courante' => 'Numéro de la rubrique parente ou "courante" si la rubrique parente est la rubrique courante du contexte', # NEW
+       'entree_id_rubriques_exclues' => 'Numéros des rubriques à exclure, séparés par des virgules', # NEW
+       'entree_id_secteur_exclus' => 'Numéros des secteurs à exclure, séparés par des virgules', # NEW
+       'entree_infini' => 'All\'infinito',
+       'entree_mapage' => 'La mia pagina personale',
+       'entree_masquer_articles_uniques' => 'Si oui et si une rubrique contient un seul article, le masquer ? (mettre "oui" pour cela)', # NEW
+       'entree_niveau' => 'Livelli di sotto rubriche',
+       'entree_nombre_articles' => 'Numero massimo di articoli (0 predefinito)',
+       'entree_page' => 'Nome della pagina',
+       'entree_parametres' => 'Lista dei parametri',
+       'entree_rubriques_max_affichees' => 'Si oui, limiter le nombre de rubriques listés à xx maximum (suivis d\'un item "... Toutes les rubriques" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum de rubriques, laissez vide pour afficher toutes les rubriques)', # NEW
+       'entree_sousrub_cond' => 'N\'afficher que les sous-rubriques de la rubrique en cours (mettre "oui", sinon laisser vide)', # NEW
+       'entree_suivant_connexion' => 'Restreindre cette entrée suivant la connexion (mettre "connecte" pour afficher seulement si le visiteur est connecté, "deconnecte" pour le cas contraire, ou laisser vide pour toujours afficher)', # NEW
+       'entree_suivant_connexion_connecte' => 'seulement si connecté', # NEW
+       'entree_suivant_connexion_deconnecte' => 'seulement si déconnecté', # NEW
+       'entree_sur_n_articles' => '@n@ articoli mostrati',
+       'entree_sur_n_mots' => '@n@ parole chiave mostrate',
+       'entree_sur_n_niveaux' => 'Su @n@ livelli',
+       'entree_titre' => 'Titolo',
+       'entree_titre_connecter' => 'Titolo per l\'accesso al form di login',
+       'entree_titre_prive' => 'Titolo per accedere alla redazione',
+       'entree_traduction_articles_rubriques' => 'Dans la mesure du possible, afficher les articles de la rubrique dans la langue du contexte (mettre "trad" pour cela)', # NEW
+       'entree_traduction_objet' => 'Dans le cas d\'un article, choisir la traduction en fonction du contexte (mettre "trad" pour cela)', # NEW
+       'entree_tri_alpha' => 'Criterio di ordinamento (alfabetico)', # MODIF
+       'entree_tri_alpha_articles' => 'Critère de tri des articles (alphabétique). Si vous saisissez "date", le critère ajouté sera {par date} et les articles seront triés par date', # NEW
+       'entree_tri_alpha_articles_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_alpha_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num' => 'Criterio di ordinamento (numerico)', # MODIF
+       'entree_tri_num_articles' => 'Critère de tri des articles (numérique). Si vous saisissez "titre", le critère ajouté sera {par num titre} et les articles seront triés par numéro de titre', # NEW
+       'entree_tri_num_articles_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_type_objet' => 'Tipo di oggetto',
+       'entree_url' => 'Indirizzo',
+       'entree_url_public' => 'Adresse de retour après la connexion', # NEW
+       'erreur_aucun_type' => 'Nessun tipo di voce trovata.',
+       'erreur_autorisation' => 'Non sei autorizzato a modificare i menù.',
+       'erreur_identifiant_deja' => 'Questo identificativo è già utilizzato da un menù.',
+       'erreur_identifiant_forme' => 'L\'identificativo deve contenere solo lettere, cifre o il trattino basso.',
+       'erreur_menu_inexistant' => 'Il menù richiesto numero @id@ non esiste.',
+       'erreur_mise_a_jour' => 'Si è verificato un errore durante l\'aggiornamento del database.',
+       'erreur_parametres' => 'C\'è un errore nei parametri della pagina',
+       'erreur_type_menu' => 'Devi scegliere un tipo di menù',
+       'erreur_type_menu_inexistant' => 'Ce type de menu n\'est pas/plus disponible', # NEW
+
+       // F
+       'formulaire_ajouter_entree' => 'Aggiungi una voce',
+       'formulaire_ajouter_sous_menu' => 'Crea un sotto menù',
+       'formulaire_css' => 'Classi CSS',
+       'formulaire_css_explication' => 'Puoi aggiungere al menù delle eventuali classi CSS supplmentari.',
+       'formulaire_deplacer_bas' => 'Sposta verso il basso',
+       'formulaire_deplacer_haut' => 'Sposta verso l\'alto',
+       'formulaire_facultatif' => 'Facoltativo',
+       'formulaire_identifiant' => 'Identificativo',
+       'formulaire_identifiant_explication' => 'Inserisci una parola chiave unica che ti permetterà di richiamare il tuo menù facilmente.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Choisissez quel(s) menu(s) vous souhaitez importer.', # NEW
+       'formulaire_ieconfig_importer' => 'Importer', # NEW
+       'formulaire_ieconfig_menu_meme_identifiant' => 'ATTENTION : un menu avec le même identifiant existe déjà sur votre votre site !', # NEW
+       'formulaire_ieconfig_menus_a_exporter' => 'Menus à exporter :', # NEW
+       'formulaire_ieconfig_ne_pas_importer' => 'Ne pas importer', # NEW
+       'formulaire_ieconfig_remplacer' => 'Remplacer le menu actuel par le menu importé', # NEW
+       'formulaire_ieconfig_renommer' => 'Renommer ce menu avant import', # NEW
+       'formulaire_importer' => 'Importa un menù',
+       'formulaire_importer_explication' => 'Se hai esportato un menù in un file, ora lo puoi importare.',
+       'formulaire_modifier_entree' => 'Modifica questa voce',
+       'formulaire_modifier_menu' => 'Modifica il menù:',
+       'formulaire_nouveau' => 'Nuovo menù',
+       'formulaire_partie_construction' => 'Costruzione del menù',
+       'formulaire_partie_identification' => 'Identificativo del menù',
+       'formulaire_supprimer_entree' => 'Elimina questa voce',
+       'formulaire_supprimer_menu' => 'Elimina il menù',
+       'formulaire_supprimer_sous_menu' => 'Elimina il sotto menù',
+       'formulaire_titre' => 'Titolo',
+
+       // I
+       'info_afficher_articles' => 'Les articles seront inclus dans le menu.', # NEW
+       'info_articles_max' => 'Seulement si la rubrique contient au plus @max@ articles', # NEW
+       'info_articles_max_affiches' => 'Affichage limité à @max@ articles', # NEW
+       'info_classe_parent' => 'Classe des éléments parents : ', # NEW
+       'info_connexion_obligatoire' => 'Connexion obligatoire', # NEW
+       'info_deconnexion_obligatoire' => 'Uniquement déconnecté', # NEW
+       'info_masquer_articles_uniques' => 'Articles uniques masqués', # NEW
+       'info_numero_menu' => 'MENU NUMERO:',
+       'info_page_speciale' => 'Link verso la pagina "@page@"',
+       'info_page_speciale_zajax' => 'Modalbox de la page « @page@ » pour le bloc « @bloc@ &#187', # NEW
+       'info_rubrique_courante' => 'Rubrique courante', # NEW
+       'info_rubriques_exclues' => ' / sauf rubrique(s) @id_rubriques@', # NEW
+       'info_rubriques_max_affichees' => 'Affichage limité à @max@ rubriques', # NEW
+       'info_secteur_exclus' => ' / sauf secteur(s) @id_secteur@', # NEW
+       'info_sousrub_cond' => 'Seules les sous-rubriques de la rubriques en cours sont affichées.', # NEW
+       'info_tous_groupes_mots' => 'Tutti i gruppi di parole chiave',
+       'info_traduction_recuperee' => 'Le contexte décidera de la traduction choisie', # NEW
+       'info_tri' => 'Ordina:', # MODIF
+       'info_tri_alpha' => '(alfabetico)',
+       'info_tri_articles' => 'Tri des articles :', # NEW
+       'info_tri_num' => '(numerico)',
+
+       // N
+       'noisette_description' => 'Insère un menu défini avec le plugin Menus.', # NEW
+       'noisette_label_afficher_titre_menu' => 'Afficher le titre du menu ?', # NEW
+       'noisette_label_identifiant' => 'Menu à afficher :', # NEW
+       'noisette_nom_noisette' => 'Menu', # NEW
+       'nom_menu_accueil' => 'Pannello di controllo',
+       'nom_menu_articles_rubrique' => 'Articoli di una rubrica',
+       'nom_menu_deconnecter' => 'Disconnettersi',
+       'nom_menu_espace_prive' => 'Connettersi / link alla redazione',
+       'nom_menu_groupes_mots' => 'Parole chiave e articoli di un gruppo di parole chiave',
+       'nom_menu_lien' => 'Link arbitrario',
+       'nom_menu_mapage' => 'La mia pagina',
+       'nom_menu_mots' => 'Articoli di un a parola chiave',
+       'nom_menu_objet' => 'Articolo, rubrica o altro oggetto SPIP',
+       'nom_menu_page_speciale' => 'Link verso una pagina di modello',
+       'nom_menu_page_speciale_zajax' => 'Un bloc d\'une page Zpip', # NEW
+       'nom_menu_rubriques_completes' => 'Liste ou arborescence de rubriques et d\'articles (avec beaucoup d\'options)', # NEW
+       'nom_menu_rubriques_evenements' => 'Eventi delle rubriche',
+       'nom_menu_secteurlangue' => 'Settore di lingua',
+       'nom_menu_texte_libre' => 'Texte libre', # NEW
+
+       // T
+       'tous_les_articles' => '... Tous les articles', # NEW
+       'toutes_les_rubriques' => '... Toutes les rubriques' # NEW
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_ru.php b/www/plugins/menus_1/lang/menus_ru.php
new file mode 100644 (file)
index 0000000..eb3441f
--- /dev/null
@@ -0,0 +1,171 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://www.spip.net/trad-lang/
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'Voulez-vous vraiment supprimer cette entrée ?', # NEW
+
+       // D
+       'description_menu_accueil' => 'Ссылка на главную страницу.',
+       'description_menu_articles_rubrique' => 'Affiche la liste des articles d\'une rubrique.', # NEW
+       'description_menu_deconnecter' => 'Si le visiteur est connecté, ajoute une entrée lui proposant la déconnexion.', # NEW
+       'description_menu_espace_prive' => 'Lien permettant de se connecter au site si on ne l\'est pas déjà, puis d\'aller dans l\'espace privé si l\'on y est autorisé.', # NEW
+       'description_menu_groupes_mots' => 'Affiche automatiquement un menu listant les mots du groupe et les articles liés. Par d&eacute;faut, affiche la liste des groupes de mots et les mots li&eacute;s. Si un squelette groupes_mots.html existe, le lien vers le groupe est utilis&eacute;.', # NEW
+       'description_menu_lien' => 'Ajoute un lien arbitraire, en interne (URL relative) ou externe (http://...).', # NEW
+       'description_menu_mapage' => 'Si le visiteur est connecté, ajoute un lien vers sa page auteur.', # NEW
+       'description_menu_mots' => 'Affiche automatiquement un menu listant les articles liés au mot clé.', # NEW
+       'description_menu_objet' => 'Crée un lien vers un objet de SPIP : article, rubrique ou autre. Par défaut, l\'entrée aura le titre de l\'objet.', # NEW
+       'description_menu_page_speciale' => 'Ajoute un lien vers un squelette page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ces pages sont souvent fournies par des plugins.', # NEW
+       'description_menu_page_speciale_zajax' => 'Ajoute un lien vers un bloc d\'une page accessible par une url du type <code>spip.php?page=nom&param1=xx&param2=yyy...</code> Ceci nécéssite une squelette de type Z et le plugin <a href="http://www.spip-contrib.net/MediaBox">médiabox</a>.', # NEW
+       'description_menu_rubriques' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).', # NEW
+       'description_menu_rubriques_articles' => 'Affiche une liste de rubriques et, si on veut, les sous-rubriques et les articles sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement). Les articles sont placés systématiquement après les rubriques.', # NEW
+       'description_menu_secteurlangue' => 'Cette entrée est spécifique aux sites utilisant un secteur par langue. Elle affiche automatiquement un menu listant les rubriques du secteur correspondant à la langue de la page et, si on veut, les sous-rubriques sur plusieurs niveaux. Par défaut, affiche toutes les rubriques depuis la racine, triées par titre (numériquement puis alphabétiquement).', # NEW
+       'description_menu_texte_libre' => 'Simplement le texte que vous souhaitez, ou un code de langue SPIP (<:...:>)', # NEW
+
+       // E
+       'editer_menus_editer' => 'Редактировать это меню',
+       'editer_menus_explication' => 'Создать и настроить меню для сайта',
+       'editer_menus_exporter' => 'Экспортировать меню',
+       'editer_menus_nouveau' => 'Создать новое меню',
+       'editer_menus_titre' => 'Меню сайта',
+       'entree_afficher_articles' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_afficher_item_suite' => 'Inclure les articles dans le menu ? (mettre "oui" pour cela)', # NEW
+       'entree_articles_max' => 'Si oui, afficher les articles seulement si la rubrique contient au maximum xx articles ? (mettre le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_articles_max_affiches' => 'Si oui, limiter le nombre d\'articles list&eacute;s &agrave; xx maximum (suivis d\'un item "... Tous les articles" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum d\'articles, laissez vide pour afficher tous les articles)', # NEW
+       'entree_aucun' => 'Aucun', # NEW
+       'entree_bloc' => 'Bloc Zpip', # NEW
+       'entree_choisir' => 'Выбрать тип пункта меню:',
+       'entree_classe_parent' => 'Classe des liens des éléments parents. Cette classe sera rajoutée aux li>a ayant une suite ul/li. Par exemple, si vous saisissez "daddy", cela vous permet d\'utiliser le plugin menu deroulant 2 pour la mise en forme du menu.', # NEW
+       'entree_connexion_objet' => 'Obliger à être connecté (mettre "session") ou déconnecté (mettre "nosession") pour voir l\'objet', # NEW
+       'entree_contenu' => 'Contenu', # NEW
+       'entree_css' => 'CSS класс', # MODIF
+       'entree_css_lien' => 'Classes CSS du lien', # NEW
+       'entree_id_groupe' => 'Numéro du groupe de mot clé', # NEW
+       'entree_id_mot' => 'Numéro du mot clé', # NEW
+       'entree_id_objet' => 'Номер',
+       'entree_id_rubrique' => 'Номер родительского раздела',
+       'entree_id_rubrique_ou_courante' => 'Numéro de la rubrique parente ou "courante" si la rubrique parente est la rubrique courante du contexte', # NEW
+       'entree_id_rubriques_exclues' => 'Numéros des rubriques à exclure, séparés par des virgules', # NEW
+       'entree_id_secteur_exclus' => 'Numéros des secteurs à exclure, séparés par des virgules', # NEW
+       'entree_infini' => 'Бесконечность',
+       'entree_mapage' => 'Моя страница',
+       'entree_masquer_articles_uniques' => 'Si oui et si une rubrique contient un seul article, le masquer ? (mettre "oui" pour cela)', # NEW
+       'entree_niveau' => 'Уровень подразделов',
+       'entree_nombre_articles' => 'Nombre d\'articles au maximum (0 par défaut)', # NEW
+       'entree_page' => 'Nom de la page', # NEW
+       'entree_parametres' => 'Liste des paramètres', # NEW
+       'entree_rubriques_max_affichees' => 'Si oui, limiter le nombre de rubriques list&eacute;s &agrave; xx maximum (suivis d\'un item "... Toutes les rubriques" comportant un lien vers la rubrique parente) ? (indiquer le nombre maximum de rubriques, laissez vide pour afficher toutes les rubriques)', # NEW
+       'entree_sousrub_cond' => 'N\'afficher que les sous-rubriques de la rubrique en cours (mettre "oui", sinon laisser vide)', # NEW
+       'entree_sur_n_articles' => '@n@ articles affiché(s)', # NEW
+       'entree_sur_n_mots' => '@n@ mots affiché(s)', # NEW
+       'entree_sur_n_niveaux' => 'На @n@ уровне',
+       'entree_titre' => 'Название',
+       'entree_titre_connecter' => 'Titre pour l\'accès au formulaire d\'identification', # NEW
+       'entree_titre_prive' => 'Titre pour accéder à l\'espace privé', # NEW
+       'entree_traduction_articles_rubriques' => 'Dans la mesure du possible, afficher les articles de la rubrique dans la langue du contexte (mettre "trad" pour cela)', # NEW
+       'entree_traduction_objet' => 'Dans le cas d\'un article, choisir la traduction en fonction du contexte (mettre "trad" pour cela)', # NEW
+       'entree_tri_alpha' => 'Critère de tri (alphabétique)', # MODIF
+       'entree_tri_alpha_articles' => 'Critère de tri des articles (alphabétique). Si vous saisissez "date", le critère ajouté sera {par date} et les articles seront triés par date', # NEW
+       'entree_tri_alpha_articles_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_alpha_inverse' => 'Inverser le critère de tri alphabétique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num' => 'Critère de tri (numérique)', # MODIF
+       'entree_tri_num_articles' => 'Critère de tri des articles (numérique). Si vous saisissez "titre", le critère ajouté sera {par num titre} et les articles seront triés par numéro de titre', # NEW
+       'entree_tri_num_articles_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_tri_num_inverse' => 'Inverser le critère de tri numérique ? (mettre "oui" pour cela)', # NEW
+       'entree_type_objet' => 'Тип объекта',
+       'entree_url' => 'Ссылка (URL)',
+       'entree_url_public' => 'Adresse de retour après la connexion', # NEW
+       'erreur_aucun_type' => 'Ничего не найдено.',
+       'erreur_autorisation' => 'У вас нет прав для редактирования этого меню.',
+       'erreur_identifiant_deja' => 'Этот идентификатор уже используется в другом меню.',
+       'erreur_identifiant_forme' => 'Идентификатор может состоять из латинских букв, цифр и подчеркиваний.',
+       'erreur_menu_inexistant' => 'Меню номер @id@ не существует.',
+       'erreur_mise_a_jour' => 'Произошла ошибка при обновлении базы.',
+       'erreur_parametres' => 'Il y a une erreur dans les paramètres de la page', # NEW
+       'erreur_type_menu' => 'Vous devez choisir un type de menu', # NEW
+       'erreur_type_menu_inexistant' => 'Ce type de menu n\'est pas/plus disponible', # NEW
+
+       // F
+       'formulaire_ajouter_entree' => 'Добавить пункт меню',
+       'formulaire_ajouter_sous_menu' => 'Создать подменю',
+       'formulaire_css' => 'CSS классы',
+       'formulaire_css_explication' => 'Вы можете добавить дополнительный классы CSS к вашему меню.',
+       'formulaire_deplacer_bas' => 'Вниз',
+       'formulaire_deplacer_haut' => 'Вверх',
+       'formulaire_facultatif' => 'Не обязательно',
+       'formulaire_identifiant' => 'Идентификатор',
+       'formulaire_identifiant_explication' => 'Назначьте меню уникальное ключевое слово, которое позволит в дальнейшем легко его вызывать.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Choisissez quel(s) menu(s) vous souhaitez importer.', # NEW
+       'formulaire_ieconfig_importer' => 'Importer', # NEW
+       'formulaire_ieconfig_menu_meme_identifiant' => 'ATTENTION : un menu avec le même identifiant existe déjà sur votre votre site !', # NEW
+       'formulaire_ieconfig_menus_a_exporter' => 'Menus à exporter :', # NEW
+       'formulaire_ieconfig_ne_pas_importer' => 'Ne pas importer', # NEW
+       'formulaire_ieconfig_remplacer' => 'Remplacer le menu actuel par le menu importé', # NEW
+       'formulaire_ieconfig_renommer' => 'Renommer ce menu avant import', # NEW
+       'formulaire_importer' => 'Импортировать меню',
+       'formulaire_importer_explication' => 'Если вы экспортировали меню в файл, вы можете импортировать его сейчас.',
+       'formulaire_modifier_entree' => 'Редактировать этот пункт меню',
+       'formulaire_modifier_menu' => 'Редактировать меню:',
+       'formulaire_nouveau' => 'Новое меню',
+       'formulaire_partie_construction' => 'Создание меню',
+       'formulaire_partie_identification' => 'Идентификатор меню',
+       'formulaire_supprimer_entree' => 'Удалить этот пункт меню',
+       'formulaire_supprimer_menu' => 'Удалить меню',
+       'formulaire_supprimer_sous_menu' => 'Удалить подменю',
+       'formulaire_titre' => 'Название',
+
+       // I
+       'info_afficher_articles' => 'Les articles seront inclus dans le menu.', # NEW
+       'info_articles_max' => 'Seulement si la rubrique contient au plus @max@ articles', # NEW
+       'info_articles_max_affiches' => 'Affichage limit&eacute; &agrave; @max@ articles', # NEW
+       'info_classe_parent' => 'Classe des éléments parents : ', # NEW
+       'info_connexion_obligatoire' => 'Connexion obligatoire', # NEW
+       'info_deconnexion_obligatoire' => 'Uniquement déconnecté', # NEW
+       'info_masquer_articles_uniques' => 'Articles uniques masqu&eacute;s', # NEW
+       'info_numero_menu' => 'НОМЕР МЕНЮ:',
+       'info_page_speciale' => 'Lien vers la page « @page@ »', # NEW
+       'info_page_speciale_zajax' => 'Modalbox de la page « @page@ » pour le bloc « @bloc@ &#187', # NEW
+       'info_rubrique_courante' => 'Rubrique courante', # NEW
+       'info_rubriques_exclues' => ' / sauf rubrique(s) @id_rubriques@', # NEW
+       'info_rubriques_max_affichees' => 'Affichage limit&eacute; &agrave; @max@ rubriques', # NEW
+       'info_secteur_exclus' => ' / sauf secteur(s) @id_secteur@', # NEW
+       'info_sousrub_cond' => 'Seules les sous-rubriques de la rubriques en cours sont affichées.', # NEW
+       'info_tous_groupes_mots' => 'Tous les groupes de mots', # NEW
+       'info_traduction_recuperee' => 'Le contexte décidera de la traduction choisie', # NEW
+       'info_tri' => 'Tri :', # MODIF
+       'info_tri_alpha' => '(alphabétique)', # NEW
+       'info_tri_articles' => 'Tri des articles :', # NEW
+       'info_tri_num' => '(numérique)', # NEW
+
+       // N
+       'noisette_description' => 'Insère un menu défini avec le plugin Menus.', # NEW
+       'noisette_label_afficher_titre_menu' => 'Afficher le titre du menu ?', # NEW
+       'noisette_label_identifiant' => 'Menu à afficher :', # NEW
+       'noisette_nom_noisette' => 'Menu', # NEW
+       'nom_menu_accueil' => 'Главная страница',
+       'nom_menu_articles_rubrique' => 'Articles d\'une rubrique', # NEW
+       'nom_menu_deconnecter' => 'Se déconnecter', # NEW
+       'nom_menu_espace_prive' => 'Se connecter / lien vers espace privé', # NEW
+       'nom_menu_groupes_mots' => 'Mots-clés et Articles d\'un Groupes de mots', # NEW
+       'nom_menu_lien' => 'Lien arbitraire', # NEW
+       'nom_menu_mapage' => 'Ma page', # NEW
+       'nom_menu_mots' => 'Articles d\'un Mot-clé', # NEW
+       'nom_menu_objet' => 'Article, rubrique ou autre objet SPIP', # NEW
+       'nom_menu_page_speciale' => 'Lien vers un squelette page', # NEW
+       'nom_menu_page_speciale_zajax' => 'Un bloc d\'une page Zpip', # NEW
+       'nom_menu_rubriques' => 'Liste ou arborescence de rubriques', # MODIF
+       'nom_menu_rubriques_evenements' => 'Événements de rubriques', # NEW
+       'nom_menu_secteurlangue' => 'Secteurs de langue', # NEW
+       'nom_menu_texte_libre' => 'Texte libre', # NEW
+
+       // T
+       'tous_les_articles' => '... Tous les articles', # NEW
+       'toutes_les_rubriques' => '... Toutes les rubriques' # NEW
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/menus_sk.php b/www/plugins/menus_1/lang/menus_sk.php
new file mode 100644 (file)
index 0000000..03a5e23
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/menus?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'confirmer_supprimer_entree' => 'Chcete odstrániť tento záznam?',
+
+       // D
+       'description_menu_accueil' => 'Odkaz na úvodnú stránku webu.',
+       'description_menu_articles_rubrique' => 'Zobraziť zoznam článkov v rubrike.',
+       'description_menu_deconnecter' => 'Ak je návštevník online, pridať možnosť odpojenia.',
+       'description_menu_espace_prive' => 'Odkaz umožňujúci prihlásenie na stránku, ak ste sa ešte neprihlásili a potom na vstup do súkromnej zóny, ak na to máte oprávnenie.',
+       'description_menu_groupes_mots' => 'Automaticky vypíše skupiny kľúčových slov a články, ktoré sú k ním priradené. Podľa predvolených nastavení sa zobrazia skupiny kľúčových slov a kľúčové slová v rámci nich. Ak existuje súbor šablóny groupes_mots.html, použije sa odkaz na skupinu kľúčových slov.',
+       'description_menu_lien' => 'Pridá samostatne zadaný odkaz, a to buď interný (relatívna adresa), alebo externý(http://...).',
+       'description_menu_mapage' => 'Ak je návštevník prihlásený, pridá odkaz na jeho autorskú stránku.',
+       'description_menu_mots' => 'Automaticky zobrazí menu so zoznamom článkov prepojených s kľúčovým slovom.',
+       'description_menu_objet' => 'Vytvorí odkaz na objekt SPIPu: článok, rubriku alebo iný. Podľa predvolených nastavení bude niesť názov objektu.',
+       'description_menu_page_speciale' => 'Pridá odkaz na stránku šablóny pomocou adresy formulára <code>spip.php?page=name&param1=xx&param2=yyy...</code> Takéto stránky často využívajú zásuvné moduly.',
+       'description_menu_page_speciale_zajax' => 'Pridať odkaz do bolu na stránke, na ktorú sa dá dostať progredníctvom adresy typu <code>spip.php?page=name&param1=xx&param2=yyy...</code> Na to treba šablónu typu Z a zásuvný modul <a href="http://www.spip-contrib.net/MediaBox">médiabox.</a>',
+       'description_menu_rubriques_articles' => 'Zobrazí zoznam rubrík, v ktorom môžu byť podrubriky a články včlenené do rôznych úrovní. Podľa predvolených nastavení sa zobrazia všetky rubriky počnúc koreňovým adresárom stránky a budú zotriedené podľa názvu (najprv čísla, potom písmená). Články v danej rubrike budú vždy uvedené po jej podrubrikách.',
+       'description_menu_rubriques_completes' => 'Zobrazí zoznam rubrík a ak existujú, aj podrubrík na mnohých úrovniach. Podľa predvolených nastavení zobrazí všetky rubriky od koreňového adresára zotriedené podľa názvu (najprv podľa čísel potom podľa abecedy).',
+       'description_menu_secteurlangue' => 'This entry can be used by sites which have one language per sector. It displays a menu which lists the sections of the sector corresponding to the language of the page, and if desired the subsections to several levels. By default, all sections are shown from the site root, sorted by title (numerically then alphabetically).',
+       'description_menu_texte_libre' => 'Jednoducho text, ktorý chcete, alebo kód jazyka SPIP (<:...:>)',
+
+       // E
+       'editer_menus_editer' => 'Upraviť toto menu',
+       'editer_menus_explication' => 'Vytvorte a nastavte ponky menu pre svoju stránku.',
+       'editer_menus_exporter' => 'Exportovať toto menu',
+       'editer_menus_nouveau' => 'Vytvoriť nové menu',
+       'editer_menus_titre' => 'Ponuky menu stránky',
+       'entree_afficher_articles' => 'Zaradiť články do menu? (na to využite možnosť "áno")',
+       'entree_afficher_item_suite' => 'Zaradiť články do menu? (použite na to možnosť "áno")',
+       'entree_articles_max' => 'Ak áno, zobraziť články, len ak je v rubrike maximálne xx článkov? (zadajte maximálny počet článkov; ak chcete zobraziť všetky články, nechajte toto pole prázdne)',
+       'entree_articles_max_affiches' => 'Ak áno, obmedziť počet článkov v zozname na maximálne xx (za položkou "...Všetky články" s odkazom na nadradenú rubriku)? (zadajte maximálny počet článkov; ak chcete zobraziť všetky články, nechajte toto pole prázdne)',
+       'entree_aucun' => 'Žiadny',
+       'entree_bloc' => 'Blok Zpipu',
+       'entree_choisir' => 'Vyberte typ položky, ktorú chcete pridať:',
+       'entree_classe_parent' => 'Trieda odkazov nadradených prvkov. Táto trieda bude pridaná na  li>v postupnosit ul/li. Napríklad, ak zadáte "daddy", umožní vám to využiť na formátovanie menu rozbaľovacie menu zásuvného modulu 2.',
+       'entree_connexion_objet' => 'Na zobrazenie objektu sa vyžaduje prihlásenie (vloženie "session") alebo odhlásenie (vloženie "nosession")',
+       'entree_contenu' => 'Obsah',
+       'entree_css' => 'CSS triedy tejto položky (objektu)',
+       'entree_css_lien' => 'Triedy CSS pre odkazy',
+       'entree_id_groupe' => 'Číslo skupiny kľúčových slov',
+       'entree_id_mot' => 'Číslo kľúčového slova',
+       'entree_id_objet' => 'Číslo',
+       'entree_id_rubrique' => 'Číslo nadradenej rubriky',
+       'entree_id_rubrique_ou_courante' => 'Číslo nadradenej alebo "aktuálnej" rubriky, ak nadradená rubrika je aktuálnou rubrikou kontextu',
+       'entree_id_rubriques_exclues' => 'Čísla rubrík, ktoré majú byť vylúčené, oddelené čiarkami',
+       'entree_id_secteur_exclus' => 'Čísla sektorov, ktoré majú byť vylúčené, oddelené čiarkami',
+       'entree_infini' => 'Do nekonečna',
+       'entree_mapage' => 'Moja stránka',
+       'entree_masquer_articles_uniques' => 'Ak áno a ak je v rubrike jeden článok, schovať ju? (ak to tak chcete, označte možnosť "áno")',
+       'entree_niveau' => 'Úroveň podrubrík',
+       'entree_nombre_articles' => 'Maximálny počet článkov (predvolené 0)',
+       'entree_page' => 'Názov stránky',
+       'entree_parametres' => 'Zoznam parametrov',
+       'entree_rubriques_max_affichees' => 'Ak áno, obmedziť počet rubrík v zozname na maximálne xx (po položke "...Všetky rubriky" s odkazom na nadradenú rubriku)? (zadajte maximálny počet rubrík; ak chcete zobraziť všetky rubriky, nechajte toto pole prázdne)',
+       'entree_sousrub_cond' => 'Zobrazovať len podrubriky aktuálnej rubriky (zadajte "oui" (áno), v opačnom prípade nevypĺňajte)',
+       'entree_suivant_connexion' => 'Obmedziť toto pole podľa prihlásenia  (nastavte "prihlásený" ak chcete zobraziť len návštevníka, ktorý je online; možnosť "odhlásený" v opačnom prípade;  ak autor riadi nejakú rubriku, nastavte pole "administrátor"; ak ho chcete zobraziť v každom prípade, toto pole nevypĺňajte)',
+       'entree_suivant_connexion_connecte' => 'len ak je online',
+       'entree_suivant_connexion_deconnecte' => 'len ak je offline',
+       'entree_sur_n_articles' => '@n@ zobrazených článkov',
+       'entree_sur_n_mots' => '@n@ zobrazených kľúčových slov',
+       'entree_sur_n_niveaux' => 'Na @n@ úrovni(ach)',
+       'entree_titre' => 'Nadpis',
+       'entree_titre_connecter' => 'Nadpis pre prístup do prihlasovacieho formulára',
+       'entree_titre_prive' => 'Nadpis pre prístup do súkromnej zóny',
+       'entree_traduction_articles_rubriques' => 'Ak je to možné, zobraziť články rubriky v jazyku textu (na aktiváciu tejto možnosti zadajte "trad")',
+       'entree_traduction_objet' => 'Pri článku vyberajte preklad v závislosti od kontextu (na to, aby se to dosiahli, vložte "trad")',
+       'entree_tri_alpha' => 'Kritérium triedenia (abecedné)',
+       'entree_tri_alpha_articles' => 'Kritérium triedenia článkov(abecedné). Ak zadáte "dátum", bude pridané kritérium {podľa dátumu} a články budú zotriedené podľa dátumu',
+       'entree_tri_alpha_articles_inverse' => 'Obrátiť poradie abecedného triedenia? (použite na to možnosť "áno")',
+       'entree_tri_alpha_inverse' => 'Obrátiť poradie abecedného triedenia? (použite na to možnosť "áno")',
+       'entree_tri_num' => 'Kritérium triedenia (číselné)',
+       'entree_tri_num_articles' => 'Kritérium triedenia článkov (číselné). Ak zadáte "nadpis", bude pridané kritérium {podľa čísla nadpisu} a články budú zotriedené podľa čísla nadpisu',
+       'entree_tri_num_articles_inverse' => 'Obrátiť poradie číselného triedenia? (použite na to možnosť "áno")',
+       'entree_tri_num_inverse' => 'Obrátiť poradie číselného triedenia? (použite na to možnosť "áno")',
+       'entree_type_objet' => 'Typ objektu',
+       'entree_url' => 'Internetová adresa',
+       'entree_url_public' => 'Po prihlásení vypísať adresu',
+       'erreur_aucun_type' => 'Žiaden typ položky sa nenašiel.',
+       'erreur_autorisation' => 'Nemáte povolené upravovať menu.',
+       'erreur_identifiant_deja' => 'Tento identifikátor už využíva iné menu.',
+       'erreur_identifiant_forme' => 'Identifikátor musí obsahovať len písmená, čísla alebo podčiarkovníky.',
+       'erreur_menu_inexistant' => 'Menu číslo @id@ neexistuje.',
+       'erreur_mise_a_jour' => 'Počas aktualizácie databázy došlo k chybe.',
+       'erreur_parametres' => 'V parametroch stránky je chyba',
+       'erreur_type_menu' => 'Musíte si vybrať typ menu',
+       'erreur_type_menu_inexistant' => 'Tento typ menu (už viac) nie je dostupný',
+
+       // F
+       'formulaire_ajouter_entree' => 'Pridať položku menu',
+       'formulaire_ajouter_sous_menu' => 'Vytvoriť podmenu',
+       'formulaire_css' => 'Triedy CSS',
+       'formulaire_css_explication' => 'K svojmu menu môžete pridať ďalšie triedy CSS.',
+       'formulaire_deplacer_bas' => 'Posunúť nadol',
+       'formulaire_deplacer_haut' => 'Posunúť nahor',
+       'formulaire_facultatif' => 'Nepovinné',
+       'formulaire_identifiant' => 'Identifikátor',
+       'formulaire_identifiant_explication' => 'Priraďte mu unikátne kľúčové slovo, ktoré vám umožní ľahko zavolať svoje menu.',
+       'formulaire_ieconfig_choisir_menus_a_importer' => 'Vyberte, ktoré menu chcete nahrať.',
+       'formulaire_ieconfig_importer' => 'Nahrať',
+       'formulaire_ieconfig_menu_meme_identifiant' => 'UPOZORNENIE: na vašej stránke je už menu s rovnakým názvom!',
+       'formulaire_ieconfig_menus_a_exporter' => 'Menu na export:',
+       'formulaire_ieconfig_ne_pas_importer' => 'Nenahrávať',
+       'formulaire_ieconfig_remplacer' => 'Prepísať súčasné menu nahratým menu',
+       'formulaire_ieconfig_renommer' => 'Premenovať toto menu pred nahrávaním',
+       'formulaire_importer' => 'Nahrať menu',
+       'formulaire_importer_explication' => 'Ak ste exportovali menu do súboru, môžete ho teraz nahrať.',
+       'formulaire_modifier_entree' => 'Upraviť túto položku menu',
+       'formulaire_modifier_menu' => 'Upraviť menu:',
+       'formulaire_nouveau' => 'Nové menu',
+       'formulaire_partie_construction' => 'Vytvorenie menu',
+       'formulaire_partie_identification' => 'Identifikácia menu',
+       'formulaire_supprimer_entree' => 'Odstrániť túto položku menu',
+       'formulaire_supprimer_menu' => 'Odstrániť menu',
+       'formulaire_supprimer_sous_menu' => 'Odstrániť toto podmenu',
+       'formulaire_titre' => 'Nadpis',
+
+       // I
+       'info_afficher_articles' => 'Články budú zaradené do menu.',
+       'info_articles_max' => 'Iba ak v rubrike nie je viac ako @max@ článkov',
+       'info_articles_max_affiches' => 'Zobrazenie obmedzené na @max@ článkov',
+       'info_classe_parent' => 'Trieda nadradených prvkov: ',
+       'info_connexion_obligatoire' => 'Vyžaduje sa prihlásenie',
+       'info_deconnexion_obligatoire' => 'Iba keď ste odhlásený',
+       'info_masquer_articles_uniques' => 'Unikátne články skryté',
+       'info_numero_menu' => 'MENU ČÍSLO:',
+       'info_page_speciale' => 'Odkaz na stránku "@page@"',
+       'info_page_speciale_zajax' => 'Modalbox pre stránku "@page@" bloku "@bloc@" ',
+       'info_rubrique_courante' => 'Aktuálna rubrika',
+       'info_rubriques_exclues' => ' /okrem rubriky (-ík) @id_rubriques@',
+       'info_rubriques_max_affichees' => 'Zobrazenie obmedzené na @max@ rubrík',
+       'info_secteur_exclus' => ' /okrem sektora (-ov) @id_secteur@',
+       'info_sousrub_cond' => 'Sú zobrazené iba podrubriky aktuálnej rubriky.',
+       'info_tous_groupes_mots' => 'Všetky skupiny kľúčových slov',
+       'info_traduction_recuperee' => 'Kontext určí vybraný preklad',
+       'info_tri' => 'Triedenie:',
+       'info_tri_alpha' => '(abecedné)',
+       'info_tri_articles' => 'Roztriediť články:',
+       'info_tri_num' => '(číselné)',
+
+       // N
+       'noisette_description' => 'Vkladanie menu definované v zásuvnom module Menus.',
+       'noisette_label_afficher_titre_menu' => 'Zobraziť názov menu?',
+       'noisette_label_identifiant' => 'Menu, ktoré sa má zobraziť:',
+       'noisette_nom_noisette' => 'Menu',
+       'nom_menu_accueil' => 'Úvodná stránka',
+       'nom_menu_articles_rubrique' => 'Články v rubrike',
+       'nom_menu_deconnecter' => 'Odhlásiť sa',
+       'nom_menu_espace_prive' => 'Prihlásenie/odkaz na súkromnú zónu',
+       'nom_menu_groupes_mots' => 'Kľúčové slová a články skupiny kľúčových slov',
+       'nom_menu_lien' => 'Samostatný odkaz',
+       'nom_menu_mapage' => 'Moja stránka',
+       'nom_menu_mots' => 'Články s kľúčovým slovom',
+       'nom_menu_objet' => 'Článok, rubrika alebo iný objekt SPIPU',
+       'nom_menu_page_speciale' => 'Odkaz na šablónu stránky',
+       'nom_menu_page_speciale_zajax' => 'Blok na stránke v SPIPe',
+       'nom_menu_rubriques_completes' => 'Zoznam alebo stromová štruktúra  rubrík a článkov (s mnohými možnosťami)',
+       'nom_menu_rubriques_evenements' => 'Udalosti, ktoré sa týkajú rubriky',
+       'nom_menu_secteurlangue' => 'Jazykové sektory',
+       'nom_menu_texte_libre' => 'Potvrdený text',
+
+       // T
+       'tous_les_articles' => '... Všetky články',
+       'toutes_les_rubriques' => '... Všetky rubriky'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/paquet-menus.xml b/www/plugins/menus_1/lang/paquet-menus.xml
new file mode 100644 (file)
index 0000000..e74acae
--- /dev/null
@@ -0,0 +1,21 @@
+<traduction module="paquet-menus" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/menus/trunk/lang/" reference="fr">
+       <langue code="ar" url="http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=ar">
+               <traducteur nom="George" lien="http://trad.spip.net/auteur/جورج-قندلفت" />
+       </langue>
+       <langue code="de" url="http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=de">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="it" url="http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=it">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/menus_1/lang/paquet-menus_ar.php b/www/plugins/menus_1/lang/paquet-menus_ar.php
new file mode 100644 (file)
index 0000000..9370c82
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=ar
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'menus_description' => 'عندما لا نستخدم ملحق {{القوائم}}، نضطر لتعريف كل قوائم الموقع في الصفحات النموذجية،
+       مما يؤدي الى ان مدراء الموقع لا يمكنهم التحكم مباشرة بهذه القوائم، وعندما يرغبون في تعديل اي شيء فيها، يضطرون الى 
+       الطلب من مطور الصفحات النموذجية إدخال التعديلات. إضافة الى ذلك، اذا اردنا وضع روابط ثابتة (مثلاً رابط الى مقال محدد او صفحة محددة او موقع آخر) يجب ادخال هذه الروابط كما هي في صفحة القوائم النموذجية.
+
+       الهدف من ملحق {{القوائم}} هو السماح بإنشاء قوائم بسهولة من خلال واجهة تفاعلية في المجال الخاص.
+       {{تنبيه!}} لا يتحكم هذا الملحق بالطريقة التي ستعرض فيها هذه القوائم في الموقع العمومي. يكتفي بإنشاء القوائم بسهولة وإنتاج علامات html الخاصة بها. ',
+       'menus_nom' => 'القوائم',
+       'menus_slogan' => 'إنشاء قوائم شخصية',
+       'menus_titre' => 'القوائم'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/paquet-menus_de.php b/www/plugins/menus_1/lang/paquet-menus_de.php
new file mode 100644 (file)
index 0000000..87b6f95
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'menus_description' => 'Menüs bequem im Redaktionssystem gestalten.', # MODIF
+       'menus_nom' => 'Menus', # NEW
+       'menus_slogan' => 'Menüs bequem im Redaktionssystem gestalten.',
+       'menus_titre' => 'Menüs'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/paquet-menus_en.php b/www/plugins/menus_1/lang/paquet-menus_en.php
new file mode 100644 (file)
index 0000000..e5cde92
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'menus_description' => 'When you are not using the plugin {{menus}}, you have to define all the menus in your templates, so that site administrators do not have direct hands on it and when they want to change something in it, they are forced to make a request to the person in charge of the templates.
+
+In addition, when you want static links (a link to a specific article, to a specific page or to an external site) they should be hard written in the template of the menu.
+
+The purpose of the plugin {{Menus}} is to allow you to create easily menus using an intuitive interface, directly into the private area.
+
+{{Warning}} This plugin does not deal with the way menus are displayed. It allows their easy creation and to generate the HTML code.',
+       'menus_nom' => 'Menus',
+       'menus_slogan' => 'Create your own custom menus.',
+       'menus_titre' => 'Menus'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/paquet-menus_es.php b/www/plugins/menus_1/lang/paquet-menus_es.php
new file mode 100644 (file)
index 0000000..42a00c4
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'menus_description' => 'Cuando no se usa el plugin {{Menús}}, es necesario definir todos los menús en los esqueletos, lo que hace los administradores del sitio no puedan cambiar algo a su antojo, sino que deban solicitar a la persona modificar los esqueletos. Además, cuando vea los enlaces estáticos (un enlace a un artículo específico, o a una página determinada, o a un sitio externo)  deberá escribirlos en duro en el esqueleto del menú.
+       El propósito del plugin {{Menús}} es entonces permitir elaborar fácilmente menús mediante una interfaz sencilla directamente en la parte privada. 
+       {{¡Atención!}} Este plugin no se ocupa de cómo se mostrarán los menús. Permite crearlos fácilmente y generar el código HTML.',
+       'menus_nom' => 'Menús',
+       'menus_slogan' => 'Cree sus menús personalizados.',
+       'menus_titre' => 'Menús'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/paquet-menus_fr.php b/www/plugins/menus_1/lang/paquet-menus_fr.php
new file mode 100644 (file)
index 0000000..46d3bcc
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/menus/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'menus_description' => 'Lorsqu\'on ne se sert pas du plugin {{Menus}}, on est obligé de définir tous ses menus dans les squelettes,
+       ce qui fait que les administrateurs du site n\'ont pas directement la main dessus et que lorsqu\'ils veulent y changer quelque chose, ils sont obligés
+       d\'en faire la demande à la personne en charge des squelettes. De plus, lorsqu\'on veut des liens statiques (un lien vers un article précis,
+       ou vers une page précise, ou vers un site externe) il faut les écrire en dur dans le squelette du menu.
+
+       Le but du plugin {{Menus}} est donc de permettre de facilement élaborer des menus au moyen d\'une interface conviviale, directement dans la partie privée.
+       {{Attention !}} Ce plugin ne s\'occupe pas de la manière dont seront affichés les menus. Il permet de les créer facilement et d\'en générer le code HTML.',
+       'menus_nom' => 'Menus',
+       'menus_slogan' => 'Créez vos menus personnalisés.',
+       'menus_titre' => 'Menus'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/paquet-menus_it.php b/www/plugins/menus_1/lang/paquet-menus_it.php
new file mode 100644 (file)
index 0000000..9a6975f
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'menus_description' => 'Crea i tuoi menù in redazione.', # MODIF
+       'menus_nom' => 'Menus', # NEW
+       'menus_slogan' => 'Crea i tuoi menù in redazione.',
+       'menus_titre' => 'Menù'
+);
+
+?>
diff --git a/www/plugins/menus_1/lang/paquet-menus_sk.php b/www/plugins/menus_1/lang/paquet-menus_sk.php
new file mode 100644 (file)
index 0000000..6a87678
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-menus?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'menus_description' => 'Keď sa nepoužíva zásuvný modul{{Menus,}} všetky šablóny musia byť definované v ich menu,
+       čiže administrátori stránky to nemajú úplne pod kontrolou a ak chcú niečo zmeniť, musia sa obrátiť 
+       na človeka, ktorý je zodpovedný za šablóny. Okrem toho ak chcete pridať statické odkazy (odkaz na konkrétny článok
+       alebo na konkrétnu stránku, alebo na externú stránku), tie musia byť zapísané do šablóny menu.
+
+       Cieľom zásuvného modulu {{Menus}} je umožniť vám ľahko vytvárať menu pomocou intuitívneho rozhrania priamo do súkromnej zóny.
+       {{Pozor!}} Tento zásuvný modul sa nezaoberá tým, ako sa položky menu zobrazia. Umožňuje  ľahké vytváranie menu a vygenerovanie kódu HTML.',
+       'menus_nom' => 'Ponuky menu',
+       'menus_slogan' => 'Vytvorte svoje vlastné ponuky menu.',
+       'menus_titre' => 'Ponuky menu'
+);
+
+?>
diff --git a/www/plugins/menus_1/menu.html b/www/plugins/menus_1/menu.html
new file mode 100644 (file)
index 0000000..b6581eb
--- /dev/null
@@ -0,0 +1,11 @@
+<BOUCLE_menu_principal(MENUS){id_menu}>
+<html>
+       <head>
+               [<title>(#TITRE|textebrut)</title>]
+       </head>
+       <body>
+               <h1>#TITRE</h1>
+               #INCLURE{fond=inclure/menu, env}
+       </body>
+</html>
+</BOUCLE_menu_principal>
diff --git a/www/plugins/menus_1/menus/accueil.html b/www/plugins/menus_1/menus/accueil.html
new file mode 100644 (file)
index 0000000..95ae86e
--- /dev/null
@@ -0,0 +1,9 @@
+[(#SET{titre,[(#ENV*{titre}|typo|sinon{<:accueil_site:>})]})]
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">#GET{titre}</div>
+       <div class="infos"><:info_racine_site:></div>
+]
+[(#ENV{appel_menu}|oui)
+       <li class="menu-entree item[ (#ENV{css})][(#ENV{env/type}|=={page}|et{#ENV{env/composition}|=={sommaire}}|ou{#ENV{env/type-page}|=={sommaire}|oui}|oui)on active]">
+               <a href="#URL_SITE_SPIP/">#GET{titre}</a>
+]
diff --git a/www/plugins/menus_1/menus/accueil.xml b/www/plugins/menus_1/menus/accueil.xml
new file mode 100644 (file)
index 0000000..bf77651
--- /dev/null
@@ -0,0 +1,8 @@
+<entree>
+       <nom><:menus:nom_menu_accueil:></nom>
+       <rang>01</rang>
+       <description><:menus:description_menu_accueil:></description>
+       <icone>images/menus_accueil.png</icone>
+       <parametre nom="titre" class="multilang" label="menus:entree_titre" />
+       <parametre nom="css" label="menus:entree_css" />
+</entree>
diff --git a/www/plugins/menus_1/menus/articles_rubrique.html b/www/plugins/menus_1/menus/articles_rubrique.html
new file mode 100644 (file)
index 0000000..f2339ea
--- /dev/null
@@ -0,0 +1,47 @@
+[(#SET{id_rubrique, #ENV{id_rubrique}|intval})]\r
+[(#SET{tri_num, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_num},'titre'}})]\r
+[(#SET{tri_alpha, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_alpha},'titre'}})]\r
+[(#SET{articles_max_affiches, #ENV{articles_max_affiches}|intval|?{#ENV{articles_max_affiches},10000}})]\r
+\r
+[(#ENV{appel_formulaire}|oui)\r
+       [(#SET{titre, #GET{id_rubrique}|?{#INFO_TITRE{rubrique, #GET{id_rubrique}}, <:info_racine_site:>}})]\r
+       <div class="titre">#GET{titre}</div>\r
+       <div class="infos">\r
+               <:menus:info_tri:> [(#GET{tri_num}) <:menus:info_tri_num:>][(#GET{tri_num}|et{GET{tri_alpha}}), ][(#GET{tri_alpha}) <:menus:info_tri_alpha:>]\r
+       </div>\r
+]\r
+<BOUCLE_appel(CONDITION){si #ENV{appel_menu}|oui}>\r
+       <BOUCLE_env_trad(CONDITION){si #ENV{trad}|=={trad}}>\r
+       #SET{cpt,0}\r
+       <BOUCLE_cpt_articles_orig(ARTICLES){id_rubrique=#GET{id_rubrique}}{origine_traduction}> </BOUCLE_cpt_articles_orig>#SET{cpt,#TOTAL_BOUCLE}</B_cpt_articles_orig>\r
+       <BOUCLE_articles_orig(ARTICLES){id_rubrique=#GET{id_rubrique}}{par num #GET{tri_num}}{par #GET{tri_alpha}}{origine_traduction}{0,#GET{articles_max_affiches}}>\r
+               <BOUCLE_trad(ARTICLES){traduction}{id_rubrique=#GET{id_rubrique}}{lang=#ENV{lang}}>\r
+               <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{article,#ENV*{env}})]">\r
+                       <a href="#URL_ARTICLE">#TITRE</a>\r
+               </li>\r
+               </BOUCLE_trad>\r
+               </B_trad>\r
+               <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{article,#ENV*{env}})]">\r
+                       <a href="#URL_ARTICLE">#TITRE</a>\r
+               </li>\r
+               <//B_trad>\r
+       </BOUCLE_articles_orig>\r
+       [(#GET{cpt}|>{#GET{articles_max_affiches}}|oui)\r
+       <li><a class="suite" href="[(#URL_RUBRIQUE|parametre_url{connect,''})]"><:menus:tous_les_articles:></a></li>    \r
+    ]\r
+       </B_articles_orig>\r
+       </BOUCLE_env_trad>\r
+       </B_env_trad>\r
+       #SET{cpt,0}\r
+       <BOUCLE_cpt_articles(ARTICLES){id_rubrique=#GET{id_rubrique}}> </BOUCLE_cpt_articles>#SET{cpt,#TOTAL_BOUCLE}</B_cpt_articles>\r
+       <BOUCLE_articles(ARTICLES){id_rubrique=#GET{id_rubrique}}{par num #GET{tri_num}}{par #GET{tri_alpha}}{0,#GET{articles_max_affiches}}>\r
+               <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{article,#ENV*{env}})]">\r
+                       <a href="#URL_ARTICLE">#TITRE</a>\r
+               </li>\r
+       </BOUCLE_articles>\r
+       [(#GET{cpt}|>{#GET{articles_max_affiches}}|oui)\r
+       <li><a class="suite" href="[(#URL_RUBRIQUE|parametre_url{connect,''})]"><:menus:tous_les_articles:></a></li>    \r
+    ]\r
+       </B_articles>\r
+       <//B_env_trad>\r
+</BOUCLE_appel>
\ No newline at end of file
diff --git a/www/plugins/menus_1/menus/articles_rubrique.xml b/www/plugins/menus_1/menus/articles_rubrique.xml
new file mode 100644 (file)
index 0000000..3a18591
--- /dev/null
@@ -0,0 +1,12 @@
+<entree>
+       <nom><:menus:nom_menu_articles_rubrique:></nom>
+       <rang>04</rang>
+       <description><:menus:description_menu_articles_rubrique:></description>
+       <icone>images/menus_articles_rubrique.png</icone>
+       <parametre nom="id_rubrique" label="menus:entree_id_rubrique" />
+       <parametre nom="tri_num" label="menus:entree_tri_num_articles" />
+       <parametre nom="tri_alpha" label="menus:entree_tri_alpha_articles" />
+       <parametre nom="articles_max_affiches" label="menus:entree_articles_max_affiches" />
+       <parametre nom="trad" label="menus:entree_traduction_articles_rubriques" />
+       <refuser_sous_menu/>
+</entree>
diff --git a/www/plugins/menus_1/menus/deconnecter.html b/www/plugins/menus_1/menus/deconnecter.html
new file mode 100644 (file)
index 0000000..f045569
--- /dev/null
@@ -0,0 +1,9 @@
+[(#SET{titre,[(#ENV*{titre}|typo|sinon{<:icone_deconnecter:>})]})]
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">#GET{titre}</div>
+       <div class="infos"> </div>
+]
+[(#ENV{appel_menu}|et{#SESSION{id_auteur}|>{0}|oui}|oui)
+       <li class="menu-entree item[ (#ENV{css})]">
+               <a href="#URL_LOGOUT">#GET{titre}</a>
+]
diff --git a/www/plugins/menus_1/menus/deconnecter.xml b/www/plugins/menus_1/menus/deconnecter.xml
new file mode 100644 (file)
index 0000000..5b0869c
--- /dev/null
@@ -0,0 +1,8 @@
+<entree>
+       <nom><:menus:nom_menu_deconnecter:></nom>
+       <rang>21</rang>
+       <description><:menus:description_menu_deconnecter:></description>
+       <icone>images/menus_logout.png</icone>
+       <parametre nom="titre" class="multilang" label="menus:entree_titre" />
+       <parametre nom="css" label="menus:entree_css" />
+</entree>
diff --git a/www/plugins/menus_1/menus/espace_prive.html b/www/plugins/menus_1/menus/espace_prive.html
new file mode 100644 (file)
index 0000000..f4281c6
--- /dev/null
@@ -0,0 +1,17 @@
+[(#SET{titre,[(#ENV*{titre}|typo|sinon{<:espace_prive:>})]})]\r
+[(#SET{titre_connecter,[(#ENV*{titre_connecter}|typo|sinon{<:lien_connecter:>})]})]\r
+\r
+[(#ENV{appel_formulaire}|oui)\r
+       <div class="titre">#GET{titre}</div>\r
+       <div class="infos"> </div>\r
+]\r
+[(#ENV{appel_menu}|oui)\r
+       [(#AUTORISER{ecrire})\r
+               <li class="menu-entree item[ (#ENV{css})]">\r
+                       <a href="#EVAL{_DIR_RESTREINT_ABS}">#GET{titre}</a>\r
+       ]\r
+       [(#SESSION{id_auteur}|>{0}|non)\r
+               <li class="menu-entree item[ (#ENV{css})]">\r
+                       <a href="[(#URL_PAGE{login}|parametre_url{url,#ENV{url,#SELF}})]" rel="nofollow">#GET{titre_connecter}</a>\r
+       ]\r
+]\r
diff --git a/www/plugins/menus_1/menus/espace_prive.xml b/www/plugins/menus_1/menus/espace_prive.xml
new file mode 100644 (file)
index 0000000..4439350
--- /dev/null
@@ -0,0 +1,10 @@
+<entree>\r
+       <nom><:menus:nom_menu_espace_prive:></nom>\r
+       <rang>10</rang>\r
+       <description><:menus:description_menu_espace_prive:></description>\r
+       <icone>images/menus_logout.png</icone>\r
+       <parametre nom="titre" class="multilang" label="menus:entree_titre_prive" />\r
+       <parametre nom="titre_connecter" class="multilang" label="menus:entree_titre_connecter" />\r
+       <parametre nom="css" label="menus:entree_css" />\r
+       <parametre nom="url" label="menus:entree_url_public" />\r
+</entree>\r
diff --git a/www/plugins/menus_1/menus/groupe_mots.html b/www/plugins/menus_1/menus/groupe_mots.html
new file mode 100644 (file)
index 0000000..7d7d1a1
--- /dev/null
@@ -0,0 +1,61 @@
+[(#SET{id_groupe, #ENV{id_groupe}|intval})]
+[(#SET{nombre_articles_mot, #ENV{nombre_articles_mot}|intval|?{#ENV{nombre_articles_mot},0}})]
+[(#SET{tri_num, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_num},'titre'}})]
+[(#SET{tri_alpha, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_alpha},'titre'}})]
+
+[(#ENV{appel_formulaire}|oui)
+       [(#SET{titre, #GET{id_groupe}|?{#INFO_TITRE{groupes_mots, #GET{id_groupe}}, <:menus:info_tous_groupes_mots:>}})]
+       <div class="titre">#GET{titre}</div>
+       <div class="infos">
+               [(#GET{nombre_articles_mot}|=={0}|non)
+                       <:menus:entree_sur_n_articles{n=#GET{nombre_articles_mot}}:>
+               ]
+               [(#GET{nombre_articles_mot}|=={0}|oui)
+                       <:menus:entree_aucun:>
+               ]
+               <br />
+       <:menus:info_tri:> [(#GET{tri_num}) <:menus:info_tri_num:>][(#GET{tri_num}|et{GET{tri_alpha}}), ][(#GET{tri_alpha}) <:menus:info_tri_alpha:>]
+       </div>
+]
+
+<BOUCLE_appel(CONDITION){si #ENV{appel_menu}|oui}>
+<BOUCLE_mots(MOTS){id_groupe=#GET{id_groupe}}{par num #GET{tri_num}}{par #GET{tri_alpha}}>
+       <li class="menu-entree item">
+               <a href="#URL_MOT">#TITRE</a>
+               <B_articles_mots>
+                       <ul class="menu-liste menu-items">
+                               <BOUCLE_articles_mots(ARTICLES){id_mot=#ID_MOT}{par num #GET{tri_num}}{par #GET{tri_alpha}}{0,#GET{nombre_articles_mot}}>
+                               <li class="menu-entree item">
+                                       <a href="#URL_ARTICLE">#TITRE</a>
+                               </li>
+                               </BOUCLE_articles_mots>
+                       </ul>
+               </B_articles_mots>
+       </li>
+</BOUCLE_mots>
+</B_mots>
+       <BOUCLE_groupe_mots(GROUPES_MOTS){par num #GET{tri_num}}{par #GET{tri_alpha}}>
+       <li class="menu-entree item">
+               <a[(#CHEMIN{groupes_mot.html}|oui) href="#URL_PAGE{groupes_mot,id_groupe=#ID_GROUPE}"][(#CHEMIN{groupes_mot.html}|non) href="#"] title="[(#TITRE|attribut_html)]">#TITRE</a>
+               <B_mots_tous>
+                       <ul class="menu-liste menu-items">
+                               <BOUCLE_mots_tous(MOTS){id_groupe}{par num #GET{tri_num}}{par #GET{tri_alpha}}>
+                               <li class="menu-entree item">
+                                       <a href="#URL_MOT">#TITRE</a>
+                                               <B_mots_articles_mots>
+                                                       <ul class="menu-liste menu-items">
+                                                               <BOUCLE_mots_articles_mots(ARTICLES){id_mot=#ID_MOT}{par num #GET{tri_num}}{par #GET{tri_alpha}}{0,#GET{nombre_articles_mot}}>
+                                                                       <li class="menu-entree item">
+                                                                       <a href="#URL_ARTICLE">#TITRE</a>
+                                                                       </li>
+                                                               </BOUCLE_mots_articles_mots>
+                                                       </ul>
+                                               </B_mots_articles_mots>
+                               </li>
+                               </BOUCLE_mots_tous>
+                       </ul>
+               </B_mots_tous>
+       </li>
+       </BOUCLE_groupe_mots>
+<//B_mots>
+</BOUCLE_appel>
\ No newline at end of file
diff --git a/www/plugins/menus_1/menus/groupe_mots.xml b/www/plugins/menus_1/menus/groupe_mots.xml
new file mode 100644 (file)
index 0000000..f43eabd
--- /dev/null
@@ -0,0 +1,11 @@
+<entree>
+       <nom><:menus:nom_menu_groupes_mots:></nom>
+       <rang>05</rang>
+       <description><:menus:description_menu_groupes_mots:></description>
+       <icone>images/menus_groupes_mots.png</icone>
+       <parametre nom="id_groupe" label="menus:entree_id_groupe" />
+       <parametre nom="tri_num" label="menus:entree_tri_num" />
+       <parametre nom="tri_alpha" label="menus:entree_tri_alpha" />
+       <parametre nom="nombre_articles_mot" label="menus:entree_nombre_articles" />
+       <refuser_sous_menu/>
+</entree>
diff --git a/www/plugins/menus_1/menus/lien.html b/www/plugins/menus_1/menus/lien.html
new file mode 100644 (file)
index 0000000..ab348b8
--- /dev/null
@@ -0,0 +1,10 @@
+#SET{titre, #ENV*{titre}|typo}
+
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">#GET{titre}</div>
+       <div class="infos">[(#ENV*{url}|extraire_multi)]</div>
+]
+[(#ENV{appel_menu}|oui)
+       <li class="menu-entree item[ (#ENV{css})]">
+               <a href="[(#ENV*{url}|extraire_multi)]"[ class="(#ENV{css_lien})"]>#GET{titre}</a>
+]
diff --git a/www/plugins/menus_1/menus/lien.xml b/www/plugins/menus_1/menus/lien.xml
new file mode 100644 (file)
index 0000000..476e237
--- /dev/null
@@ -0,0 +1,10 @@
+<entree>
+       <nom><:menus:nom_menu_lien:></nom>
+       <rang>11</rang>
+       <description><:menus:description_menu_lien:></description>
+       <icone>images/menus_lien.png</icone>
+       <parametre nom="titre" class="multilang" label="menus:entree_titre" obligatoire="oui" />
+       <parametre nom="url" label="menus:entree_url" obligatoire="oui" />
+       <parametre nom="css" label="menus:entree_css" />
+       <parametre nom="css_lien" label="menus:entree_css_lien" />
+</entree>
diff --git a/www/plugins/menus_1/menus/mapage.html b/www/plugins/menus_1/menus/mapage.html
new file mode 100644 (file)
index 0000000..d4940ee
--- /dev/null
@@ -0,0 +1,9 @@
+[(#SET{titre,[(#ENV*{titre}|typo|sinon{<:menus:entree_mapage:>})]})]
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">#GET{titre}</div>
+       <div class="infos"> </div>
+]
+[(#ENV{appel_menu}|et{#SESSION{id_auteur}|>{0}|oui}|oui)
+       <li class="menu-entree item[ (#ENV{css})][(#ENV{env/type}|=={auteur}|ou{#ENV{env/type-page}|=={auteur}}|et{#ENV{env/id_auteur}|=={#SESSION{id_auteur}}}) on active]">
+               <a href="#URL_AUTEUR{#SESSION{id_auteur}}">#GET{titre}</a>
+]
diff --git a/www/plugins/menus_1/menus/mapage.xml b/www/plugins/menus_1/menus/mapage.xml
new file mode 100644 (file)
index 0000000..492ca43
--- /dev/null
@@ -0,0 +1,8 @@
+<entree>
+       <nom><:menus:nom_menu_mapage:></nom>
+       <rang>20</rang>
+       <description><:menus:description_menu_mapage:></description>
+       <icone>images/menus_mapage.png</icone>
+       <parametre nom="titre" class="multilang" label="menus:entree_titre" />
+       <parametre nom="css" label="menus:entree_css" />
+</entree>
diff --git a/www/plugins/menus_1/menus/mots.html b/www/plugins/menus_1/menus/mots.html
new file mode 100644 (file)
index 0000000..ac3a5f5
--- /dev/null
@@ -0,0 +1,47 @@
+[(#SET{id_mot, #ENV{id_mot}|intval})]
+[(#SET{nombre, #ENV{nombre}|intval|?{#ENV{nombre},0}})]
+[(#SET{tri_num, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_num},'titre'}})]
+[(#SET{tri_alpha, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_alpha},'titre'}})]
+
+[(#ENV{appel_formulaire}|oui)
+       [(#SET{titre, #GET{id_mot}|?{#INFO_TITRE{mots, #GET{id_mot}}, <:info_racine_site:>}})]
+       <div class="titre">#GET{titre}</div>
+       <div class="infos">
+               [(#GET{nombre}|=={0}|non)
+                       <:menus:entree_sur_n_mots{n=#GET{nombre}}:>
+               ]
+               [(#GET{nombre}|=={0}|oui)
+                       <:menus:entree_infini:>
+               ]
+               <br /><:menus:info_tri:> [(#GET{tri_num}) <:menus:info_tri_num:>][(#GET{tri_num}|et{GET{tri_alpha}}), ][(#GET{tri_alpha}) <:menus:info_tri_alpha:>]
+       </div>
+]
+<BOUCLE_appel(CONDITION){si #ENV{appel_menu}|oui}>
+       <BOUCLE_mot(MOTS){id_mot=#GET{id_mot}}>
+               <li class="menu-entree item[ (#ID_MOT|menus_exposer{mot,#ENV*{env}})]">
+                       <a href="#URL_MOT" title="[(#TITRE|attribut_html)]">#TITRE</a>
+                       <BOUCLE_infini(CONDITION){si #GET{nombre}|=={0}}>
+                               <B_articles_infini>
+                               <ul class="menu-liste menu-items">
+                                       <BOUCLE_articles_infini(ARTICLES){id_mot}{par num #GET{tri_num}}{par #GET{tri_alpha}}>
+                                               <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{rubrique,#ENV*{env}})]">
+                                                       <a href="#URL_ARTICLE">#TITRE</a>
+                                               </li>
+                                       </BOUCLE_articles_infini>
+                               </ul>
+                               </B_articles_infini>
+                       </BOUCLE_infini>
+                       <BOUCLE_limite(CONDITION){si #GET{nombre}|>{0}}>
+                       <B_articles_limite>
+                               <ul class="menu-liste menu-items">
+                                       <BOUCLE_articles_limite(ARTICLES){id_mot}{par num #GET{tri_num}}{par #GET{tri_alpha}}{0,#GET{nombre}}>
+                                               <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{rubrique,#ENV*{env}})]">
+                                                       <a href="#URL_ARTICLE">#TITRE</a>
+                                               </li>
+                                       </BOUCLE_articles_limite>
+                               </ul>
+                               </B_articles_limite>
+                       </BOUCLE_limite>
+               </li>
+       </BOUCLE_mot>
+</BOUCLE_appel>
diff --git a/www/plugins/menus_1/menus/mots.xml b/www/plugins/menus_1/menus/mots.xml
new file mode 100644 (file)
index 0000000..1d32e0c
--- /dev/null
@@ -0,0 +1,11 @@
+<entree>
+       <nom><:menus:nom_menu_mots:></nom>
+       <rang>04</rang>
+       <description><:menus:description_menu_mots:></description>
+       <icone>images/menus_mots.png</icone>
+       <parametre nom="id_mot" label="menus:entree_id_mot" obligatoire="oui" />
+       <parametre nom="nombre" label="menus:entree_nombre_articles" />
+       <parametre nom="tri_num" label="menus:entree_tri_num_articles" />
+       <parametre nom="tri_alpha" label="menus:entree_tri_alpha_articles" />
+       <refuser_sous_menu/>
+</entree>
diff --git a/www/plugins/menus_1/menus/objet.html b/www/plugins/menus_1/menus/objet.html
new file mode 100644 (file)
index 0000000..9301da6
--- /dev/null
@@ -0,0 +1,36 @@
+#SET{id_objet,#ENV{id_objet}}
+<BOUCLE_si_art(CONDITION){si #ENV{type_objet}|=={article}|et{#ENV{trad}|=={trad}}}>
+<BOUCLE_art_orig(ARTICLES){id_article=#ENV{id_objet}}{origine_traduction}>
+<BOUCLE_art_lang(ARTICLES){traduction}{lang=#ENV{lang}}>
+#SET{id_objet,#ID_ARTICLE}
+</BOUCLE_art_lang>
+#SET{id_objet,#ID_ARTICLE}
+<//B_art_lang>
+</BOUCLE_art_orig>
+</BOUCLE_si_art>
+
+[(#SET{titre, #ENV*{titre}|typo|sinon{#INFO_TITRE{#ENV{type_objet}, #GET{id_objet}}}|sinon{<:info_sans_titre:>}})]
+
+[(#ENV{trad}|=={trad}|et{#ENV{type_objet}|=={article}}|oui)#SET{info_trad,#VAL{menus:info_traduction_recuperee}|_T}]
+
+#SET{visible,oui}
+[(#ENV{connexion}|=={session}|oui)
+       [(#SESSION{statut}|non)
+               #SET{visible,non}]
+       #SET{info_session,#VAL{menus:info_connexion_obligatoire}|_T}
+]
+[(#ENV{connexion}|=={nosession}|oui)
+       [(#SESSION{statut}|oui)
+               #SET{visible,non}]
+       #SET{info_session,#VAL{menus:info_deconnexion_obligatoire}|_T}
+]
+
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">#GET{titre}</div>
+       <div class="infos">#ENV{type_objet}-#GET{id_objet}[-(#GET{info_session})][-(#GET{info_trad})]</div>
+]
+
+[(#ENV{appel_menu}|et{#GET{visible}|=={oui}}|oui)
+       <li class="menu-entree item[ (#ENV{css})][ (#ENV{id_objet}|menus_exposer{#ENV{type_objet},#ENV*{env}})]">
+               <a href="#INFO_URL{#ENV{type_objet}, #GET{id_objet}}">#GET{titre}</a>
+]
diff --git a/www/plugins/menus_1/menus/objet.xml b/www/plugins/menus_1/menus/objet.xml
new file mode 100644 (file)
index 0000000..2f716a6
--- /dev/null
@@ -0,0 +1,12 @@
+<entree>
+       <nom><:menus:nom_menu_objet:></nom>
+       <rang>02</rang>
+       <description><:menus:description_menu_objet:></description>
+       <icone>images/menus_objet.png</icone>
+       <parametre nom="type_objet" label="menus:entree_type_objet" obligatoire="oui" />
+       <parametre nom="id_objet" label="menus:entree_id_objet" obligatoire="oui" />
+       <parametre nom="titre" class="multilang" label="menus:entree_titre" />
+       <parametre nom="css" label="menus:entree_css" />
+       <parametre nom="connexion" label="menus:entree_connexion_objet" />
+       <parametre nom="trad" label="menus:entree_traduction_objet" />
+</entree>
diff --git a/www/plugins/menus_1/menus/page_speciale.html b/www/plugins/menus_1/menus/page_speciale.html
new file mode 100644 (file)
index 0000000..c592781
--- /dev/null
@@ -0,0 +1,25 @@
+#SET{titre, #ENV*{titre}|typo}
+
+[(#REM) Par défaut on affiche toujours l'entrée ]
+#SET{afficher_entree,oui}
+[(#REM) Si le champ est rempli on désactive l'entrée si ça ne correspond pas aux attentes ]
+[(#ENV{suivant_connexion}|oui)
+       [(#ENV{suivant_connexion}|=={connecte}|et{#SESSION{id_auteur}|non})
+               #SET{afficher_entree,''}
+       ]
+       [(#ENV{suivant_connexion}|=={deconnecte}|et{#SESSION{id_auteur}|oui})
+               #SET{afficher_entree,''}
+       ]
+       [(#ENV{suivant_connexion}|=={admin}|et{#SESSION{statut}|!={"0minirezo"}})
+               #SET{afficher_entree,''}
+       ]
+]
+
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">#GET{titre}</div>
+       <div class="infos"><:menus:info_page_speciale{page=#ENV{nom}}:>[ ((#ENV{suivant_connexion}|?{[(#VAL{menus:entree_suivant_connexion_}|concat{#ENV{suivant_connexion}}|_T)]}))]</div>
+]
+[(#ENV{appel_menu}|et{#GET{afficher_entree}})
+       <li class="menu-entree item[ (#ENV{css})][(#ENV{env/type-page}|=={#ENV{nom}}|ou{#ENV{env/type}|=={page}|et{#ENV{env/composition}|=={#ENV{nom}}}}) on active]">
+               <a href="#URL_PAGE{#ENV{nom}, #ENV{parametres}}">#GET{titre}</a>
+]
diff --git a/www/plugins/menus_1/menus/page_speciale.xml b/www/plugins/menus_1/menus/page_speciale.xml
new file mode 100644 (file)
index 0000000..0eebfdd
--- /dev/null
@@ -0,0 +1,11 @@
+<entree>
+       <nom><:menus:nom_menu_page_speciale:></nom>
+       <rang>10</rang>
+       <description><:menus:description_menu_page_speciale:></description>
+       <icone>images/menus_page_speciale.png</icone>
+       <parametre nom="titre" class="multilang" label="menus:entree_titre" obligatoire="oui" />
+       <parametre nom="nom" label="menus:entree_page" obligatoire="oui" />
+       <parametre nom="parametres" label="menus:entree_parametres" />
+       <parametre nom="css" label="menus:entree_css" />
+       <parametre nom="suivant_connexion" label="menus:entree_suivant_connexion" />
+</entree>
diff --git a/www/plugins/menus_1/menus/page_speciale_zajax.html b/www/plugins/menus_1/menus/page_speciale_zajax.html
new file mode 100644 (file)
index 0000000..13119d8
--- /dev/null
@@ -0,0 +1,10 @@
+#SET{titre, #ENV*{titre}|typo}
+
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">#GET{titre}</div>
+       <div class="infos"><:menus:info_page_speciale_zajax{page=#ENV{nom},bloc=#ENV{bloc}}:></div>
+]
+[(#ENV{appel_menu}|oui)
+       <li class="menu-entree item[ (#ENV{css})][(#ENV{env/type-page}|=={#ENV{nom}}|ou{#ENV{env/type}|=={page}|et{#ENV{env/composition}|=={#ENV{nom}}}}) on active]">
+               <a href="#URL_PAGE{#ENV{nom}, #ENV{parametres}}" onclick="jQuery.modalbox('[(#URL_PAGE{#ENV{nom}, #ENV{parametres}}|parametre_url{var_zajax,#ENV{bloc},'&'})]');return false;">#GET{titre}</a>
+]
diff --git a/www/plugins/menus_1/menus/page_speciale_zajax.xml b/www/plugins/menus_1/menus/page_speciale_zajax.xml
new file mode 100644 (file)
index 0000000..ede0ad3
--- /dev/null
@@ -0,0 +1,13 @@
+<entree>
+       <nom><:menus:nom_menu_page_speciale_zajax:></nom>
+       <rang>10</rang>
+       <description><:menus:description_menu_page_speciale_zajax:></description>
+       <icone>images/menus_page_speciale.png</icone>
+       <parametre nom="titre" class="multilang" label="menus:entree_titre" obligatoire="oui" />
+       <parametre nom="nom" label="menus:entree_page" obligatoire="oui" />
+       <parametre nom="bloc" label="menus:entree_bloc" obligatoire="oui" />
+       <parametre nom="parametres" label="menus:entree_parametres" />
+       <parametre nom="css" label="menus:entree_css" />
+       <necessite type="plugin" nom="mediabox" />
+       <necessite type="plugin" nom="Z" />
+</entree>
diff --git a/www/plugins/menus_1/menus/rubriques_completes.html b/www/plugins/menus_1/menus/rubriques_completes.html
new file mode 100644 (file)
index 0000000..0790dca
--- /dev/null
@@ -0,0 +1,217 @@
+[(#REM)        Rubrique de depart :\r
+                       Si l'id_rubrique saisi vaut "courante" on va chercher l'id de la rubrique courante => env{env{id_rubrique}}\r
+                       sinon, on utilise l'id saisi ]\r
+[(#SET{id_rubrique, #ENV{id_rubrique}|=={courante}|?{#ENV**|unserialize|table_valeur{env}|table_valeur{id_rubrique},#ENV{id_rubrique}|intval}})]\r
+\r
+[(#SET{id_secteur_exclus, #ENV{id_secteur_exclus}|?{#ENV{id_secteur_exclus}|explode{','},#ARRAY}})]\r
+[(#SET{niveau_max_txt, #ENV{niveau}|intval|?{#ENV{niveau},infini}})]\r
+[(#SET{niveau_max, #ENV{niveau}|intval|?{#ENV{niveau},1000}})]\r
+[(#SET{sousrub_cond, #ENV{sousrub_cond}|=={oui}|?{'on',''}})]\r
+[(#SET{rubriques_max_affichees, #ENV{rubriques_max_affichees}|intval|?{#ENV{rubriques_max_affichees},10000}})]\r
+[(#SET{id_rubriques_exclues, #ENV{id_rubriques_exclues}|?{#ENV{id_rubriques_exclues}|explode{','},#ARRAY}})]\r
+[(#SET{classe_parent, #ENV{classe_parent}})]\r
+\r
+[(#SET{afficher_articles, #ENV{afficher_articles}|=={oui}|?{'on',''}})]\r
+[(#SET{masquer_articles_uniques, #ENV{masquer_articles_uniques}|=={oui}|?{'on',''}})]\r
+[(#SET{articles_max, #ENV{articles_max}|intval|?{#ENV{articles_max},10000}})]\r
+[(#SET{articles_max_plus_un, #GET{articles_max}|plus{1}})]\r
+[(#SET{articles_max_affiches, #ENV{articles_max_affiches}|intval|?{#ENV{articles_max_affiches},10000}})]\r
+\r
+[(#REM) Tri des rubriques ]\r
+[(#SET{tri_num, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_num},'titre'}})]\r
+[(#SET{tri_alpha, #ENV{tri_num}|ou{#ENV{tri_alpha}}|?{#ENV{tri_alpha},'titre'}})]\r
+[(#SET{tri_num_inverse, #ENV{tri_num_inverse}|=={oui}|?{'1','0'}})]\r
+[(#SET{tri_alpha_inverse, #ENV{tri_alpha_inverse}|=={oui}|?{'1','0'}})]\r
+\r
+[(#REM) Tri des articles ]\r
+[(#SET{tri_num_articles, #ENV{tri_num_articles}|ou{#ENV{tri_alpha_articles}}|?{#ENV{tri_num_articles},'titre'}})]\r
+[(#SET{tri_alpha_articles, #ENV{tri_num_articles}|ou{#ENV{tri_alpha_articles}}|?{#ENV{tri_alpha_articles},'titre'}})]\r
+[(#SET{tri_num_articles_inverse, #ENV{tri_num_articles_inverse}|=={oui}|?{'1','0'}})]\r
+[(#SET{tri_alpha_articles_inverse, #ENV{tri_alpha_articles_inverse}|=={oui}|?{'1','0'}})]\r
+\r
+[(#ENV{appel_formulaire}|oui)\r
+       [(#SET{titre, #ENV{id_rubrique}|?{#ENV{id_rubrique}|=={courante}|?{<:menus:info_rubrique_courante:>,#INFO_TITRE{rubrique, #GET{id_rubrique}}}, <:info_racine_site:>}})]\r
+       [(#ENV{secteurlangue}non)<div class="titre">#GET{titre}</div>]\r
+       [(#ENV{secteurlangue}oui)<div class="titre"><:menus:nom_menu_secteurlangue:></div>]\r
+       <div class="infos">\r
+               [(#GET{niveau_max_txt}|=={infini}|non)\r
+                       <:menus:entree_sur_n_niveaux{n=#GET{niveau_max_txt}}:>\r
+               ]\r
+               [(#GET{niveau_max_txt}|=={infini}|oui)\r
+                       <:menus:entree_infini:>\r
+               ]\r
+               [(#GET{id_secteur_exclus}|oui)\r
+                       <:menus:info_secteur_exclus{id_secteur=#ENV{id_secteur_exclus}}:>\r
+               ]\r
+               [(#GET{id_rubriques_exclues}|oui)\r
+                       <:menus:info_rubriques_exclues{id_rubriques=#ENV{id_rubriques_exclues}}:>\r
+               ]\r
+               [(#GET{sousrub_cond}|oui)\r
+                       <br /><:menus:info_sousrub_cond:>\r
+               ]\r
+               [(#GET{rubriques_max_affichees}|<{10000}|oui) / <:menus:info_rubriques_max_affichees{max=#GET{rubriques_max_affichees}}:>]\r
+               <br /><:menus:info_tri:> [(#GET{tri_num}) [(#GET{tri_num_inverse}|=={1}|oui) inverse] <:menus:info_tri_num:>][(#GET{tri_num}|et{GET{tri_alpha}}), ][(#GET{tri_alpha}) [(#GET{tri_alpha_inverse}|=={1}|oui) inverse] <:menus:info_tri_alpha:>]\r
+               [<br /><:menus:info_classe_parent:>(#GET{classe_parent})]\r
+\r
+               [(#GET{afficher_articles}|oui)\r
+                       <br /><:menus:info_afficher_articles:>\r
+                       [(#GET{articles_max}|<{10000}|oui) / <:menus:info_articles_max{max=#GET{articles_max}}:>]\r
+                       [(#GET{articles_max_affiches}|<{10000}|oui) / <:menus:info_articles_max_affiches{max=#GET{articles_max_affiches}}:>]\r
+                       [(#GET{masquer_articles_uniques}|oui) / <:menus:info_masquer_articles_uniques:>]\r
+               ]\r
+               <br /><:menus:info_tri_articles:> [(#GET{tri_num_articles}) [(#GET{tri_num__articles_inverse}|=={1}|oui) inverse] <:menus:info_tri_num:>][(#GET{tri_num_articles}|et{GET{tri_alpha_articles}}), ][(#GET{tri_alpha_articles}) [(#GET{tri_alpha_articles_inverse}|=={1}|oui) inverse] <:menus:info_tri_alpha:>]\r
+       </div>\r
+]\r
+<BOUCLE_appel(CONDITION){si #ENV{appel_menu}|oui}>\r
+       <BOUCLE_rubriques(RUBRIQUES){id_parent=#GET{id_rubrique}}{id_secteur !IN #GET{id_secteur_exclus}}{id_rubrique !IN #GET{id_rubriques_exclues}}{par num #GET{tri_num}}{inverse #GET{tri_num_inverse}}{par #GET{tri_alpha}}{inverse #GET{tri_alpha_inverse}}{0,#GET{rubriques_max_affichees}}>\r
+               #SET{niveau_actuel,#EVAL{1}|intval}\r
+               <li class="menu-entree item[ (#ID_RUBRIQUE|menus_exposer{rubrique,#ENV*{env}})] rub#ID_RUBRIQUE">\r
+                       <a href="#URL_RUBRIQUE">#TITRE</a>\r
+\r
+                       [(#REM) Doit-on descendre plus loin ? ]\r
+                       [(#SET{cond,#GET{niveau_max}|>{#GET{niveau_actuel}}|et{#GET{sousrub_cond}|?{#ID_RUBRIQUE|menus_exposer{rubrique,#ENV*{env}},'on'}}})]\r
+\r
+                       <BOUCLE_test_niveau(CONDITION){si #GET{cond}}>\r
+                               [(#REM) On commence par compter le nombre total de sous-rubriques (servira pour l'item "Toutes les rubriques")]\r
+                               #SET{cpt_sousrub,0}\r
+                               <BOUCLE_cpt_sousrub(RUBRIQUES){id_parent}{id_rubrique !IN #GET{id_rubriques_exclues}}> </BOUCLE_cpt_sousrub>#SET{cpt_sousrub,#TOTAL_BOUCLE}</B_cpt_sousrub>\r
+\r
+                               <B_sous_rubriques>\r
+                                       <ul class="menu-liste menu-items">\r
+                               <BOUCLE_sous_rubriques(RUBRIQUES){id_parent}{id_rubrique !IN #GET{id_rubriques_exclues}}{par num #GET{tri_num}}{inverse #GET{tri_num_inverse}}{par #GET{tri_alpha}}{inverse #GET{tri_alpha_inverse}}{0,#GET{rubriques_max_affichees}}>\r
+                                       #SET{niveau_actuel,#GET{niveau_actuel}|plus{1}}\r
+                                       [(#REM) Doit-on descendre recursivement plus loin ? ]\r
+                                       [(#SET{cond,#GET{niveau_max}|>{#GET{niveau_actuel}}|et{#GET{sousrub_cond}|?{#ID_RUBRIQUE|menus_exposer{rubrique,#ENV*{env}},'on'}}})]\r
+                                       <li class="menu-entree item[ (#ID_RUBRIQUE|menus_exposer{rubrique,#ENV*{env}})] rub#ID_RUBRIQUE">\r
+\r
+                                               [(#REM) ------------------------------------------------\r
+                                                               Positionnement de la classe daddy sur le lien pour indiquer qu'il a un ul a suivre, un autre sous-menu a ouvrir\r
+                                                               si on doit descendre plus loin et\r
+                                                                               - qu'il y a des sous-rubriques a afficher\r
+                                                                               - ou qu'il y a des articles a afficher et qu'on l'a demande ]\r
+                  #SET{class,""}\r
+                                               <BOUCLE_test_classe_parent(CONDITION){si #GET{classe_parent}}>\r
+                     [(#REM) On commence par compter le nombre de sous-rubriques ]\r
+                     #SET{cpt_sousrub_asuivre,0}\r
+                     <BOUCLE_cpt_sousrub_asuivre(RUBRIQUES){id_parent}{id_rubrique !IN #GET{id_rubriques_exclues}}> </BOUCLE_cpt_sousrub_asuivre>#SET{cpt_sousrub_asuivre,#TOTAL_BOUCLE}</B_cpt_sousrub_asuivre>\r
+                     [(#REM) Puis on compte le nombre d'articles ]\r
+                     #SET{cpt_articles_asuivre,0}\r
+                     <BOUCLE_cpt_articles_asuivre(ARTICLES){id_rubrique}{lang}> </BOUCLE_cpt_articles_asuivre>#SET{cpt_articles_asuivre,#TOTAL_BOUCLE}</B_cpt_articles_asuivre>\r
+                     [(#GET{cond}|oui)\r
+                        [(#GET{cpt_sousrub_asuivre}|oui) #SET{class,#GET{classe_parent}}]\r
+                        [(#GET{afficher_articles}|et{#GET{cpt_articles_asuivre}|<={#GET{articles_max}}|oui|et{#GET{cpt_articles_asuivre}|>{1}|ou{#GET{masquer_articles_uniques}|=={'on'}|non}}}) #SET{class,#GET{classe_parent}}]\r
+                     ]\r
+                  </BOUCLE_test_classe_parent>\r
+                                               [(#REM) --------------------------- Fin Positionnement de la classe daddy ]\r
+\r
+                                               <a href="#URL_RUBRIQUE"[ class="(#GET{class})"]>#TITRE</a>\r
+                                               <BOUCLE_test_niveau2(CONDITION){si #GET{cond}}>\r
+                                               <BOUCLE_sous_sous(BOUCLE_sous_rubriques)></BOUCLE_sous_sous>\r
+                                               </BOUCLE_test_niveau2>\r
+                                       </li>\r
+                               </BOUCLE_sous_rubriques>\r
+                                       [(#REM) On affiche le lien vers le reste si on a d�pass� le quota ]\r
+                                       [(#GET{cpt_sousrub}|>{#GET{rubriques_max_affichees}}|oui)\r
+                                               <li class="menu-entree item"><a class="suite" href="#URL_RUBRIQUE"><:menus:toutes_les_rubriques:></a></li>]\r
+\r
+                                       [(#REM) ------------------------------------------------\r
+                                                       Premier cas de gestion de l'affichage des articles \r
+                                                       Ce code est dupliqu� dans les 2e et 3e cas, voir ci dessous (a un ul pres)\r
+                                                       Il n'est pas possible en spip 2 d'utiliser inclure pour eviter la duplication\r
+                                                       Cf http://comments.gmane.org/gmane.comp.web.spip.devel/60475\r
+                                                       Ce doit etre le meme soucis qui fait que #URL_RUBRIQUE est trasnforme en\r
+                                                       spip.php?page=rubrique&id_rubrique=2&connect=condition qu'on enleve avec le filtre parametre_url ]\r
+\r
+                                       <BOUCLE_test_articles_si_sousrub(CONDITION){si #GET{afficher_articles}}>\r
+                                               [(#REM) On commence par compter le nombre d'articles de la rubrique (servira pour l'item "Tous les articles") ]\r
+                                               #SET{cpt,0}\r
+                                               <BOUCLE_cpt_si_sousrub(ARTICLES){id_rubrique}{lang}> </BOUCLE_cpt_si_sousrub>#SET{cpt,#TOTAL_BOUCLE}</B_cpt_si_sousrub>\r
+                       \r
+                                               [(#REM) On affiche les articles :\r
+                                                                       - S'il y en a moins que le max demand� \r
+                                                                       - ET    - si on n'a pas demand� de masquage des articles uniques\r
+                                                                                       - OU si le masquage des articles uniques est demand� et qu'il y en a plus d'un ]\r
+                                               #SET{afficher,non}\r
+                                               [(#GET{cpt}|<={#GET{articles_max}}|oui|et{#GET{cpt}|>{1}|ou{#GET{masquer_articles_uniques}|=={'on'}|non}})\r
+                                                       #SET{afficher,oui}]\r
+\r
+                                               <BOUCLE_test_afficher_si_sousrub(CONDITION){si #GET{afficher}|=={oui}|oui}>\r
+                                                       <BOUCLE_articles_si_sousrub(ARTICLES){id_rubrique}{lang}{par num #GET{tri_num_articles}}{inverse #GET{tri_num_articles_inverse}}{par #GET{tri_alpha_articles}}{inverse #GET{tri_alpha_articles_inverse}}{0,#GET{articles_max_affiches}}>\r
+                                                               <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{article,#ENV*{env}})]">\r
+                                                                       <a href="#URL_ARTICLE">#TITRE</a>\r
+                                                               </li>\r
+                                                       </BOUCLE_articles_si_sousrub>\r
+                                                       [(#GET{cpt}|>{#GET{articles_max_affiches}}|oui)\r
+                                                               <li class="menu-entree item"><a class="suite" href="[(#URL_RUBRIQUE|parametre_url{connect,''})]"><:menus:tous_les_articles:></a></li>]\r
+                                                       </B_articles_si_sousrub>\r
+                                               </BOUCLE_test_afficher_si_sousrub>\r
+                                       </BOUCLE_test_articles_si_sousrub>\r
+                                       [(#REM) --------------------------- Fin Premier cas ]\r
+                                       </ul>\r
+                               </B_sous_rubriques>\r
+\r
+                                       [(#REM) ---------------------------------- \r
+                                                       Second cas de gestion de l'affichage des articles ]\r
+                                       <BOUCLE_test_articles_pas_de_sousrub(CONDITION){si #GET{afficher_articles}}>\r
+                                               [(#REM) On commence par compter le nombre d'articles de la rubrique (servira pour l'item "Tous les articles") ]\r
+                                               #SET{cpt,0}\r
+                                               <BOUCLE_cpt_pas_de_sousrub(ARTICLES){id_rubrique}{lang}> </BOUCLE_cpt_pas_de_sousrub>#SET{cpt,#TOTAL_BOUCLE}</B_cpt_pas_de_sousrub>\r
+\r
+                                               [(#REM) On affiche les articles :\r
+                                                                       - S'il y en a moins que le max demand� \r
+                                                                       - ET    - si on n'a pas demand� de masquage des articles uniques\r
+                                                                                       - OU si le masquage des articles uniques est demand� et qu'il y en a plus d'un ]\r
+                                               #SET{afficher,non}\r
+                                               [(#GET{cpt}|<={#GET{articles_max}}|oui|et{#GET{cpt}|>{1}|ou{#GET{masquer_articles_uniques}|=={'on'}|non}})              \r
+                                                       #SET{afficher,oui}]\r
+\r
+                                               <BOUCLE_test_afficher_pas_de_sousrub(CONDITION){si #GET{afficher}|=={oui}|oui}>\r
+                                                       <B_articles_pas_de_sousrub>\r
+                                                               <ul class="menu-liste menu-items">\r
+                                                       <BOUCLE_articles_pas_de_sousrub(ARTICLES){id_rubrique}{lang}{par num #GET{tri_num_articles}}{inverse #GET{tri_num_articles_inverse}}{par #GET{tri_alpha_articles}}{inverse #GET{tri_alpha_articles_inverse}}{0,#GET{articles_max_affiches}}>\r
+                                                               <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{article,#ENV*{env}})]">\r
+                                                                               <a href="#URL_ARTICLE">#TITRE</a>\r
+                                                               </li>\r
+                                                       </BOUCLE_articles_pas_de_sousrub>\r
+                                                               [(#GET{cpt}|>{#GET{articles_max_affiches}}|oui)\r
+                                                                       <li class="menu-entree item"><a class="suite" href="[(#URL_RUBRIQUE|parametre_url{connect,''})]"><:menus:tous_les_articles:></a></li>]\r
+                                                               </ul>\r
+                                                       </B_articles_pas_de_sousrub>\r
+                                               </BOUCLE_test_afficher_pas_de_sousrub>\r
+                                       </BOUCLE_test_articles_pas_de_sousrub>\r
+                                       [(#REM) --------------------------- Fin Second cas ]\r
+\r
+                               <//B_sous_rubriques>\r
+                       </BOUCLE_test_niveau>\r
+               </li>\r
+       </BOUCLE_rubriques>\r
+\r
+   [(#REM) ---------------------------------- \r
+         troisieme cas de gestion de l'affichage des articles : les articles de la rubriques de d�part ]\r
+   <BOUCLE_test_articles_pas_de_rub(CONDITION){si #GET{afficher_articles}}>\r
+      [(#REM) On commence par compter le nombre d'articles de la rubrique (servira pour l'item "Tous les articles") ]\r
+      #SET{cpt,0}\r
+      <BOUCLE_cpt_pas_de_rub(ARTICLES){id_rubrique=#GET{id_rubrique}}{lang}> </BOUCLE_cpt_pas_de_rub>#SET{cpt,#TOTAL_BOUCLE}</B_cpt_pas_de_rub>\r
+\r
+      [(#REM) On affiche les articles :\r
+               - S'il y en a moins que le max demand� \r
+               - ET    - si on n'a pas demand� de masquage des articles uniques\r
+                     - OU si le masquage des articles uniques est demand� et qu'il y en a plus d'un ]\r
+      #SET{afficher,non}\r
+      [(#GET{cpt}|<={#GET{articles_max}}|oui|et{#GET{cpt}|>{1}|ou{#GET{masquer_articles_uniques}|=={'on'}|non}})               \r
+         #SET{afficher,oui}]\r
+      <BOUCLE_test_afficher_pas_de_rub(CONDITION){si #GET{afficher}|=={oui}|oui}>\r
+         <B_articles_pas_de_rub>\r
+         <BOUCLE_articles_pas_de_rub(ARTICLES){id_rubrique=#GET{id_rubrique}}{lang}{par num #GET{tri_num_articles}}{inverse #GET{tri_num_articles_inverse}}{par #GET{tri_alpha_articles}}{inverse #GET{tri_alpha_articles_inverse}}{0,#GET{articles_max_affiches}}>\r
+            <li class="menu-entree item[ (#ID_ARTICLE|menus_exposer{article,#ENV*{env}})]">\r
+               <a href="#URL_ARTICLE">#TITRE</a>\r
+            </li>\r
+         </BOUCLE_articles_pas_de_rub>\r
+            [(#GET{cpt}|>{#GET{articles_max_affiches}}|oui)\r
+               <li class="menu-entree item"><a class="suite" href="[(#URL_RUBRIQUE|parametre_url{connect,''})]"><:menus:tous_les_articles:></a></li>]\r
+         </B_articles_pas_de_rub>\r
+      </BOUCLE_test_afficher_pas_de_rub>\r
+   </BOUCLE_test_articles_pas_de_rub>\r
+   [(#REM) --------------------------- Fin troisieme cas ]\r
+\r
+</BOUCLE_appel>\r
diff --git a/www/plugins/menus_1/menus/rubriques_completes.xml b/www/plugins/menus_1/menus/rubriques_completes.xml
new file mode 100644 (file)
index 0000000..60c185a
--- /dev/null
@@ -0,0 +1,26 @@
+<entree>\r
+       <nom><:menus:nom_menu_rubriques_completes:></nom>\r
+       <rang>04</rang>\r
+       <description><:menus:description_menu_rubriques_completes:></description>\r
+       <icone>images/menus_rubriques.png</icone>\r
+       <parametre nom="id_rubrique" label="menus:entree_id_rubrique_ou_courante" />\r
+       <parametre nom="id_secteur_exclus" label="menus:entree_id_secteur_exclus" />\r
+       <parametre nom="niveau" label="menus:entree_niveau" />\r
+       <parametre nom="id_rubriques_exclues" label="menus:entree_id_rubriques_exclues" />\r
+       <parametre nom="rubriques_max_affichees" label="menus:entree_rubriques_max_affichees" />\r
+       <parametre nom="sousrub_cond" label="menus:entree_sousrub_cond" />\r
+       <parametre nom="classe_parent" label="menus:entree_classe_parent" />\r
+       <parametre nom="tri_num" label="menus:entree_tri_num" />\r
+       <parametre nom="tri_num_inverse" label="menus:entree_tri_num_inverse" />\r
+       <parametre nom="tri_alpha" label="menus:entree_tri_alpha" />\r
+       <parametre nom="tri_alpha_inverse" label="menus:entree_tri_alpha_inverse" />\r
+       <parametre nom="afficher_articles" label="menus:entree_afficher_articles" />\r
+       <parametre nom="masquer_articles_uniques" label="menus:entree_masquer_articles_uniques" />\r
+       <parametre nom="articles_max" label="menus:entree_articles_max" />\r
+       <parametre nom="articles_max_affiches" label="menus:entree_articles_max_affiches" />\r
+       <parametre nom="tri_num_articles" label="menus:entree_tri_num_articles" />\r
+       <parametre nom="tri_num_articles_inverse" label="menus:entree_tri_num_articles_inverse" />\r
+       <parametre nom="tri_alpha_articles" label="menus:entree_tri_alpha_articles" />\r
+       <parametre nom="tri_alpha_articles_inverse" label="menus:entree_tri_alpha_articles_inverse" />\r
+       <refuser_sous_menu/>\r
+</entree>\r
diff --git a/www/plugins/menus_1/menus/secteurlangue.html b/www/plugins/menus_1/menus/secteurlangue.html
new file mode 100644 (file)
index 0000000..aa50e85
--- /dev/null
@@ -0,0 +1,2 @@
+<BOUCLE_appel(CONDITION){si #ENV{appel_menu}|oui}><BOUCLE_secteur(RUBRIQUES){racine}{lang}{0,1}>#SET{id_rubrique,#ID_RUBRIQUE}</BOUCLE_secteur></BOUCLE_appel>
+#INCLURE{fond=menus/rubriques_completes,id_rubrique=#GET{id_rubrique},secteurlangue=oui,env}
diff --git a/www/plugins/menus_1/menus/secteurlangue.xml b/www/plugins/menus_1/menus/secteurlangue.xml
new file mode 100644 (file)
index 0000000..3ae2299
--- /dev/null
@@ -0,0 +1,21 @@
+<entree>\r
+       <nom><:menus:nom_menu_secteurlangue:></nom>\r
+       <description><:menus:description_menu_secteurlangue:></description>\r
+       <icone>images/menus_secteurlangue.png</icone>\r
+       <parametre nom="niveau" label="menus:entree_niveau" />\r
+       <parametre nom="sousrub_cond" label="menus:entree_sousrub_cond" />\r
+       <parametre nom="classe_parent" label="menus:entree_classe_parent" />\r
+       <parametre nom="tri_num" label="menus:entree_tri_num" />\r
+       <parametre nom="tri_num_inverse" label="menus:entree_tri_num_inverse" />\r
+       <parametre nom="tri_alpha" label="menus:entree_tri_alpha" />\r
+       <parametre nom="tri_alpha_inverse" label="menus:entree_tri_alpha_inverse" />\r
+       <parametre nom="afficher_articles" label="menus:entree_afficher_articles" />\r
+       <parametre nom="masquer_articles_uniques" label="menus:entree_masquer_articles_uniques" />\r
+       <parametre nom="articles_max" label="menus:entree_articles_max" />\r
+       <parametre nom="articles_max_affiches" label="menus:entree_articles_max_affiches" />\r
+       <parametre nom="tri_num_articles" label="menus:entree_tri_num_articles" />\r
+       <parametre nom="tri_num_articles_inverse" label="menus:entree_tri_num_articles_inverse" />\r
+       <parametre nom="tri_alpha_articles" label="menus:entree_tri_alpha_articles" />\r
+       <parametre nom="tri_alpha_articles_inverse" label="menus:entree_tri_alpha_articles_inverse" />\r
+       <refuser_sous_menu/>\r
+</entree>\r
diff --git a/www/plugins/menus_1/menus/texte_libre.html b/www/plugins/menus_1/menus/texte_libre.html
new file mode 100644 (file)
index 0000000..596a6a2
--- /dev/null
@@ -0,0 +1,10 @@
+#SET{contenu, #ENV*{contenu}|_T_ou_typo}
+
+[(#ENV{appel_formulaire}|oui)
+       <div class="titre">[(#GET{contenu}|expanser_liens)]</div>
+       <div class="infos"></div>
+]
+[(#ENV{appel_menu}|oui)
+       <li class="menu-entree item[ (#ENV{css})]">
+               <span class="texte_libre">[(#GET{contenu}|expanser_liens)]</span>
+]
diff --git a/www/plugins/menus_1/menus/texte_libre.xml b/www/plugins/menus_1/menus/texte_libre.xml
new file mode 100644 (file)
index 0000000..309526d
--- /dev/null
@@ -0,0 +1,8 @@
+<entree>
+       <nom><:menus:nom_menu_texte_libre:></nom>
+       <rang>2</rang>
+       <description><:menus:description_menu_texte_libre:></description>
+       <icone>images/menus_texte_libre.png</icone>
+       <parametre nom="contenu" label="menus:entree_contenu" class="multilang" obligatoire="oui" />
+       <parametre nom="css" label="menus:entree_css" />
+</entree>
diff --git a/www/plugins/menus_1/menus_administrations.php b/www/plugins/menus_1/menus_administrations.php
new file mode 100644 (file)
index 0000000..963514b
--- /dev/null
@@ -0,0 +1,43 @@
+<?php\r
+\r
+// Sécurité\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+include_spip('inc/meta');\r
+\r
+// Installation et mise à jour\r
+function menus_upgrade($nom_meta_version_base, $version_cible){\r
+       $maj = array();\r
+       \r
+       $maj['create'] = array(\r
+               array('creer_base'),\r
+               array('ecrire_config', 'menus/entrees_masquees', array('rubriques', 'groupe_mots', 'mapage', 'deconnecter', 'secteurlangue')),\r
+       );\r
+       \r
+       $maj['0.5.0'] = array(\r
+               array('sql_alter', "TABLE spip_menus ADD COLUMN css tinytext DEFAULT '' NOT NULL"),\r
+       );\r
+       \r
+       $maj['0.5.1'] = array(\r
+               array('sql_updateq', 'spip_menus_entrees', array('type_entree'=>'rubriques_completes'), 'type_entree = '.sql_quote('rubriques')),\r
+       );\r
+       \r
+       include_spip('base/upgrade');\r
+       maj_plugin($nom_meta_version_base, $version_cible, $maj);\r
+}\r
+\r
+// Désinstallation\r
+function menus_vider_tables($nom_meta_version_base){\r
+       include_spip('base/abstract_sql');\r
+       \r
+       // On efface les tables du plugin\r
+       sql_drop_table('spip_menus');\r
+       sql_drop_table('spip_menus_entrees');\r
+               \r
+       // On efface la version enregistrée\r
+       effacer_meta($nom_meta_version_base);\r
+       // On efface la config\r
+       effacer_meta('menus');\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/menus_1/menus_fonctions.php b/www/plugins/menus_1/menus_fonctions.php
new file mode 100644 (file)
index 0000000..1d84cdf
--- /dev/null
@@ -0,0 +1,25 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function menus_type_entree($nom){
+       include_spip('inc/menus');
+       $infos = menus_informer($nom);
+       return $infos['nom'];
+}
+
+function menus_type_refuser_sous_menu($nom){
+       include_spip('inc/menus');
+       $infos = menus_informer($nom);
+       return $infos['refuser_sous_menu'];
+}
+
+function menus_exposer($id_objet, $objet, $env, $on='on active', $off=''){
+       if (is_string($env))
+               $env = unserialize($env);
+       $primary = id_table_objet($objet);
+       include_spip('public/quete');
+       return calcul_exposer($id_objet, $primary, $env, '', $primary) ? $on : $off;
+}
+?>
diff --git a/www/plugins/menus_1/menus_ieconfig.php b/www/plugins/menus_1/menus_ieconfig.php
new file mode 100644 (file)
index 0000000..f94656f
--- /dev/null
@@ -0,0 +1,139 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * Pipeline ieconfig pour l'import/export de configuration\r
+ *\r
+ * @param array $flux\r
+ * @return array\r
+ */\r
+function menus_ieconfig($flux){\r
+       include_spip('inc/texte');\r
+       $action = $flux['args']['action'];\r
+       \r
+       // Formulaire d'export\r
+       if ($action=='form_export') {\r
+               $saisies = array(\r
+                       array(\r
+                               'saisie' => 'fieldset',\r
+                               'options' => array(\r
+                                       'nom' => 'menus_export',\r
+                                       'label' => '<:menus:editer_menus_titre:>',\r
+                                       'icone' => 'menu-16.png'\r
+                               ),\r
+                               'saisies' => array(\r
+                                       array(\r
+                                               'saisie' => 'menus_multiple',\r
+                                               'options' => array(\r
+                                                       'nom' => 'menus_a_exporter',\r
+                                                       'label' => '<:menus:formulaire_ieconfig_menus_a_exporter:>',\r
+                                                       'cacher_option_intro' => 'oui'\r
+                                               )\r
+                                       )\r
+                               )\r
+                       )\r
+               );\r
+               $flux['data'] = array_merge($flux['data'],$saisies);\r
+       }\r
+       \r
+       // Tableau d'export\r
+       if ($action=='export' && is_array(_request('menus_a_exporter')) && count(_request('menus_a_exporter'))>0) {\r
+               $flux['data']['menus'] = array();\r
+               include_spip('base/abstract_sql');\r
+               include_spip('action/exporter_menu');\r
+               foreach (_request('menus_a_exporter') as $identifiant) {\r
+                       $menu = sql_fetsel(array('id_menu','titre','css'),'spip_menus','identifiant = '.sql_quote($identifiant));\r
+                       $id_menu = $menu['id_menu'];\r
+                       unset($menu['id_menu']);\r
+                       $menu['entrees'] = exporter_menu_recursif($id_menu);\r
+                       $flux['data']['menus'][$identifiant] = $menu;\r
+               }\r
+       }\r
+       \r
+       // Formulaire d'import\r
+       if ($action=='form_import' && isset($flux['args']['config']['menus']) && is_array($flux['args']['config']['menus']) && count($flux['args']['config']['menus'])>0) {\r
+               $saisies = array(\r
+                       array(\r
+                               'saisie' => 'fieldset',\r
+                               'options' => array(\r
+                                       'nom' => 'menus_import',\r
+                                       'label' => '<:menus:editer_menus_titre:>',\r
+                                       'icone' => 'menu-16.png'\r
+                               ),\r
+                               'saisies' => array(\r
+                                       array(\r
+                                               'saisie' => 'explication',\r
+                                               'options' => array(\r
+                                                       'nom' => 'menus_import_explication',\r
+                                                       'texte' => '<:menus:formulaire_ieconfig_choisir_menus_a_importer:>'\r
+                                               )\r
+                                       )\r
+                               )\r
+                       )\r
+               );\r
+               foreach ($flux['args']['config']['menus'] as $identifiant => $menu) {\r
+                       if (sql_countsel('spip_menus','identifiant = '.sql_quote($identifiant))>0) {\r
+                               $saisies[0]['saisies'][] = array(\r
+                                       'saisie' => 'selection',\r
+                                       'options' => array(\r
+                                               'nom' => 'menus_importer_'.$identifiant,\r
+                                               'label' => $identifiant.(isset($menu['titre']) ? ' ('.typo($menu['titre']).')' : ''),\r
+                                               'cacher_option_intro' => 'oui',\r
+                                               'attention' => '<:menus:formulaire_ieconfig_menu_meme_identifiant:>',\r
+                                               'datas' => array(\r
+                                                       'non' => '<:menus:formulaire_ieconfig_ne_pas_importer:>',\r
+                                                       'renommer' => '<:menus:formulaire_ieconfig_renommer:>',\r
+                                                       'remplacer' => '<:menus:formulaire_ieconfig_remplacer:>'\r
+                                               )\r
+                                       )\r
+                               );\r
+                       } else {\r
+                               $saisies[0]['saisies'][] = array(\r
+                                       'saisie' => 'selection',\r
+                                       'options' => array(\r
+                                               'nom' => 'menus_importer_'.$identifiant,\r
+                                               'label' => $identifiant.(isset($menu['titre']) ? ' ('.typo($menu['titre']).')' : ''),\r
+                                               'cacher_option_intro' => 'oui',\r
+                                               'datas' => array(\r
+                                                       'non' => '<:menus:formulaire_ieconfig_ne_pas_importer:>',\r
+                                                       'importer' => '<:menus:formulaire_ieconfig_importer:>'\r
+                                               )\r
+                                       )\r
+                               );\r
+                       }\r
+               }\r
+               $flux['data'] = array_merge($flux['data'],$saisies);\r
+       }\r
+       \r
+       // Import de la configuration\r
+       if ($action=='import' && isset($flux['args']['config']['menus']) && is_array($flux['args']['config']['menus']) && count($flux['args']['config']['menus'])>0) {\r
+               foreach ($flux['args']['config']['menus'] as $identifiant => $menu) {\r
+                       $choix = _request('menus_importer_'.$identifiant);\r
+                       include_spip('base/abstract_sql');\r
+                       include_spip('inc/menus');\r
+                       include_spip('action/editer_menu');\r
+                       if ($choix == 'remplacer') {\r
+                               $id_menu = intval(sql_getfetsel('id_menu','spip_menus','identifiant = '.sql_quote($identifiant)));\r
+                               menus_supprimer_menu($id_menu);\r
+                       }\r
+                       if ($choix == 'renommer')\r
+                               $identifiant = $identifiant.'_'.time();\r
+                       if (in_array($choix,array('importer','remplacer','renommer'))) {\r
+                               $titre = isset($menu['titre']) ? $menu['titre'] : '';\r
+                               $css = isset($menu['css']) ? $menu['css'] : '';\r
+                               $id_menu = sql_insertq('spip_menus',array(\r
+                                       'identifiant' => $identifiant,\r
+                                       'titre' => $titre,\r
+                                       'css' => $css\r
+                               ));\r
+                               if (isset($menu['entrees']))\r
+                                       menus_importer($menu['entrees'], $id_menu);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       return($flux);\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/menus_1/menus_pipelines.php b/www/plugins/menus_1/menus_pipelines.php
new file mode 100644 (file)
index 0000000..ada042a
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function menus_header_prive($flux){
+       $css = find_in_path('css/menuspip.css');
+       $flux .= "\n<link rel='stylesheet' href='$css' type='text/css' />\n";
+       return $flux;
+}
+
+function menus_pre_boucle($boucle){
+       if ($boucle->type_requete == 'menus') {
+               $id_table = $boucle->id_table;
+               $id_menus_entree = "$id_table.id_menus_entree";
+               if (!isset($boucle->modificateur['criteres']['id_menus_entree']) and !isset($boucle->modificateur['criteres']['id_menu']) and !isset($boucle->modificateur['criteres']['identifiant'])){
+                       $boucle->where[] = array(sql_quote('='), sql_quote($id_menus_entree), 0);
+               }
+       }
+       return $boucle;
+}
+
+function menus_menus_lister_disponibles($flux){
+       return $flux;
+}
+
+function menus_declarer_url_objets($array){
+    $array[] = 'menu';
+    return $array;
+}
+?>
diff --git a/www/plugins/menus_1/noisettes/menu-preview.html b/www/plugins/menus_1/noisettes/menu-preview.html
new file mode 100644 (file)
index 0000000..b29517a
--- /dev/null
@@ -0,0 +1 @@
+<BOUCLE_menu(MENUS){identifiant=#ENV{identifiant}}>[<a href="#URL_ECRIRE{menus_editer,id_menu=#ID_MENU}">(#TITRE)</a>]</BOUCLE_menu>
\ No newline at end of file
diff --git a/www/plugins/menus_1/noisettes/menu.html b/www/plugins/menus_1/noisettes/menu.html
new file mode 100644 (file)
index 0000000..d183a3b
--- /dev/null
@@ -0,0 +1,6 @@
+<BOUCLE_menu(MENUS){identifiant=#ENV{identifiant}}>\r
+       <div class="menu">\r
+               [(#ENV{afficher_titre_menu}|oui)[<h2 class="h2">(#TITRE|typo)</h2>]]\r
+               #INCLURE{fond=inclure/menu, env, identifiant=#IDENTIFIANT}\r
+       </div>\r
+</BOUCLE_menu>
\ No newline at end of file
diff --git a/www/plugins/menus_1/noisettes/menu.yaml b/www/plugins/menus_1/noisettes/menu.yaml
new file mode 100644 (file)
index 0000000..62dc23a
--- /dev/null
@@ -0,0 +1,16 @@
+nom: '<:menus:noisette_nom_noisette:>'\r
+description: '<:menus:noisette_description:>'\r
+icon: 'menu-24.png'\r
+parametres:\r
+  -\r
+    saisie: 'menu'\r
+    options:\r
+      nom: 'identifiant'\r
+      label: '<:menus:noisette_label_identifiant:>'\r
+      cacher_option_intro: 'oui'\r
+  -\r
+    saisie: 'oui_non'\r
+    options:\r
+      nom: 'afficher_titre_menu'\r
+      label: '<:menus:noisette_label_afficher_titre_menu:>'\r
+      defaut: 'on'
\ No newline at end of file
diff --git a/www/plugins/menus_1/paquet.xml b/www/plugins/menus_1/paquet.xml
new file mode 100644 (file)
index 0000000..e766ca3
--- /dev/null
@@ -0,0 +1,39 @@
+<paquet\r
+       prefix="menus"\r
+       categorie="navigation"\r
+       version="1.4.5"\r
+       etat="test"\r
+       compatibilite="[3.0.0;3.0.*]"\r
+       logo="prive/themes/spip/images/menu-32.png"\r
+       documentation="http://www.spip-contrib.net/Plugin-Menus"\r
+       schema="0.5.1"\r
+>\r
+       <nom>Menus</nom>\r
+\r
+       <auteur>RastaPopoulos</auteur>\r
+       <auteur lien="http://www.ldd.fr">Les Développements Durables</auteur>\r
+       <licence>GPL v3</licence>\r
+\r
+       <traduire module="menus" reference="fr" gestionnaire="salvatore" />\r
+\r
+       <pipeline nom="declarer_tables_principales" inclure="base/menus_tables.php" />\r
+       <pipeline nom="declarer_tables_interfaces" inclure="base/menus_tables.php" />\r
+       <pipeline nom="header_prive" inclure="menus_pipelines.php" />\r
+       <pipeline nom="pre_boucle" inclure="menus_pipelines.php" />\r
+       <pipeline nom="menus_lister_disponibles" inclure="menus_pipelines.php" />\r
+       <pipeline nom="declarer_url_objets" inclure="menus_pipelines.php" />\r
+       <pipeline nom="autoriser" inclure="inc/menus_autoriser.php" />\r
+       <pipeline nom="ieconfig" inclure="menus_ieconfig.php" />\r
+\r
+       <menu nom="menus_tous" titre="menus:editer_menus_titre" parent="menu_squelette" icone="images/menu-16.png" />\r
+\r
+       <!-- pour _T_ou_typo -->\r
+       <necessite nom="saisies" compatibilite="[1.9.10;]" />\r
+       \r
+       <utilise nom="Z" />\r
+       <utilise nom="Zpip" />\r
+       <utilise nom="spipr" />\r
+       <utilise nom="spipr_blog" />\r
+       <utilise nom="spipr_dist" />\r
+       <utilise nom="spipr_doc" />\r
+</paquet>\r
diff --git a/www/plugins/menus_1/prive/squelettes/contenu/configurer_menus.html b/www/plugins/menus_1/prive/squelettes/contenu/configurer_menus.html
new file mode 100644 (file)
index 0000000..b9143b1
--- /dev/null
@@ -0,0 +1,2 @@
+<h1>Configurer les entrées du plugin Menus</h1>
+<div class="ajax">#FORMULAIRE_CONFIGURER_MENUS</div>
diff --git a/www/plugins/menus_1/prive/squelettes/contenu/menus_editer.html b/www/plugins/menus_1/prive/squelettes/contenu/menus_editer.html
new file mode 100644 (file)
index 0000000..aedf9f0
--- /dev/null
@@ -0,0 +1,25 @@
+
+<div class="cadre-formulaire-editer">
+       <div class="entete-formulaire">
+               [(#URL_ECRIRE{menus_tous}|icone_verticale{<:retour:>,menus-24,'',left})]
+               <:menus:formulaire_modifier_menu:>
+               <h1>
+                       <BOUCLE_menu(MENUS){id_menu=#VAL{id_menu}|_request}>
+                       #TITRE
+                       </BOUCLE_menu>
+                       [(#ENV{nouveau}|=={oui}|?{<:menus:formulaire_nouveau:>,#VAL{id_menu}|_request})]
+                       <//B_menu>
+               </h1>
+       </div>
+       #FORMULAIRE_EDITER_MENU{#ENV{id_menu,0}, #ENV{nouveau,''}}
+       [(#ENV{id_menu,0}|intval|oui)
+               <div class="ajax">#FORMULAIRE_EDITER_MENUS_ENTREE{#ENV{id_menu}}</div>
+       ]
+
+</div>
+
+[(#ENV{id_menu,0}|intval|oui)
+[<div class="actions">
+(#URL_ACTION_AUTEUR{supprimer_menu,#ENV{id_menu},#URL_ECRIRE{menus_tous}}|icone_verticale{<:menus:formulaire_supprimer_menu:>,menus-24.png,del})
+</div>]
+]
diff --git a/www/plugins/menus_1/prive/squelettes/contenu/menus_tous.html b/www/plugins/menus_1/prive/squelettes/contenu/menus_tous.html
new file mode 100644 (file)
index 0000000..32c51a6
--- /dev/null
@@ -0,0 +1,20 @@
+
+<h1 class="grostitre"><:menus:editer_menus_titre:></h1>
+<p><:menus:editer_menus_explication:></p>
+
+<B_menus_principaux>
+<ul class="liste_items">
+       <BOUCLE_menus_principaux(MENUS){par titre}>
+       <li class="item">#SET{auth,#AUTORISER{modifier,menu,#ID_MENU}}
+               [(#GET{auth}|oui)<a href="[(#URL_ECRIRE{menus_editer,id_menu=#ID_MENU})]">]#TITRE (#IDENTIFIANT)[(#GET{auth}|oui)</a>]
+               <p class='actions'>
+                       [(#AUTORISER{modifier,menu,#ID_MENU})   <span class='lien_modifier'>&#91;<a href='[(#URL_ECRIRE{menus_editer,id_menu=#ID_MENU})]'><:menus:editer_menus_editer:></a>&#93;</span>]
+               </p>
+       </li>
+       </BOUCLE_menus_principaux>
+</ul>
+</B_menus_principaux>
+
+[(#URL_ECRIRE{menus_editer}|parametre_url{nouveau,oui}|icone_verticale{<:menus:editer_menus_nouveau:>,menus-24.png,new,right})]
+
+<div class="nettoyeur"></div>
diff --git a/www/plugins/menus_1/prive/squelettes/navigation/menus_editer.html b/www/plugins/menus_1/prive/squelettes/navigation/menus_editer.html
new file mode 100644 (file)
index 0000000..9456afb
--- /dev/null
@@ -0,0 +1,19 @@
+[(#ENV{id_menu,0}|intval|oui)
+[(#BOITE_OUVRIR{'','info'})]
+       <div class="infos">
+               <div class="numero">
+                       <:menus:info_numero_menu:>
+                       <p>[(#ENV{id_menu})]</p>
+               </div>
+               [(#VAL{redirect}
+                       |generer_url_action{type=menu&id=#ENV{id_menu}}
+                       |parametre_url{var_mode,calcul}
+                       |icone_horizontale{<:icone_voir_en_ligne:>,racine})]
+
+               [(#PLUGIN{yaml}|oui)
+                       [(#URL_ACTION_AUTEUR{exporter_menu,#ENV{id_menu}}
+                               |icone_horizontale{<:menus:editer_menus_exporter:>,menu-export-24.png})]
+               ]
+       </div>
+#BOITE_FERMER
+]
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-16.png b/www/plugins/menus_1/prive/themes/spip/images/menu-16.png
new file mode 100644 (file)
index 0000000..dafabc8
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-16.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-24.png b/www/plugins/menus_1/prive/themes/spip/images/menu-24.png
new file mode 100644 (file)
index 0000000..841aec5
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-24.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-32.png b/www/plugins/menus_1/prive/themes/spip/images/menu-32.png
new file mode 100644 (file)
index 0000000..e719a85
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-32.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-add-16.png b/www/plugins/menus_1/prive/themes/spip/images/menu-add-16.png
new file mode 100644 (file)
index 0000000..5b75b15
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-add-16.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-add-24.png b/www/plugins/menus_1/prive/themes/spip/images/menu-add-24.png
new file mode 100644 (file)
index 0000000..2a652c5
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-add-24.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-add-32.png b/www/plugins/menus_1/prive/themes/spip/images/menu-add-32.png
new file mode 100644 (file)
index 0000000..6399f30
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-add-32.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-del-16.png b/www/plugins/menus_1/prive/themes/spip/images/menu-del-16.png
new file mode 100644 (file)
index 0000000..5acfd8c
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-del-16.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-del-24.png b/www/plugins/menus_1/prive/themes/spip/images/menu-del-24.png
new file mode 100644 (file)
index 0000000..fb5bffd
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-del-24.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-del-32.png b/www/plugins/menus_1/prive/themes/spip/images/menu-del-32.png
new file mode 100644 (file)
index 0000000..62be59a
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-del-32.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-export-24.png b/www/plugins/menus_1/prive/themes/spip/images/menu-export-24.png
new file mode 100644 (file)
index 0000000..046697e
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-export-24.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menu-exporter-24.png b/www/plugins/menus_1/prive/themes/spip/images/menu-exporter-24.png
new file mode 100644 (file)
index 0000000..22b6ae3
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menu-exporter-24.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menus-16.png b/www/plugins/menus_1/prive/themes/spip/images/menus-16.png
new file mode 100644 (file)
index 0000000..4807b53
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menus-16.png differ
diff --git a/www/plugins/menus_1/prive/themes/spip/images/menus-24.png b/www/plugins/menus_1/prive/themes/spip/images/menus-24.png
new file mode 100644 (file)
index 0000000..563d388
Binary files /dev/null and b/www/plugins/menus_1/prive/themes/spip/images/menus-24.png differ
diff --git a/www/plugins/menus_1/saisies-vues/menu.html b/www/plugins/menus_1/saisies-vues/menu.html
new file mode 100644 (file)
index 0000000..0b4cb5e
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_menu(MENUS){identifiant=#ENV{valeur}}>
+<p>[(#TITRE|typo)] (#IDENTIFIANT)</p>
+</BOUCLE_menu>
+<p><:saisies:vue_sans_reponse:></p>
+<//B_menu>
\ No newline at end of file
diff --git a/www/plugins/menus_1/saisies-vues/menus_multiple.html b/www/plugins/menus_1/saisies-vues/menus_multiple.html
new file mode 100644 (file)
index 0000000..31252e6
--- /dev/null
@@ -0,0 +1,9 @@
+<B_choix>
+<ul>
+       <BOUCLE_choix(MENUS){identifiant IN #ENV**{valeur}}>
+       <li class="choix">[(#TITRE|typo)] (#IDENTIFIANT)</li>
+       </BOUCLE_choix>
+</ul>
+</B_choix>
+<p>#ENV{sans_reponse}</p>
+<//B_choix>
\ No newline at end of file
diff --git a/www/plugins/menus_1/saisies/menu.html b/www/plugins/menus_1/saisies/menu.html
new file mode 100644 (file)
index 0000000..ca0bc4e
--- /dev/null
@@ -0,0 +1,20 @@
+[(#REM) 
+  Saisie permettant de sélectionner un menu par son identifiant
+       
+  Parametres :
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - class : classe(s) css ajoutes au select
+  
+  Exemple d'appel :
+       [(#SAISIE{menu,nom,
+               label=<:plugin:label:>,
+       })] 
+]
+
+<select name="#ENV{nom}" id="champ_#ENV{nom}"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_selection(MENUS){par titre}>
+       <option value="#IDENTIFIANT" [(#IDENTIFIANT|=={#ENV{valeur,#ENV{defaut}}}|oui) selected="selected"]>[(#TITRE|typo)] (#IDENTIFIANT)</option>
+</BOUCLE_selection>
+</select>
diff --git a/www/plugins/menus_1/saisies/menus_multiple.html b/www/plugins/menus_1/saisies/menus_multiple.html
new file mode 100644 (file)
index 0000000..564a8c1
--- /dev/null
@@ -0,0 +1,24 @@
+[(#REM) 
+  Saisie permettant de sélectionner plusieurs menus par leur identifiant
+       
+  Parametres :
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - class : classe(s) css ajoutes au select
+  
+  Exemple d'appel :
+       [(#SAISIE{menus_multiple,nom,
+               label=<:plugin:label:>,
+       })] 
+]
+
+[(#REM) defaut peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
+#SET{defaut, #ENV{defaut}}
+#SET{defaut, #GET{defaut}|is_string|?{(#GET{defaut}|saisies_chaine2tableau), (#GET{defaut}|sinon{#ARRAY})}}
+
+<select name="#ENV{nom}[]" id="champ_#ENV{nom}" multiple="multiple"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_selection(MENUS){par titre}>
+       <option value="#IDENTIFIANT" [(#IDENTIFIANT|in_array{#ENV{valeur,#GET{defaut}}}|oui) selected="selected"]>[(#TITRE|typo)] (#IDENTIFIANT)</option>
+</BOUCLE_selection>
+</select>
diff --git a/www/plugins/menus_1/svn.revision b/www/plugins/menus_1/svn.revision
new file mode 100644 (file)
index 0000000..9a2fabc
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/menus/trunk
+Revision: 73250
+Dernier commit: 2013-06-04 14:42:03 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/menus/trunk</origine>
+<revision>73250</revision>
+<commit>2013-06-04 14:42:03 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/multilang/alire.txt b/www/plugins/multilang/alire.txt
new file mode 100644 (file)
index 0000000..05e8bb7
--- /dev/null
@@ -0,0 +1,71 @@
+\r
+Tous les champs input:text et textarea sauf ceux des forms .form_upload et .form_upload_icon sont traites dans :\r
+- articles\r
+- rubriques\r
+- configuration du site\r
+- auteurs (interessant uniquement pour le champs BIO)\r
+- documents dans les colonnes de gauche des pages d'edition d'articles et de rubriques\r
+- documents dans les parties basses des pages de presentation des articles et rubriques\r
+- groupe de mots cles\r
+- mots cles\r
+- sites\r
+- Breves\r
+\r
+\r
+A faire :\r
+- F&T : pb de doublon avec forms_lang.js\r
+- Integration avec Porte-Plume : quand on change de langue, la previsu "Voir" ne bascule pas\r
+\r
+- Suggestion de RastaPopoulos : J'avais une idée supplémentaire pour que ce soit extensible : activer également ce système sur tous les champs ayant une classe "multilang". Fait, a tester avec class "multilang"\r
+\r
+Trucs a regler :\r
+1.-------------\r
+Avec Mediatheque, l'init est rappelee grace au onAjaxLoad. Et affiche bien le menu lang dans la modale. Mais un 2e menu est aussi rajoute dans le doc principal sous la modale de mediatheque... De meme quand on ferme la modale, on repasse par l'init... Et on se retrouve avec un 3e menu. J'ai donc interdit la creation d'un menu s'il en existe deja un dans la div :\r
+fct forms_init_multi :\r
+               if(!container.find('.menu_lang').size())\r
+                       container.prepend("<div class='menu_lang'>");\r
+et supprime le test de la fonction d'init (qui est un peu bourrin de toute facon):\r
+       //if(multilang_root.find('.menu_lang').length > 0) return;\r
+\r
+Premier bug : Dans une page d'edition article ou rubrique, si on modifie le doc + enregistrer le doc, PUIS enregistrer l'article (ou la rubrique) on passe 2 fois dans le submit et les champs ont la structure multi en double\r
+\r
+Solution : \r
+function forms_attach_submit() {\r
+       if($(this).parents('.ajax').size() && $(this).find('input[name=var_ajax]')){\r
+               $(this).bind('form-pre-serialize',forms_multi_submit);\r
+       }else{\r
+               var oldsubmit = this.onsubmit;\r
+               this.onsubmit = "";\r
+               if(oldsubmit && oldsubmit != "")\r
+                       $(this).submit(function(){forms_multi_submit.apply(this);return oldsubmit.apply(this);})\r
+               else\r
+                       if(oldsubmit != "")$(this).submit(forms_multi_submit);\r
+       }\r
+}\r
+Ca marche mais je ne pige pas bien...  En fait quand on charge la page d'edition, le this.onsubmit est undefined et on rajoute une action sur le submit : forms_multi_submit . Lors du 2e passage (onAjaxLoad), le this.onsubmit vaut "" et on rajoutait une 2e fois le forms_multi_submit... Mais pourquoi une chaine vide ?\r
+\r
+Avec ou sans mediatheque, donc maintenant ca fonctionne\r
+\r
+2.---------------\r
+Dans le pipeline, j'ai rajoute un 2e passage par l'init pour la suggestion de Rasta :\r
+forms_selector = $(".multilang").parents("form")\r
+multilang_init_lang({fields:".multilang",forms:forms_selector});\r
+du coup, y'a pas de root de defini, donc le multilang agit sur tout le document\r
+\r
+Effet, le le menu lang s'affiche bien, mais ne fonctionne plus\r
+\r
+En fait faut pas passer 2 fois dans la fonction d'init. Ce n'est pas prevu pour. Donc faut tout integrer en un appel :\r
+\r
+       jQuery(document).ready(function(){\r
+               function multilang_init(){\r
+                       root = "'.$root.'" ;\r
+                       fields_selector = "textarea,input:text:not(input#id_parent,input.password,input#new_login,#titreparent,*.nomulti),.multilang" ;\r
+                       forms_selector = ".multilang:parent,form[class!=\'form_upload\'][class!=\'form_upload_icon\']" ;\r
+                       multilang_init_lang({fields:fields_selector,root:root,forms:forms_selector});\r
+               }\r
+               multilang_init();\r
+               if(typeof onAjaxLoad == "function") onAjaxLoad(multilang_init);\r
+       });\r
+\r
+Bon donc ca marche toujours avec ou sans mediatheque... Reste plus qu'a tester avec un plugin qui veut du multilang\r
+       \r
diff --git a/www/plugins/multilang/formulaires/configurer_multilang.html b/www/plugins/multilang/formulaires/configurer_multilang.html
new file mode 100644 (file)
index 0000000..1cf4c1e
--- /dev/null
@@ -0,0 +1,72 @@
+<div class="formulaire_spip formulaire_configurer formulaire_#FORM">\r
+\r
+   [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]\r
+   [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]\r
+\r
+   <form method="post" action="#ENV{action}">\r
+   <div>\r
+      #ACTION_FORMULAIRE{#ENV{action}}\r
+\r
+      <ul>\r
+         <li class="fieldset">\r
+            <fieldset>\r
+               <h3 class="legend"><:multilang:cfg_activer:></h3>\r
+               <ul>\r
+                  [(#SAISIE{oui_non,siteconfig,\r
+                     label=<:multilang:cfg_lbl_siteconfig:>,\r
+                     defaut=on}\r
+                  )]\r
+                  #SET{defaut_on,#LISTE{rubrique,auteur,document}}\r
+                  <BOUCLE_objets(DATA){source tableau,#REM|lister_tables_objets_sql}>\r
+                  [(#VALEUR{editable}|=={oui}|oui)\r
+                       [(#SET{name,[(#CLE|objet_type)]})]\r
+                       [(#SET{label,[(#VALEUR{texte_objets}|_T)]})]\r
+                                       [(#SAISIE{oui_non,#GET{name},\r
+                            label=#GET{label},\r
+                            defaut=''})]\r
+                                       ]</BOUCLE_objets>\r
+                  \r
+                                 [(#PLUGIN{agenda}|oui)\r
+                                         [(#SAISIE{oui_non,evenement,\r
+                            label=<:multilang:cfg_lbl_evenement:>,\r
+                            defaut=''}\r
+                         )]\r
+                                 ]\r
+                                 [(#PLUGIN{gis}|oui)\r
+                                         [(#SAISIE{oui_non,gis,\r
+                            label=<:multilang:cfg_lbl_gis:>,\r
+                            defaut=''}\r
+                         )]\r
+                                 ]\r
+                                 [(#SAISIE{oui_non,multilang_public,\r
+                     label=<:multilang:cfg_lbl_espace_public:>,\r
+                     defaut=off}\r
+                  )]\r
+                                 [(#SAISIE{oui_non,multilang_crayons,\r
+                     label=<:multilang:cfg_lbl_crayons:>,\r
+                                        explication=<:multilang:cfg_explication_crayons:>,\r
+                     defaut=''}\r
+                  )]\r
+               </ul>\r
+            </fieldset>\r
+         </li>\r
+         <li class="fieldset">\r
+                       <fieldset>\r
+                               <h3 class="legend"><:multilang:cfg_langues:></h3>\r
+                               [(#SET{langues,[(#CONFIG{langues_multilingue}|explode{','}|multilang_nommer_langues)]})]\r
+                               [(#SAISIE{selection_multiple,langues_utilisees,\r
+                                       label=<:multilang:label_langues_utilisees:>,\r
+                                       explication=<:multilang:explication_langues_utilisees:>,\r
+                                       cacher_option_intro=oui,\r
+                                       datas=#GET{langues},\r
+                                       size=[(#GET{langues}|count|>{10}|?{10,#GET{langues}|count})]})]\r
+                       </fieldset>\r
+               </li>\r
+      </ul>\r
+\r
+      <p class="boutons">\r
+         <input type="submit" name="_cfg_ok" class="submit" value="<:bouton_enregistrer:>" />\r
+      </p>\r
+   </div>\r
+   </form>\r
+</div>\r
diff --git a/www/plugins/multilang/formulaires/configurer_multilang_fonctions.php b/www/plugins/multilang/formulaires/configurer_multilang_fonctions.php
new file mode 100644 (file)
index 0000000..78bf5d1
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+function multilang_nommer_langues($langues=array()){
+       if(!is_array($langues) || count($langues) <= 1){
+               return false;
+       }
+       sort($langues);
+       foreach ($langues as $l => $langue) {
+               $langues[$langue] = traduire_nom_langue($langue);
+               unset($langues[$l]);
+       }
+       return $langues;
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/multilang/images/background.png b/www/plugins/multilang/images/background.png
new file mode 100644 (file)
index 0000000..70bb7dc
Binary files /dev/null and b/www/plugins/multilang/images/background.png differ
diff --git a/www/plugins/multilang/images/multi_forbidden.png b/www/plugins/multilang/images/multi_forbidden.png
new file mode 100644 (file)
index 0000000..fa5cabd
Binary files /dev/null and b/www/plugins/multilang/images/multi_forbidden.png differ
diff --git a/www/plugins/multilang/images/multi_undefined.png b/www/plugins/multilang/images/multi_undefined.png
new file mode 100644 (file)
index 0000000..1dabe73
Binary files /dev/null and b/www/plugins/multilang/images/multi_undefined.png differ
diff --git a/www/plugins/multilang/images/multilang-16.png b/www/plugins/multilang/images/multilang-16.png
new file mode 100644 (file)
index 0000000..78abc66
Binary files /dev/null and b/www/plugins/multilang/images/multilang-16.png differ
diff --git a/www/plugins/multilang/images/multilang-24.png b/www/plugins/multilang/images/multilang-24.png
new file mode 100644 (file)
index 0000000..11e6ed4
Binary files /dev/null and b/www/plugins/multilang/images/multilang-24.png differ
diff --git a/www/plugins/multilang/images/multilang-32.png b/www/plugins/multilang/images/multilang-32.png
new file mode 100644 (file)
index 0000000..d7b88d0
Binary files /dev/null and b/www/plugins/multilang/images/multilang-32.png differ
diff --git a/www/plugins/multilang/images/multilang-48.png b/www/plugins/multilang/images/multilang-48.png
new file mode 100644 (file)
index 0000000..fc2db8e
Binary files /dev/null and b/www/plugins/multilang/images/multilang-48.png differ
diff --git a/www/plugins/multilang/javascript/multilang.js b/www/plugins/multilang/javascript/multilang.js
new file mode 100644 (file)
index 0000000..72f0fb7
--- /dev/null
@@ -0,0 +1,646 @@
+/**\r
+ * multilang\r
+ *\r
+ * Copyright (c) 2006-2010 Renato Formato (rformato@gmail.com)\r
+ * Licensed under the GPL License:\r
+ *   http://www.gnu.org/licenses/gpl.html\r
+ *\r
+ * Modif Yffic mars 2010\r
+ * - Correction bug : Fonctionnement incoherent si plusieurs menu dans la meme page (ex : portfolio dans page de\r
+ *   presentation d'un article)\r
+ * - On ne rajoute pas le menu s'il existe deja (cas d'un retour Ajax)\r
+ * - On ne rajoute pas le menu dans forms d'upload (par ex vignette d'un doc)\r
+ */\r
+\r
+\r
+var multilang_containers={}, //menu containers\r
+    multilang_forms_fields={};\r
+\r
+/*\r
+(?:\[([a-z_]+)\]|^[\s\n]*)\r
+[lang] or white space\r
+\r
+((?:.|\n)*?)\r
+all chars not greedy\r
+\r
+(?=\[[a-z_]+\]|$)\r
+[lang] or end string\r
+*/\r
+\r
+/**\r
+ * Initialisation de différentes variables :\r
+ *\r
+ */\r
+var multilang_match_multi = /(?:\[([a-z_]+)\]|^[\s\n]*)((?:.|\n|\s)*?)(?=\[[a-z_]+\]|$)/ig;\r
+var multilang_jq_root, //root of the search (jQuery object)\r
+    multilang_root_opt,\r
+    multilang_fields_selector,\r
+    multilang_fields_selector_opt,\r
+    multilang_menu_selector,\r
+    multilang_containers,\r
+    multilang_forms_toadd,\r
+    multilang_forms, //forms to be processed (jQuery object)\r
+    multilang_menu_lang, //template of the menu (jQuery object)\r
+    multilang_forms_selector, //selector of the forms to be processed (string)\r
+    multilang_init = false;\r
+\r
+/**\r
+ * options is a hash having the following values:\r
+ * - fields (mandatory): a jQuery selector to set the fields that have to be internationalized.\r
+ * - page (optional): a string to be searched in the current url. if found the plugin is applied.\r
+ * - root (optional): the root element of all processing. Default value is 'document'. To speed up search\r
+ * - forms (optional): a jQuery selector to set the forms that have to be internationalized. Default value is 'form'.\r
+ * - main_menu (optional): a jQuery selector to set the container for the main menu to control all the selected forms.\r
+ * - form_menu (optional): a jQuery selector to set the container for the form menus.\r
+ */\r
+function multilang_init_lang(options) {\r
+       var init_done = options.init_done || multilang_init;\r
+       //Detect if we're on the right page and if multilinguism is activated. If not return.\r
+       if((options.page && window.location.search.indexOf(options.page)==-1) || multilang_avail_langs.length<=1) return;\r
+       \r
+       //set the root element of all processing\r
+\r
+       var root = options.root || document;\r
+       multilang_jq_root = $(root).add($(options.root_opt).parent());\r
+       multilang_root_opt = options.root_opt;\r
+\r
+       /**\r
+        * set the main menu element\r
+        * Plus utilisé pour l'instant\r
+        */\r
+       multilang_containers = options.main_menu ? $(options.main_menu,multilang_jq_root) : $([]);\r
+\r
+       multilang_forms_toadd = $([]);\r
+\r
+       /**\r
+        * On crée le modèle du menu de langue\r
+        * C'est ce modèle qui est cloné au début de chaque formulaire\r
+        */\r
+       multilang_menu_lang = $("<div class='langues'></div>");\r
+       $.each(multilang_avail_langs,function() {\r
+               var title = 'multilang_lang.title_lien_multi_'+this;\r
+               multilang_menu_lang.append($("<a class='change_lang "+this+"' title='"+eval(title)+"'></a>").html("["+this+"]"));\r
+       });\r
+       multilang_menu_lang.append($("<a class='recover_lang' href='#'></a>").html("["+multilang_lang.lien_desactiver+"]"));\r
+\r
+       //init fields\r
+       multilang_fields_selector = options.fields;\r
+       multilang_fields_selector_opt = options.fields_opt;\r
+\r
+       //store all the internationalized forms\r
+       multilang_forms_selector = options.forms || "form";\r
+\r
+       if(init_done){\r
+               multilang_forms_toadd = $(multilang_forms_selector,multilang_jq_root).not($(multilang_forms));\r
+       }\r
+       multilang_forms = $(multilang_forms_selector,multilang_jq_root);\r
+       if(!init_done)\r
+               multilang_forms_toadd = multilang_forms;\r
+\r
+       //create menu lang for the global form\r
+       if(multilang_containers.size())\r
+               multilang_make_menu_lang(multilang_containers);\r
+       multilang_menu_selector = options.form_menu;\r
+\r
+       multilang_init = true;\r
+\r
+       // Modif Yffic : On va pas plus loin s'il n'y a pas de form\r
+       if(multilang_forms_toadd.size()) multilang_init_multi();\r
+\r
+}\r
+\r
+/**\r
+ * Initialisation des champs multi sur les formulaires\r
+ *\r
+ * @param options\r
+ * @return\r
+ */\r
+function multilang_init_multi(options) {\r
+       var target = options ? options.target : null;\r
+       var init_forms;\r
+       //Update the list of form if this is an update\r
+       if(target) {\r
+               //Verify the target is really a form to be internationalized (in case of an ajax request fired by onAjaxLoad)\r
+               if(target==document) return;\r
+               init_forms = $(target).find('form').in_set($(multilang_forms_selector,multilang_jq_root));\r
+               if(!init_forms.length) return;\r
+               multilang_forms.add(init_forms.each(multilang_attach_submit).get());\r
+       } else {\r
+               //attach multi processing to submit event\r
+               init_forms = multilang_forms_toadd;\r
+               multilang_forms_toadd.each(multilang_attach_submit);\r
+       }\r
+\r
+       multilang_forms_fields = {};\r
+       multilang_forms_fields["undefined"] = $(multilang_fields_selector,multilang_forms);\r
+       //init the value of the field to current lang\r
+       //add a container for the language menu inside the form\r
+       init_forms.each(function() {\r
+               /*\r
+                * Je ne sais pas à quoi cela sert particulièrement, désactivé pour l'instant\r
+                */\r
+               //$(this).find('input[type=submit],button').click(function(){\r
+                       //multilang_multi_submit.apply($(this).parents('form').get(0));\r
+                       //$(this).parents('form').submit();\r
+                       //return false;\r
+               //});\r
+               this.isfull = false;\r
+               this.form_lang = multilang_def_lang;\r
+               var container = multilang_menu_selector ? $(multilang_menu_selector,this) : $(this);\r
+               // Pas de rajout s'il y en deja un\r
+               if(!container.find('.menu_multilang').size())\r
+                       container.prepend("<div class='menu_multilang'></div>");\r
+       });\r
+\r
+       /**\r
+        * Initialisation de chaque input ou textarea\r
+        * On vérifie si on est dans un formulaire optionnel (dans ce cas on ne prend que\r
+        * les éléments qui on la class optionnelle) sinon on prend tous les champs qui\r
+        * matchent\r
+        */\r
+       $(multilang_fields_selector,init_forms).each(function(){\r
+           var me = $(this);\r
+           if(me.closest(multilang_root_opt).length){\r
+               if(me.is(multilang_fields_selector_opt))\r
+                       multilang_init_field(this,this.form.form_lang);\r
+           }else{\r
+                       multilang_init_field(this,this.form.form_lang);\r
+               }\r
+       });\r
+       //create menu for each form. The menu is just before the form\r
+       $("div.menu_multilang",init_forms).empty().each(function() {\r
+               //store all form containers to allow menu lang update on each container\r
+               //when it is triggered by global menu\r
+               multilang_containers.add(this);\r
+               multilang_make_menu_lang($(this),$(this).parents("form"));\r
+       });\r
+}\r
+\r
+/**\r
+ * Création du menu de langue\r
+ * Liste les langues disponibles et ajoute un lien pour désactiver multilang\r
+ *\r
+ * @param container\r
+ * @param target\r
+ * @return\r
+ */\r
+function multilang_make_menu_lang(container,target) {\r
+       target = target || multilang_forms;\r
+       $(multilang_menu_lang).clone().find("a").click(function() {\r
+               if($(this).is('.change_lang') && !$(this).is('.on')){\r
+                       $(this).parents('form > .menu_multilang').find('a.on').removeClass('on');\r
+                       $(this).parents('form > .menu_multilang').find('.multilang_message').detach();\r
+                       $(this).parents('form').find('li.editer_titre_numero,div.editer_titre_numero').show();\r
+                       $(this).addClass('on');\r
+                       multilang_change_lang(this,container,target);\r
+               }else if(!$(this).is('.on') && $(this).is('.recover_lang')){\r
+                       $(this).parents('form > .menu_multilang').find('a.on').removeClass('on');\r
+                       $(this).parents('form > .menu_multilang').append('<div class="multilang_message"><p>'+multilang_lang.champs_readonly+'<\/p><\/div>');\r
+                       $(this).parents('form').find('li.editer_titre_numero,div.editer_titre_numero').hide();\r
+                       $(this).addClass('on');\r
+                       multilang_multi_recover(this,container,target,'submit');\r
+               }\r
+               return false;\r
+       }).end().appendTo(container);\r
+       $(target).find('.menu_multilang .langues a').eq(0).addClass('on');\r
+\r
+       var target_id = multilang_init_target_id(target);\r
+       multilang_forms_fields[target_id].each(function(){\r
+               multilang_save_lang(this,this.form.form_lang);\r
+       });\r
+       // Maj du menu de langues\r
+       multilang_mark_empty_langs(container,target);\r
+}\r
+\r
+/**\r
+ * Initialise target_id\r
+ *\r
+ * @param target Le formulaire\r
+ * @return\r
+ */\r
+function multilang_init_target_id(target){\r
+       var target_id = target != multilang_forms ? jQuery.data(target[0]) : "undefined";\r
+       multilang_forms_fields[target_id] = $(multilang_fields_selector,target);\r
+       return(target_id);\r
+}\r
+\r
+/**\r
+ * Affiche le contenu complet du champ\r
+ * Utilisé lors de la désactivation de multilang et de la validation des formulaires\r
+ *\r
+ * @param el Le lien de désactivation\r
+ * @param container Le container du formulaire\r
+ * @param target Le formulaire\r
+ * @return\r
+ */\r
+function multilang_multi_recover(el,container,target,event){\r
+       if(target[0].isfull){\r
+               return true;\r
+       }\r
+       if(event == 'submit'){\r
+               lang = 'full';\r
+               var target_id = multilang_init_target_id(target);\r
+               target[0].isfull = true;\r
+               multilang_forms_fields[target_id].each(function(){\r
+                       if(!this.totreat) return ;\r
+                       //save data before submit\r
+                       multilang_save_lang(this,this.form.form_lang);\r
+                       //build the string value\r
+                       multilang_field_set_background(this,lang);\r
+                       if(container && target){\r
+                               multilang_mark_empty_langs(container,target);\r
+                       }\r
+                       var def_value = this.field_lang[multilang_def_lang];\r
+                       if(!this.multi)\r
+                               this.value = (def_value==undefined?"":def_value);\r
+                       else {\r
+                               var value="",count=0;\r
+                               $.each(this.field_lang,function(name){\r
+                                       if((name != 'full') && (this.length > 0)){\r
+                                               //save default lang value and other lang values if different from the default one\r
+                                               if(name == multilang_def_lang){\r
+                                                       value = "["+name+"]"+this+value;\r
+                                                       count++;\r
+                                               }else if(this!=def_value) {\r
+                                                       value += "["+name+"]"+this;\r
+                                                       count++;\r
+                                               }\r
+                                       }\r
+                               });\r
+                               this.value = (count > 1 ? "<multi>"+value+"</multi>":value.replace(/^\[[a-z_]+\]/,''));\r
+                       }\r
+                       // Add the title number to the final value\r
+                       if(multilang_is_title(this) && ($('#'+this.id+'_numero').val() != ''))\r
+                               this.value= $('#'+this.id+'_numero').val().replace(/\.|\s+/,'') + ". " + this.value;\r
+               });\r
+               return true;\r
+       }\r
+}\r
+\r
+/**\r
+ * Défini si un id de champ correspond a un champ "numerotable"\r
+ *\r
+ * @param id chaine correspondant a l'id du champ\r
+ */\r
+function multilang_is_title(el) {\r
+       return (el.id=='titre' || el.id=='champ_titre' || (el.id=='nom_site' && ($(el).parents('#configurer-accueil,.formulaire_configurer_identite,.formulaire_editer_auteur').size() < 1)) || el.id.match(/^titre_document[0-9]+/)!=null || el.name.match(/^content_[a-z0-9_]+_titre/)!=null || el.name.match(/^content_[a-z0-9_-]+nom_/)!=null)\r
+}\r
+\r
+/**\r
+ * Initialisation du script sur un champ\r
+ *\r
+ * Récupère les données suivantes\r
+ * - Le contenu de l'élément du champ\r
+ * - Le booléen (true/false) multi (est ce un champs déjà multi)\r
+ * - Les différentes chaines de langue dans un objet :\r
+ * {fr="texte fr",en="texte en",full="<multi>[fr]texte fr[en]texte en</multi>"}\r
+ * Si le champ est déjà initialisé, fait un simple return\r
+ *\r
+ * @param el Le champ a initialiser\r
+ * @param lang La langue\r
+ *\r
+ */\r
+function multilang_init_field(el,lang,force) {\r
+       if(el.field_lang && !force) return;\r
+       var langs;\r
+       \r
+       // On enlève les espaces, retours à la ligne et tabulations de début et de fin de chaine\r
+       el.value.replace(/(?:^\s+|\s+$)/g, "");\r
+       \r
+       // Modif Yffic : ne pas considerer comme multi les champs qui contiennent du texte\r
+       // en dehors des multi sauf un numero (\d+\.\s+)\r
+       var m = el.value.match(/(\d+\.\s+)?<multi>((?:.|\n|\s)*?)<\/multi>(.|\n*)/);\r
+       el.field_lang = {};\r
+       el.field_pre_lang = ""; //this is the 01. part of the string, the will be put outside the <multi>\r
+       el.titre_el = $("#titre_"+el.id);\r
+       \r
+       // Init the elements to treat\r
+       if(m!=null) {\r
+               if( m.index || (m[3]!=undefined && m[3]!="")){\r
+                       $(el).addClass('multi_lang_broken');\r
+                       el.totreat=false;\r
+               }\r
+               else\r
+                       el.totreat=true;\r
+               if(el.totreat) {\r
+                       el.field_pre_lang = m[1] || "";\r
+                       // Suppress point and spaces\r
+                       el.field_pre_lang = el.field_pre_lang.replace(/\.|\s+/,'') ;\r
+                       el.multi = true;\r
+                       multilang_match_multi.lastIndex=0;\r
+                       el.field_lang['full'] = el.value;\r
+                       while((langs=multilang_match_multi.exec(m[2]))!=null) {\r
+                               var text = langs[2].match(/^(\d+\.\s+)((?:.|\n|\s)*)/), value;\r
+                               // Suppression du numero uniquement pour les titres\r
+                               if(multilang_is_title(el) && text!=null) {\r
+                                       value = text[2];\r
+                                       // Suppress point and spaces\r
+                                       el.field_pre_lang = text[1].replace(/\.|\s+/,'') || "";\r
+                               } else {\r
+                                       value = langs[2];\r
+                               }\r
+                               el.field_lang[langs[1]||multilang_def_lang] = value;\r
+                       }\r
+               }\r
+       } else {\r
+               el.multi = false;\r
+               el.totreat=true;\r
+\r
+               // Suppression du numero uniquement pour les titres\r
+               if(multilang_is_title(el)) {\r
+                       var n = el.value.match(/(\d+\.\s+)?(.*)/);\r
+                       el.field_pre_lang = n[1] || "";\r
+                       el.field_pre_lang = el.field_pre_lang.replace(/\.|\s+/,'') ;\r
+                       el.field_lang[multilang_def_lang] = n[2];\r
+               } else\r
+                       el.field_lang[multilang_def_lang] = el.value;\r
+       }\r
+\r
+       // Put the current lang string only in the field\r
+       multilang_set_lang(el,lang);\r
+\r
+       /**\r
+        * Si le champ est un titre, on ajoute un champ facultatif "numéro" au formulaire permettant\r
+        * de traiter le cas où l'on utilise les numéros pour trier les objets\r
+        * Ajout d'Yffic le 30/03/2010\r
+        */\r
+       if(!force && multilang_is_title(el)){\r
+               numid=el.id+'_numero';\r
+               /**\r
+                * Cas des crayons qui n'ont pas toujours de formalisme en ul > li\r
+                */\r
+               if(el.name.match(/^content_[a-z0-9_]+_titre/)){\r
+                       if($(el).parent().is('li'))\r
+                               $(el).parent()\r
+                                       .before('<li class="editer_'+numid+'"><label for="titre_numero">'+multilang_lang.numero+'</label><input id="'+numid+'" name="titre_numero" type="text" value="'+el.field_pre_lang+'" size="4" class="text nomulti" /></li>');\r
+                       else\r
+                               $(el)\r
+                                       .before('<div class="editer_titre_numero"><label for="titre_numero">'+multilang_lang.numero+'</label><input id="'+numid+'" name="titre_numero" type="text" value="'+el.field_pre_lang+'" size="4" class="text nomulti" /><br /><br /></div>');\r
+               }else\r
+                       $(el).parent()\r
+                               .before('<li class="editer_'+numid+'"><label for="titre_numero">'+multilang_lang.numero+'</label><input id="'+numid+'" name="titre_numero" type="text" value="'+el.field_pre_lang+'" size="4" class="text nomulti" /></li>');\r
+               $('#'+numid).totreat = false;\r
+       }\r
+}\r
+\r
+/**\r
+ * Action au click sur une langue du menu de langue\r
+ *\r
+ * @param el Le lien cliqué sur le menu\r
+ * @param container Le conteneur du formulaire\r
+ * @param target Le formulaire lui même\r
+ *\r
+ */\r
+function multilang_change_lang(el,container,target) {\r
+       var added_lang="";\r
+       var target_id = multilang_init_target_id(target);\r
+       var lang = el.innerHTML;\r
+\r
+       lang = lang.slice(1,-1);\r
+\r
+       if(target[0].isfull){\r
+               // Maj du menu de langues avant multilang_init_field\r
+               multilang_forms_fields[target_id].each(function(){\r
+                       var me = $(this);\r
+                       if(me.parents(multilang_root_opt).size()>0){\r
+                       if(me.is(multilang_fields_selector_opt))\r
+                               multilang_init_field(this,lang,true);\r
+                   }else\r
+                       multilang_init_field(this,lang,true);\r
+               });\r
+               target[0].isfull = false;\r
+       }else{\r
+               //store the fields inputs for later use (usefull for select)\r
+               //save the current values\r
+               multilang_forms_fields[target_id].each(function(){\r
+                       multilang_save_lang(this,this.form.form_lang);\r
+               });\r
+               // Maj du menu de langues apres multilang_save_lang\r
+       }\r
+\r
+       //change current lang\r
+       target.each(function(){this.form_lang = lang});\r
+\r
+       //reinit fields to current lang\r
+       multilang_forms_fields[target_id].each(function(){\r
+               multilang_set_lang(this,lang);\r
+       });\r
+       \r
+       multilang_mark_empty_langs(container,target);\r
+}\r
+\r
+/**\r
+ * Marquer dans le menu des langues, celles pour lesquelles\r
+ * au moins un champ multi du formulaire n'est pas renseigne\r
+ *\r
+ * @param container Le conteneur du formulaire\r
+ *\r
+ */\r
+function multilang_mark_empty_langs(container,target) {\r
+       var langs_empty = [];\r
+       var target_id = multilang_init_target_id(target);\r
+\r
+       multilang_forms_fields[target_id].each(function(){\r
+               var field_langs = [];\r
+               // Mise sous forme de tableau\r
+               if(typeof(this.field_lang) != 'undefined'){\r
+                       $.each(this.field_lang,function(name,value){\r
+                               if(value)\r
+                                       field_langs.push(name);\r
+                       });\r
+               }\r
+               // Trouver les elements non communs entre le tableau des langues availables et pour chaque champ,\r
+               // celui des langues renseignees, si ce champ est multi\r
+               // Si la langue d'origine n'est pas remplie (champ texte par exemple, on ne considère donc pas empty)\r
+               if(this.multi) {\r
+                       // Comparaison des tableaux\r
+                       $.each(multilang_avail_langs,function(i,name){\r
+                               if ((jQuery.inArray(name, field_langs) == -1) && (jQuery.inArray(name, langs_empty) == -1) && (jQuery.inArray(multilang_def_lang, field_langs) != -1))\r
+                                       langs_empty.push(name);\r
+                       });\r
+               }else{\r
+                       // Comparaison des tableaux\r
+                       $.each(multilang_avail_langs,function(i,name){\r
+                               if ((jQuery.inArray(name, field_langs) == -1) && (jQuery.inArray(name, langs_empty) == -1) && (jQuery.inArray(multilang_def_lang, field_langs) != -1))\r
+                                       langs_empty.push(name);\r
+                       });\r
+               }\r
+       });\r
+\r
+       // On indique dans le menu de langue, celles qui ont au moins un champ non renseigne\r
+       if(container!='') {\r
+               $.each(multilang_avail_langs,function(i,name){\r
+                       if((jQuery.inArray(name, langs_empty) == -1)){\r
+                               var title = 'multilang_lang.title_lien_multi_'+name;\r
+                               container.find('a[class~='+name+']').removeClass('empty').attr('title',eval(title));\r
+                       }else{\r
+                               var title = 'multilang_lang.title_lien_multi_sans_'+name;\r
+                               container.find('a[class~='+name+']').addClass('empty').attr('title',eval(title));\r
+                       }\r
+               });\r
+       }\r
+}\r
+\r
+/**\r
+ * Action au changement de la langue\r
+ * Lorsque l'on clique sur une le menu de langue\r
+ * On affiche pour le champ "el" son contenu dans la langue "lang"\r
+ *\r
+ * @param el Un champ du formulaire (input ou textarea)\r
+ * @param lang La langue correspondante souhaitée\r
+ * @return\r
+ */\r
+function multilang_set_lang(el,lang) {\r
+\r
+       if(!el.totreat) return;\r
+\r
+       //if current lang is not setted use default lang value\r
+       if(el.field_lang[lang]==undefined) {\r
+               el.field_lang[lang] = el.field_lang[multilang_def_lang];\r
+       }\r
+\r
+       el.value = (el.field_lang[lang] == undefined ? "" : el.field_lang[lang]);\r
+\r
+       el.titre_el.html(el.value);\r
+\r
+       multilang_field_set_background(el,lang);\r
+}\r
+\r
+/**\r
+ * Change la class multi_lang_* d'un champ pour indiquer la présence ou non de multis\r
+ * - multi_lang_(lang) si une langue particulière est disponible\r
+ * - multi_lang_no_multi si pas de multis pour le champ\r
+ *\r
+ * @param el\r
+ * @param lang\r
+ * @return\r
+ */\r
+function multilang_field_set_background(el,lang) {\r
+       if(lang != 'full'){\r
+               if(el.totreat){\r
+                       $(el).removeAttr('readonly').removeClass('multilang_readonly');\r
+                       if(typeof($(el).attr('class')) != 'undefined'){\r
+                               $($(el).attr('class').split(' ')).each(function(){\r
+                                       var m = this.match(/^multi_lang_*/);\r
+                                       if(m!=null)\r
+                                               $(el).removeClass(m.input).addClass('multi_lang_'+lang);\r
+                               });\r
+                       }\r
+                       $(el).addClass('multi_lang_'+(el.multi?lang:'no_multi'));\r
+               }\r
+               else{\r
+                       if(typeof($(el).attr('class')) != 'undefined'){\r
+                               $($(el).attr('class').split(' ')).each(function(){\r
+                                       var m = this.match(/^multi_lang_*/);\r
+                                       if(m!=null)\r
+                                               $(el).removeClass(m.input);\r
+                               });\r
+                       }\r
+                       $(el).css({"background":"url("+multilang_dir_plugin+"/images/multi_forbidden.png) no-repeat right top"});\r
+               }\r
+       }else{\r
+               $(el).attr('readonly','readonly').addClass('multilang_readonly');\r
+               if(typeof($(el).attr('class')) != 'undefined'){\r
+                       $($(el).attr('class').split(' ')).each(function(){\r
+                               var m = this.match(/^multi_lang_*/);\r
+                               if(m!=null)\r
+                                       $(el).removeClass(m.input);\r
+                       });\r
+               }\r
+       }\r
+}\r
+\r
+/**\r
+ * Garde en mémoire dans l'array de langues du champs la valeur de la langue\r
+ * sélectionnée\r
+ *\r
+ * @param el Le champ du formulaire concerné\r
+ * @param lang La langue actuelle\r
+ * @return\r
+ */\r
+function multilang_save_lang(el,lang) {\r
+\r
+       if(!el.totreat) return ;\r
+\r
+       // Suppression du numero uniquement pour les titres\r
+       if(multilang_is_title(el)) {\r
+               var m = el.value.match(/^(\d+\.\s+)((?:.|\n|\s)*)/);\r
+               if(m!=null) {\r
+                       // Suppress point and spaces\r
+                       el.field_pre_lang = m[1].replace(/\.|\s+/,'');\r
+                       el.value = m[2];\r
+               }\r
+       }\r
+\r
+       //if the lang value is equal to the def lang do nothing\r
+       //else save value but if the field is not empty, delete lang value\r
+       if(el.field_lang[multilang_def_lang]!= el.value) {\r
+               if(!el.value) {\r
+                       delete el.field_lang[lang];\r
+                       return;\r
+               }\r
+               el.multi = true;\r
+               el.field_lang[lang] = el.value;\r
+       }else{\r
+               el.field_lang[lang] = el.field_lang[multilang_def_lang];\r
+               $.each(el.field_lang,function(index, value){\r
+                       if((index != multilang_def_lang) && (value == el.field_lang[multilang_def_lang])){\r
+                               delete el.field_lang[index];\r
+                       }\r
+               });\r
+       }\r
+}\r
+\r
+//This func receives the form that is going to be submitted\r
+function multilang_multi_submit(params) {\r
+       if(multilang_avail_langs.length<=1) return;\r
+       var form = $(this);\r
+       //remove the current form from the list of forms\r
+       multilang_forms.not(this);\r
+       //remove the current menu lang container from the list\r
+       multilang_containers.not("div.menu_multilang",$(this));\r
+       //build the input values\r
+       multilang_multi_recover('','',form,'submit');\r
+       //save back the params\r
+       if(params) $.extend(params,$(form).formToArray(false));\r
+}\r
+\r
+/**\r
+ * On attache nos évènements pour la validation du formulaire\r
+ * - sur le submit pour tous les formulaires\r
+ * - sur l'évènement 'form-pre-serialize' d'ajaxForms au cas où nous sommes dans\r
+ * un formulaire ajax\r
+ *\r
+ * @return\r
+ */\r
+function multilang_attach_submit() {\r
+       if($(this).parents('.ajax').size() && $(this).find('input[name=var_ajax]')){\r
+               $(this).bind('form-pre-serialize',multilang_multi_submit);\r
+       }else if($(this).is('.formulaire_crayon')){\r
+               cQuery(this).bind('form-pre-serialize',function(){multilang_multi_submit.apply(this);});\r
+       }else{\r
+               var oldsubmit = this.onsubmit;\r
+               this.onsubmit = "";\r
+               if(oldsubmit && oldsubmit != ""){\r
+                       $(this).submit(function(){multilang_multi_submit.apply(this);return oldsubmit.apply(this);});\r
+               }\r
+               else if(oldsubmit != "")\r
+                       $(this).submit(multilang_multi_submit);\r
+       }\r
+}\r
+\r
+(function($) {\r
+       $.extend($.fn, {\r
+               in_set: function(set) {\r
+                       var elements = this.get();\r
+                       var result = $.grep(set,function(i){\r
+                               var found = false;\r
+                               $.each(elements,function(){\r
+                                       if(this==i) found=true;\r
+                               })\r
+                               return found;\r
+                       });\r
+                       return jQuery(result);\r
+               }\r
+       });\r
+})(jQuery);
\ No newline at end of file
diff --git a/www/plugins/multilang/javascript/multilang_init.js.html b/www/plugins/multilang/javascript/multilang_init.js.html
new file mode 100644 (file)
index 0000000..cea63c8
--- /dev/null
@@ -0,0 +1,3 @@
+#CACHE{7*24*3600}
+#HTTP_HEADER{Content-Type: text/javascript; charset=#CHARSET}
+[(#REM|generer_multilang_init)]
\ No newline at end of file
diff --git a/www/plugins/multilang/javascript/multilang_init.js_fonctions.php b/www/plugins/multilang/javascript/multilang_init.js_fonctions.php
new file mode 100644 (file)
index 0000000..00e7d84
--- /dev/null
@@ -0,0 +1,92 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function generer_multilang_init(){
+       $data = '';
+       if(count($langues = explode(',',$GLOBALS["meta"]["langues_multilingue"])) > 1){
+               include_spip('inc/config');
+               $config = lire_config('multilang',array());
+               $root = '' ;
+               if(isset($config['multilang_public']))
+                       unset($config['multilang_public']);
+               if(isset($config['multilang_crayons']))
+                       unset($config['multilang_crayons']);
+               if(isset($config['siteconfig']) && $config['siteconfig']){
+                       $root .= 'div#configurer-accueil,div.formulaire_configurer_identite' ; // Config Site
+                       unset($config['siteconfig']);
+               }
+               
+               foreach($config as $conf => $val){
+                       if($val == 'on') {
+                               if($conf == 'document')
+                                       $root .= ',div#portfolio_portfolio,div#portfolio_documents,div#liste_documents,div.formulaire_editer_document' ;
+                               else
+                                       $root .= ',div.formulaire_editer_'.$conf;
+                               unset($config[$conf]);
+                       }
+               }
+               // Appel de multilang_init_lang si
+               // - document.ready
+               // - onAjaxLoad (cas des docs et de la configuration du site)
+               if(is_array($langues_config = lire_config('multilang/langues_utilisees','aucune')) && count($langues_config) > 0){
+                       $langues = implode(',',array_intersect($langues,$langues_config));
+               }else{
+                       $langues = implode(',',$langues);
+               }
+               $data = '
+       var multilang_avail_langs = "'.$langues.'".split(\',\'),
+       multilang_def_lang = "'.$GLOBALS["meta"]["langue_site"].'",
+       multilang_lang_courante = "'.$GLOBALS["spip_lang"].'",
+       multilang_dir_plugin = "'._DIR_PLUGIN_MULTILANG.'";
+
+       // On trie les langues. Langue de l environnement en premier,
+       // puis langue principale du site puis les autres en ordre alphabetique
+       // Un utilisateur de langue anglaise souhaite logiquement traduire en anglais
+       multilang_avail_langs = jQuery.grep(multilang_avail_langs, function(value) {
+               return (value != multilang_def_lang && value != multilang_lang_courante);
+       });
+       multilang_avail_langs.sort();
+       multilang_avail_langs.unshift(multilang_lang_courante);
+       if(multilang_lang_courante!=multilang_def_lang) multilang_avail_langs.unshift(multilang_def_lang);
+
+       jQuery(document).ready(function(){
+               function multilang_init(){
+                       var root = "'.$root.'";
+                       var fields_selector = "textarea:not(textarea#adresses_secondaires,textarea#repetitions),input:text:not(input#new_login,input#email,#titreparent,input.date,input.heure,input#largeur,input#hauteur,.ac_input,#url_syndic,#url_auto,#champ_geocoder,#champ_lat,#champ_lon,#champ_zoom,#places,*.nomulti),.multilang";
+                       // on exclue aussi les form d upload (Pour les vignettes de docs, logos...)
+                       var forms_selector = "form[class!=\'form_upload\'][class!=\'form_upload_icon\']";
+                       // Les div qui ont un formulaire de classe multilang (pour accélérer la recherche dans le DOM,
+                       // on passe le form et le parent sera trouvé dans lors de l\'init)
+                       var root_opt = "form:has(.multilang)";
+                       var fields_selector_opt = ".multilang";
+                       multilang_init_lang({fields:fields_selector,fields_opt:fields_selector_opt,root:root,root_opt:root_opt,forms:forms_selector});
+                       
+                       if($(".menu_multilang").length > 0){
+                               $(".menu_multilang").each(function(){
+                                       var menu_lang = $(this);
+                                       $(window).scroll(function() {
+                                               var offset = menu_lang.parents("form").offset();
+                                               var limite_multilang = offset.top;
+                                               var limite_bas = limite_multilang+menu_lang.parents("form").height()-menu_lang.parents("form").find(".boutons").height();
+                                               var pos_bas = menu_lang.offset().top+menu_lang.height();
+                                               if(($(window).scrollTop() >= limite_multilang) && (pos_bas <= limite_bas) && ($(window).scrollTop() < limite_bas)){
+                                                       if(!menu_lang.hasClass("menu_lang_flottant"))
+                                                               menu_lang.addClass("menu_lang_flottant");
+                                                       var menu_lang_width = menu_lang.width();
+                                                       menu_lang.css({"position": "fixed", "top": 0, "width": menu_lang_width+"px","z-index":"999"});
+                                               }
+                                               if(($(window).scrollTop() < limite_multilang)||(pos_bas > limite_bas) )
+                                                       menu_lang.removeClass("menu_lang_flottant").css({"position": "static", "width": "auto"});
+                                       });
+                               });
+                       }
+               }
+               multilang_init();
+               if(typeof onAjaxLoad == "function") onAjaxLoad(multilang_init);
+       });
+';
+       }
+       return $data;
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/multilang/javascript/multilang_lang.js.html b/www/plugins/multilang/javascript/multilang_lang.js.html
new file mode 100644 (file)
index 0000000..35dc5de
--- /dev/null
@@ -0,0 +1,12 @@
+#CACHE{7*24*3600}
+#HTTP_HEADER{Content-Type: text/javascript; charset=#CHARSET}
+#SET{langues,#EVAL{$GLOBALS["meta"]["langues_multilingue"]}}
+var multilang_lang = {
+       champs_readonly : '<:multilang:message_champs_readonly|filtrer_entites|texte_script:>',
+       lien_desactiver : '<:multilang:lien_desactiver|filtrer_entites|texte_script:>',
+       <BOUCLE_langues(DATA){source tableau, #GET{langues}|explode{','}}>[(#SET{lang,[(#VALEUR|traduire_nom_langue)]})][
+       title_lien_multi_(#VALEUR) : '<:multilang:lien_multi_title{lang=#GET{lang}}|filtrer_entites|texte_script:>',][
+       title_lien_multi_sans_(#VALEUR) : '<:multilang:lien_multi_title_sans{lang=#GET{lang}}|filtrer_entites|texte_script:>',
+       ]</BOUCLE_langues>
+       numero : '<:multilang:champ_numero|html2unicode|unicode2charset:>'
+};
diff --git a/www/plugins/multilang/lang/multilang.xml b/www/plugins/multilang/lang/multilang.xml
new file mode 100644 (file)
index 0000000..f54ac3e
--- /dev/null
@@ -0,0 +1,16 @@
+<traduction module="multilang" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/multilang/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/multilang?lang_cible=en">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/multilang?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/multilang?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/multilang?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/multilang/lang/multilang_en.php b/www/plugins/multilang/lang/multilang_en.php
new file mode 100644 (file)
index 0000000..45c174c
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/multilang?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_activer' => 'Activate Multilang on the edit page:',
+       'cfg_boite_multilang' => 'Configuration of the Multilang plugin',
+       'cfg_descr_multilang' => 'Multilang: plugin to manage multi tags',
+       'cfg_effacer' => 'Re-init',
+       'cfg_explication_crayons' => 'Requires multilang to be activated in the public space of the site.',
+       'cfg_langues' => 'Used languages',
+       'cfg_lbl_article' => 'of the articles',
+       'cfg_lbl_auteur' => 'of the authors',
+       'cfg_lbl_breve' => 'of the news items',
+       'cfg_lbl_crayons' => 'Use multilang in the pencils',
+       'cfg_lbl_document' => 'of the documents',
+       'cfg_lbl_espace_public' => 'Use multilang in the public space',
+       'cfg_lbl_evenement' => 'of the events',
+       'cfg_lbl_formstables' => 'of forms&tables',
+       'cfg_lbl_gis' => 'geolocated points',
+       'cfg_lbl_motcle' => 'of the keywords',
+       'cfg_lbl_rubrique' => 'of the sections',
+       'cfg_lbl_site' => 'of the websites',
+       'cfg_lbl_siteconfig' => 'of the website configuration',
+       'cfg_titre_multilang' => 'Multilang',
+       'champ_numero' => 'Number',
+       'configuration_multilang' => 'Multilang',
+
+       // E
+       'explication_langues_utilisees' => 'Select the languages to use in the multilang menu. Select none to use them all.',
+
+       // L
+       'label_langues_utilisees' => 'Used languages by multilang',
+       'lien_desactiver' => 'All',
+       'lien_multi_title' => 'Edit multilingual fields in «@lang@»',
+       'lien_multi_title_sans' => 'Version "@lang@" is incomplete. Click to edit.',
+
+       // M
+       'message_champs_readonly' => 'The multilingual fields are in read only mode, choose a language to edit them'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/multilang_es.php b/www/plugins/multilang/lang/multilang_es.php
new file mode 100644 (file)
index 0000000..016c7d4
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/multilang?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_activer' => 'Activar Multilang en la página de edición:',
+       'cfg_boite_multilang' => 'Configuración del plugin Multilang',
+       'cfg_descr_multilang' => 'Multilang: Plugin de gestión de las etiquetas "multi"',
+       'cfg_effacer' => 'Reiniciar',
+       'cfg_explication_crayons' => 'Se requiere activar Multilang en el espacio público del sitio.',
+       'cfg_langues' => 'Idiomas utilizados',
+       'cfg_lbl_article' => 'artículos',
+       'cfg_lbl_auteur' => 'autores',
+       'cfg_lbl_breve' => 'breves',
+       'cfg_lbl_crayons' => 'Utilizar Multilang en los lápices',
+       'cfg_lbl_document' => 'documentos',
+       'cfg_lbl_espace_public' => 'Utilizar Multilang en el espacio público del sitio',
+       'cfg_lbl_evenement' => 'Eventos',
+       'cfg_lbl_formstables' => 'forms&tables',
+       'cfg_lbl_gis' => 'puntos geolocalizados',
+       'cfg_lbl_motcle' => 'palabaras clave',
+       'cfg_lbl_rubrique' => 'secciones',
+       'cfg_lbl_site' => 'sitios',
+       'cfg_lbl_siteconfig' => 'de la configuración del sitio',
+       'cfg_titre_multilang' => 'Multilang',
+       'champ_numero' => 'Número',
+       'configuration_multilang' => 'Multilang',
+
+       // E
+       'explication_langues_utilisees' => 'Seleccione los idiomas a utilizar para el menú de Multilang. No seleccione ninguna para utilizarlas todas.',
+
+       // L
+       'label_langues_utilisees' => 'Idiomas utilizados por Multilang',
+       'lien_desactiver' => 'Todo',
+       'lien_multi_title' => 'Editar los campos multilingües en «@lang@»',
+       'lien_multi_title_sans' => 'La versión «@lang@» está incompleta. Haga clic para editar.',
+
+       // M
+       'message_champs_readonly' => 'Los campos multilingües son sólo de lectura, elija un idioma para modificarlos'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/multilang_fa.php b/www/plugins/multilang/lang/multilang_fa.php
new file mode 100644 (file)
index 0000000..0ff0f62
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/multilang?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_activer' => 'فعال سازي چندزبانگي در صفحه‌ي ويراستاري',
+       'cfg_boite_multilang' => 'پيكربندي پلاگين چندزبانگي ',
+       'cfg_descr_multilang' => 'چندزبانگي: پلاگين مديريت چند برچسب چندتايي',
+       'cfg_effacer' => 'بازنصب',
+       'cfg_explication_crayons' => 'لزوم فعال سازي چندزبانگي در فضاي همگاني سايت.',
+       'cfg_langues' => 'زبان‌هاي مورد استفاده ',
+       'cfg_lbl_article' => 'مقاله‌ها',
+       'cfg_lbl_auteur' => 'نويسندگان',
+       'cfg_lbl_breve' => 'خبرها',
+       'cfg_lbl_crayons' => 'استفاده از چندزبانگي در مدادها',
+       'cfg_lbl_document' => 'سندها',
+       'cfg_lbl_espace_public' => 'استفاده از چندزبانگي در فضاي همگاني سايت',
+       'cfg_lbl_evenement' => 'برنامه‌ها',
+       'cfg_lbl_formstables' => 'فرم‌ها/جدول‌ها',
+       'cfg_lbl_gis' => 'نقاط محلي‌سازي شده (geolocated) ',
+       'cfg_lbl_motcle' => 'كليدواژه‌ها',
+       'cfg_lbl_rubrique' => 'بخش‌ها',
+       'cfg_lbl_site' => 'سايت‌ها',
+       'cfg_lbl_siteconfig' => 'از پيكربندي سايت',
+       'cfg_titre_multilang' => 'چندزبانگي',
+       'champ_numero' => 'شماره ',
+       'configuration_multilang' => 'چندزبانگي',
+
+       // E
+       'explication_langues_utilisees' => 'زبان‌هاي مورد استفاده براي منيوي چندزبانگي را انتخاب كنيد. براي استفاده‌ از تمام آن‌ها هيچ چيز انتخاب نكنيد.',
+
+       // L
+       'label_langues_utilisees' => 'زبان‌هاي مورد استفاده توسط چندزبانگي ',
+       'lien_desactiver' => 'همه',
+       'lien_multi_title' => 'ويرايش ميدان‌هاي چندزبانگي در زبان «@lang@»  ',
+       'lien_multi_title_sans' => 'نسخه‌ي «@lang@»كامل نيست. براي ويرايش كردن آن كليك كنيد. ',
+
+       // M
+       'message_champs_readonly' => 'ميدان‌هاي چندزبانگي در حالت فقط خواندني هستند، يك زبان را براي ويرايش كردن آن‌ها انتخاب كنيد
+'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/multilang_fr.php b/www/plugins/multilang/lang/multilang_fr.php
new file mode 100644 (file)
index 0000000..02ed7bd
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/multilang/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_activer' => 'Activer Multilang sur la page d\'édition :',
+       'cfg_boite_multilang' => 'Configuration du plugin Multilang',
+       'cfg_descr_multilang' => 'Multilang : Plugin de gestion des tags multi',
+       'cfg_effacer' => 'Re-initialiser',
+       'cfg_explication_crayons' => 'Nécessite que multilang soit activé dans l\'espace public du site.',
+       'cfg_langues' => 'Langues utilisées',
+       'cfg_lbl_article' => 'des articles',
+       'cfg_lbl_auteur' => 'des auteurs',
+       'cfg_lbl_breve' => 'des breves',
+       'cfg_lbl_crayons' => 'Utiliser multilang dans les crayons',
+       'cfg_lbl_document' => 'des documents',
+       'cfg_lbl_espace_public' => 'Utiliser multilang dans l\'espace public du site',
+       'cfg_lbl_evenement' => 'des évènements',
+       'cfg_lbl_formstables' => 'des forms&tables',
+       'cfg_lbl_gis' => 'des points géolocalisés',
+       'cfg_lbl_motcle' => 'des mots clés',
+       'cfg_lbl_rubrique' => 'des rubriques',
+       'cfg_lbl_site' => 'des sites',
+       'cfg_lbl_siteconfig' => 'de la configuration du site',
+       'cfg_titre_multilang' => 'Multilang',
+       'champ_numero' => 'Numéro',
+       'configuration_multilang' => 'Multilang',
+
+       // E
+       'explication_langues_utilisees' => 'Sélectionnez les langues à utiliser pour le menu de multilang. N\'en sélectionnez aucune pour toutes les utiliser.',
+
+       // L
+       'label_langues_utilisees' => 'Langues utilisées par multilang',
+       'lien_desactiver' => 'Tout',
+       'lien_multi_title' => 'Éditer les champs multilingues en «@lang@»',
+       'lien_multi_title_sans' => 'La version «@lang@» est incomplète. Cliquez pour l\'éditer.',
+
+       // M
+       'message_champs_readonly' => 'Les champs multilingues sont en lecture seule, choisissez une langue pour les modifier'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/multilang_sk.php b/www/plugins/multilang/lang/multilang_sk.php
new file mode 100644 (file)
index 0000000..14fa8da
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/multilang?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // C
+       'cfg_activer' => 'Aktivovať Multilang na upravovacej stránke:',
+       'cfg_boite_multilang' => 'Nastavenia zásuvného modulu Multilang',
+       'cfg_descr_multilang' => 'Multilang: zásuvný modul na správu multitagov',
+       'cfg_effacer' => 'Znova spustiť',
+       'cfg_explication_crayons' => 'Treba aktivovať multilang na používanie na verejne prístupnej stránke.',
+       'cfg_langues' => 'Používané jazyky',
+       'cfg_lbl_article' => 'článkov',
+       'cfg_lbl_auteur' => 'autorov',
+       'cfg_lbl_breve' => 'noviniek',
+       'cfg_lbl_crayons' => 'Používať multilang v module crayons',
+       'cfg_lbl_document' => 'súborov',
+       'cfg_lbl_espace_public' => 'Používať multilang na verejne prístupnej stránke',
+       'cfg_lbl_evenement' => 'udalostí',
+       'cfg_lbl_formstables' => 'formulárov a tabuliek',
+       'cfg_lbl_gis' => 'geolokalizovaných bodov',
+       'cfg_lbl_motcle' => 'kľúčových slov',
+       'cfg_lbl_rubrique' => 'rubrík',
+       'cfg_lbl_site' => 'stránok',
+       'cfg_lbl_siteconfig' => 'nastavení stránky',
+       'cfg_titre_multilang' => 'Multilang',
+       'champ_numero' => 'Číslo',
+       'configuration_multilang' => 'Multilang',
+
+       // E
+       'explication_langues_utilisees' => 'Vyberte jazyky, ktoré sa budú používať v menu multilangu. Ak chcete používať všetky, nevyberte žiaden.',
+
+       // L
+       'label_langues_utilisees' => 'Jazyky, ktoré bude multilang používať',
+       'lien_desactiver' => 'Všetky',
+       'lien_multi_title' => 'Upraviť viacjazyčné polia v jazyku "@lang@"',
+       'lien_multi_title_sans' => 'Verzia v jazyku "@lang@" je neúplná. Kliknite, ak ju chcete upraviť.',
+
+       // M
+       'message_champs_readonly' => 'Viacjazyčné polia sú iba na čítanie, ak ich chcete upraviť, vyberte si jazyk'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/paquet-multilang.xml b/www/plugins/multilang/lang/paquet-multilang.xml
new file mode 100644 (file)
index 0000000..a5954f5
--- /dev/null
@@ -0,0 +1,14 @@
+<traduction module="paquet-multilang" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/multilang/trunk/lang/" reference="fr">
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="it" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=ru">
+               <traducteur nom="nazar" lien="http://trad.spip.net/auteur/nazar" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/multilang/lang/paquet-multilang_en.php b/www/plugins/multilang/lang/paquet-multilang_en.php
new file mode 100644 (file)
index 0000000..b0b4075
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'multilang_description' => 'This plugin adds a language menu like <code>[fr] [en] [it]</code> at the top of each form, depending on the language selected in the site configuration.',
+       'multilang_slogan' => 'Control the display of the contents of multi tags with a language menu'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/paquet-multilang_es.php b/www/plugins/multilang/lang/paquet-multilang_es.php
new file mode 100644 (file)
index 0000000..80b8115
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'multilang_description' => 'Este plugin añade un menú de idiomas del tipo <code>[fr] [en] [it]</code> encima de cada formulario, en función de los idiomas activados en la configuración del sitio.',
+       'multilang_slogan' => 'Administrar la muestra del contenido de las etiquetas multi con un menu'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/paquet-multilang_fr.php b/www/plugins/multilang/lang/paquet-multilang_fr.php
new file mode 100644 (file)
index 0000000..7bc8904
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/multilang/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'multilang_description' => 'Ce plugin rajoute un menu de langues du type <code>[fr] [en] [it]</code> au-dessus de chaque formulaire, en fonction des langues activées dans la configuration du site.',
+       'multilang_slogan' => 'Gérer l\'affichage du contenu des tags multi par un menu'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/paquet-multilang_it.php b/www/plugins/multilang/lang/paquet-multilang_it.php
new file mode 100644 (file)
index 0000000..74d8d3d
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'multilang_description' => 'Questo plugin aggiunge un menu di linguaggi di tipo <code>[fr] [it] [it]</code> nella parte superiore di ogni modulo, a seconda della lingua selezionata nella configurazione del sito.',
+       'multilang_slogan' => 'Gérer l\'affichage du contenu des tags multi par un menu' # NEW
+);
+
+?>
diff --git a/www/plugins/multilang/lang/paquet-multilang_ru.php b/www/plugins/multilang/lang/paquet-multilang_ru.php
new file mode 100644 (file)
index 0000000..5fcec10
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'multilang_description' => 'Этот плагин добавляет языковое меню, в виде <code> [RU] [EN] [IT] </code> в верхней части каждой формы, в зависимости от языка, выбранного в настройках сайта.',
+       'multilang_slogan' => 'Управляет отображением содержимого нескольких тегов языкового меню'
+);
+
+?>
diff --git a/www/plugins/multilang/lang/paquet-multilang_sk.php b/www/plugins/multilang/lang/paquet-multilang_sk.php
new file mode 100644 (file)
index 0000000..5b3da3c
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-multilang?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // M
+       'multilang_description' => 'Tento zásuvný modul pridá jazykové menu <code>[fr] [en] [it]</code> do hornej časti každého formulára podľa aktivovaných jazykov v konfigurácii stránky.',
+       'multilang_slogan' => 'Riadiť zobrazenie obsahu kombinovaných tagov podľa menu'
+);
+
+?>
diff --git a/www/plugins/multilang/multilang.css.html b/www/plugins/multilang/multilang.css.html
new file mode 100644 (file)
index 0000000..818a87c
--- /dev/null
@@ -0,0 +1,56 @@
+#CACHE{3600*100,cache-client}\r
+#HTTP_HEADER{Content-Type: text/css; charset=iso-8859-15}\r
+#HTTP_HEADER{Vary: Accept-Encoding}\r
+\r
+.menu_multilang {\r
+       background-color:transparent;\r
+       padding:5px;\r
+}\r
+\r
+.menu_multilang .langues{\r
+       overflow:auto;\r
+}\r
+\r
+.menu_multilang .langues a{\r
+       cursor:pointer;\r
+       font-weight:normal;\r
+       margin-right:2px;\r
+}\r
+\r
+.menu_multilang .langues a.on{\r
+       font-weight:bold;\r
+}\r
+\r
+.menu_multilang .langues a.empty{\r
+       background-color:#000000;\r
+}\r
+\r
+.menu_multilang .multilang_message{\r
+       clear:both;\r
+}\r
+\r
+.menu_lang_flottant{\r
+       border-bottom:3px solid #000;\r
+       background-color:rgb(255,255,255);\r
+       background-color:rgba(255,255,255,.8);\r
+}\r
+\r
+#SET{langues,#EVAL{$GLOBALS["meta"]["langues_multilingue"]}}\r
+<BOUCLE_langues(DATA){source table,#GET{langues}|explode{','}}>\r
+.multi_lang_#VALEUR {\r
+       background-position:98% 1px;\r
+       background-repeat:no-repeat;\r
+       background-image:url([(#VAL{Multi #VALEUR}|image_typo{taille=11,couleur=cccccc}|extraire_attribut{src}|url_absolue)]);\r
+}</BOUCLE_langues>\r
+\r
+.multi_lang_no_multi {\r
+       background-position:98% 1px;\r
+       background-repeat:no-repeat;\r
+       background-image:url([(#VAL{No multi}|image_typo{taille=11,couleur=cccccc}|extraire_attribut{src}|url_absolue)]);\r
+}\r
+\r
+.multi_lang_broken {\r
+       background-position:98% 1px;\r
+       background-repeat:no-repeat;\r
+       background-image:url(#CHEMIN{images/multi_forbidden.png});\r
+}
\ No newline at end of file
diff --git a/www/plugins/multilang/multilang.js.html b/www/plugins/multilang/multilang.js.html
new file mode 100644 (file)
index 0000000..a62d439
--- /dev/null
@@ -0,0 +1,6 @@
+#CACHE{7*24*3600}
+#HTTP_HEADER{Content-Type: text/javascript; charset=#CHARSET}
+[(#INCLURE{fond=javascript/multilang_init.js})]
+[(#INCLURE{fond=javascript/multilang_lang.js,lang})]
+[(#INCLURE{javascript/multilang.js})]
+#FILTRE{trim}
\ No newline at end of file
diff --git a/www/plugins/multilang/multilang_administrations.php b/www/plugins/multilang/multilang_administrations.php
new file mode 100644 (file)
index 0000000..7d4660f
--- /dev/null
@@ -0,0 +1,56 @@
+<?php\r
+/**\r
+ * Fichier d'installation / upgrade et désinstallation du plugin Multilang\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * Fonction d'upgrade/maj\r
+ * On crée une configuration par défaut\r
+ *\r
+ * @param string $nom_meta_base_version\r
+ * @param string $version_cible\r
+ */\r
+function multilang_upgrade($nom_meta_base_version,$version_cible){\r
+\r
+       $maj = array();\r
+       \r
+       $maj['create'] = array(\r
+               array('multilang_creer_config'),\r
+       );\r
+       include_spip('base/upgrade');\r
+       maj_plugin($nom_meta_base_version, $version_cible, $maj);\r
+\r
+}\r
+\r
+function multilang_creer_config(){\r
+       include_spip('inc/config');\r
+               $config = lire_config('multilang');\r
+       if (!is_array($config))\r
+               $config = array();\r
+       $config_defaut = array_merge(array(\r
+                       'siteconfig' => 'on',\r
+                       'article' => '',\r
+                       'breve' => '',\r
+                       'rubrique' => 'on',\r
+                       'auteur' => 'on',\r
+                       'document' => 'on',\r
+                       'motcle' => '',\r
+                       'site' => '',\r
+                       'evenement' => ''\r
+       ), $config);\r
+       ecrire_meta('multilang', serialize($config_defaut));\r
+}\r
+/**\r
+ * Fonction de desinstallation\r
+ * On efface uniquement la méta d'installation\r
+ *\r
+ * @param float $nom_meta_base_version\r
+ */\r
+function multilang_vider_tables($nom_meta_base_version) {\r
+       effacer_meta('multilang');\r
+       effacer_meta($nom_meta_base_version);\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/multilang/multilang_pipelines.php b/www/plugins/multilang/multilang_pipelines.php
new file mode 100644 (file)
index 0000000..85058c8
--- /dev/null
@@ -0,0 +1,141 @@
+<?php\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * Insertion dans le pipeline insert_head_css (SPIP)\r
+ * si on a configuré multilang pour s'insérer dans l'espace public\r
+ *\r
+ * @param string $flux Le contenu du head CSS\r
+ * @return string $flux Le contenu du head CSS modifié\r
+ */\r
+function multilang_insert_head_css($flux){\r
+       if(!function_exists('lire_config'))\r
+               include_spip('inc/config');\r
+       \r
+       $multilang_public = lire_config('multilang/multilang_public','off');\r
+       if($multilang_public == 'on'){\r
+\r
+               static $done = false;\r
+\r
+               if (!$done) {\r
+                       $done = true;\r
+                       $flux .= '<link rel="stylesheet" href="'.url_absolue(generer_url_public('multilang.css')).'" type="text/css" media="all" />';\r
+               }\r
+       }\r
+       return $flux;\r
+}\r
+\r
+/**\r
+ * Insertion dans le pipeline insert_head_prive (SPIP)\r
+ * Ajoute css et javascript dans le <head> privé\r
+ *\r
+ * @param string $flux \r
+ *             Le contenu du head\r
+ * @return string $flux \r
+ *             Le contenu du head modifié\r
+ */\r
+function multilang_insert_head_prive($flux){\r
+       if(!function_exists('lire_config'))\r
+               include_spip('inc/config');\r
+       $config = lire_config('multilang',array());\r
+\r
+       $flux .= multilang_inserer_head($config);\r
+\r
+       return $flux;\r
+}\r
+\r
+/**\r
+ * Insertion dans le pipeline insert_head (SPIP)\r
+ * si on a configuré multilang pour s'insérer dans l'espace public\r
+ *\r
+ * @param string $flux \r
+ *             Le contenu du head\r
+ * @return string $flux \r
+ *             Le contenu du head modifié\r
+ */\r
+function multilang_insert_head($flux){\r
+       if(!function_exists('lire_config'))\r
+               include_spip('inc/config');\r
+       $config = lire_config('multilang',array());\r
+\r
+       if($config['multilang_public'] == 'on'){\r
+               $flux .= multilang_insert_head_css(''); // au cas ou il n'est pas implemente\r
+               $flux .= multilang_inserer_head($config);\r
+       }\r
+       return $flux;\r
+}\r
+\r
+/**\r
+ * La fonction de modification du $flux pour l'insertion dans le head qu'il\r
+ * soit privé ou public\r
+ *\r
+ * @param array $config La configuration du plugin\r
+ * @return string $data Le contenu textuel qui sera inséré dans le head\r
+ */\r
+function multilang_inserer_head($config=array()){\r
+       /**\r
+        * N'activer multilang que si plus d'une langue dans le site\r
+        */\r
+       if(count($langues = explode(',',$GLOBALS["meta"]["langues_multilingue"])) > 1){\r
+               $data = '\r
+<script type="text/javascript" src="'.generer_url_public("multilang.js","lang=".$GLOBALS["spip_lang"]).'"></script>\r
+';\r
+       }\r
+       return $data;\r
+}\r
+\r
+/**\r
+ * Insertion dans le pipeline affichage_final (SPIP)\r
+ * \r
+ * Sur la page crayons.js, on insère également notre javascript pour être utilisable\r
+ * dans les crayons\r
+ * \r
+ * @param string $flux Le contenu de la page\r
+ * @return string $flux Le contenu de la page modifiée \r
+ */\r
+function multilang_affichage_final($flux){\r
+       if(isset($_REQUEST['page']) && $_REQUEST['page'] == 'crayons.js'){\r
+               if(!function_exists('lire_config'))\r
+                       include_spip('inc/config');\r
+               $config = lire_config('multilang',array());\r
+               \r
+               /**\r
+                * On n'utilise multilang que si l'espace public est activé ainsi que les crayons\r
+                */\r
+               if(($config['multilang_public'] == 'on') && ($config['multilang_crayons'] == 'on')){\r
+                       unset($config['multilang_public']);\r
+                       unset($config['multilang_crayons']);\r
+                       $root = '' ;\r
+                       \r
+                       if(isset($config['siteconfig']) && $config['siteconfig']){\r
+                               $root .= ',input[type=hidden][name*=name_][value|=meta-valeur]';\r
+                               unset($config['siteconfig']);\r
+                       }\r
+                       \r
+                       foreach($config as $conf => $val){\r
+                               if($val == 'on') { // Articles\r
+                                       $root .= ',input[type=hidden][name*=name_][value|='.$conf.']:not(input[value|='.$conf.'-logo])';\r
+                                       unset($config[$conf]);\r
+                               }\r
+                       }\r
+                       $texte = '\r
+                               var crayons_multilang_init = function(){\r
+                                       var crayons_root = ".formulaire_spip:has('.$root.')";\r
+                                       var fields_selector = "textarea,input:text:not(input.date,input.heure,*.nomulti)";\r
+                                       var forms_selector = "form[class!=\'form_upload\'][class!=\'form_upload_icon\']";\r
+                                       var root_opt = "form:has(.multilang)";\r
+                                       var fields_selector_opt = ".multilang";\r
+                                       multilang_init_lang({fields:fields_selector,fields_opt:fields_selector_opt,root:crayons_root,root_opt:root_opt,forms:forms_selector,init_done:false});\r
+                               }\r
+                               \r
+                               cQuery(document).ready(function(){\r
+                                       if(typeof onAjaxLoad == "function") onAjaxLoad(crayons_multilang_init);\r
+                                       crayons_multilang_init();\r
+                               });';\r
+                       $flux .= $texte;\r
+               }\r
+       }\r
+       return $flux;\r
+}\r
+?>
\ No newline at end of file
diff --git a/www/plugins/multilang/paquet.xml b/www/plugins/multilang/paquet.xml
new file mode 100644 (file)
index 0000000..239700c
--- /dev/null
@@ -0,0 +1,29 @@
+<paquet
+       prefix="multilang"
+       categorie="edition"
+       version="0.9.2"
+       etat="stable"
+       compatibilite="[3.0.0;3.0.99]"
+       logo="images/multilang-32.png"
+       schema="0.1"
+       documentation="http://contrib.spip.net/?article3498"
+>      
+
+       <nom>Multilang</nom>
+       <!-- Gérer l'affichage du contenu des tags multi par un menu -->
+
+       <auteur>Renato Formato</auteur>
+       <auteur lien="http://www.kent1.info">kent1</auteur>
+       <auteur lien="http://contrib.spip.net/?auteur10787">Yffic</auteur>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>
+
+       <pipeline nom="header_prive" action="insert_head_prive" inclure="multilang_pipelines.php" />
+       <pipeline nom="insert_head_css" inclure="multilang_pipelines.php" />
+       <pipeline nom="insert_head" inclure="multilang_pipelines.php" />
+       <pipeline nom="affichage_final" inclure="multilang_pipelines.php" />
+       <menu nom="configurer_multilangue" titre="multilang:configuration_multilang" parent="menu_configuration" icone="images/multilang-16.png" />
+       <necessite nom="saisies" compatibilite="[1.1;[" />
+
+       <utilise nom="crayons" />
+</paquet>
diff --git a/www/plugins/multilang/prive/squelettes/contenu/configurer_multilang.html b/www/plugins/multilang/prive/squelettes/contenu/configurer_multilang.html
new file mode 100644 (file)
index 0000000..48dde44
--- /dev/null
@@ -0,0 +1,5 @@
+[(#AUTORISER{configurer,multilang}|sinon_interdire_acces)]
+<h1 class="grostitre"><:multilang:configuration_multilang:></h1>
+<div class="ajax">
+       #FORMULAIRE_CONFIGURER_MULTILANG
+</div>
\ No newline at end of file
diff --git a/www/plugins/multilang/prive/squelettes/contenu/configurer_multilangue.html b/www/plugins/multilang/prive/squelettes/contenu/configurer_multilangue.html
new file mode 100644 (file)
index 0000000..e931019
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=prive/squelettes/contenu/configurer_multilang,env} />
diff --git a/www/plugins/multilang/prive/style_prive_plugin_multilang.html b/www/plugins/multilang/prive/style_prive_plugin_multilang.html
new file mode 100644 (file)
index 0000000..6fe1d00
--- /dev/null
@@ -0,0 +1,66 @@
+#CACHE{0*100,cache-client}
+#HTTP_HEADER{Content-Type: text/css; charset=iso-8859-15}
+#HTTP_HEADER{Vary: Accept-Encoding}
+
+#SET{claire,##ENV{couleur_claire,edf3fe}}
+#SET{foncee,##ENV{couleur_foncee,3874b0}}
+#SET{left,#ENV{ltr}|choixsiegal{left,left,right}}
+#SET{right,#ENV{ltr}|choixsiegal{left,right,left}}
+
+.menu_multilang {
+       background-color:transparent;
+       padding:5px;
+}
+
+.menu_multilang .langues{
+       overflow:auto;
+}
+
+.menu_multilang .langues a{
+       cursor:pointer;
+       font-weight:normal;
+       margin-right:2px;
+       display:block;
+       float:left;
+}
+
+.menu_multilang .langues a.on{
+       font-weight:bold;
+}
+
+.menu_multilang .langues a.empty{
+       background-color:#GET{foncee};
+       padding:2px;
+       color:#fff;
+}
+
+.menu_multilang .multilang_message{
+       clear:both;
+}
+
+.menu_lang_flottant{
+       border-bottom:3px solid #GET{foncee};
+       background-color:[#(#GET{claire}|couleur_eclaircir)];
+       opacity:.8;
+}
+
+#SET{langues,#EVAL{$GLOBALS["meta"]["langues_multilingue"]}}
+<BOUCLE_langues(POUR){tableau #GET{langues}|explode{','}}>
+.multi_lang_#VALEUR {
+       background-position:98% 1px;
+       background-repeat:no-repeat;
+       background-image:url([(#VAL{Multi #VALEUR}|image_typo{taille=11,couleur=cccccc}|extraire_attribut{src}|url_absolue)]);
+}
+</BOUCLE_langues>
+
+.multi_lang_no_multi {
+       background-position:98% 1px;
+       background-repeat:no-repeat;
+       background-image:url([(#VAL{No multi}|image_typo{taille=11,couleur=cccccc}|extraire_attribut{src}|url_absolue)]);
+}
+
+.multi_lang_broken {
+       background-position:98% 1px;
+       background-repeat:no-repeat;
+       background-image:url(#CHEMIN{images/multi_forbidden.png});
+}
\ No newline at end of file
diff --git a/www/plugins/multilang/prive/themes/spip/images/multilang-16.png b/www/plugins/multilang/prive/themes/spip/images/multilang-16.png
new file mode 100644 (file)
index 0000000..955defc
Binary files /dev/null and b/www/plugins/multilang/prive/themes/spip/images/multilang-16.png differ
diff --git a/www/plugins/multilang/prive/themes/spip/images/multilang-24.png b/www/plugins/multilang/prive/themes/spip/images/multilang-24.png
new file mode 100644 (file)
index 0000000..11e6ed4
Binary files /dev/null and b/www/plugins/multilang/prive/themes/spip/images/multilang-24.png differ
diff --git a/www/plugins/multilang/svn.revision b/www/plugins/multilang/svn.revision
new file mode 100644 (file)
index 0000000..42c256c
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/multilang/trunk
+Revision: 72466
+Dernier commit: 2013-04-30 12:00:50 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/multilang/trunk</origine>
+<revision>72466</revision>
+<commit>2013-04-30 12:00:50 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/nospam/images/nospam-32.png b/www/plugins/nospam/images/nospam-32.png
new file mode 100644 (file)
index 0000000..42a2218
Binary files /dev/null and b/www/plugins/nospam/images/nospam-32.png differ
diff --git a/www/plugins/nospam/images/nospam.gif b/www/plugins/nospam/images/nospam.gif
new file mode 100644 (file)
index 0000000..b0698ef
Binary files /dev/null and b/www/plugins/nospam/images/nospam.gif differ
diff --git a/www/plugins/nospam/images/nospam.png b/www/plugins/nospam/images/nospam.png
new file mode 100644 (file)
index 0000000..b1101c7
Binary files /dev/null and b/www/plugins/nospam/images/nospam.png differ
diff --git a/www/plugins/nospam/inc/detecter_langue.php b/www/plugins/nospam/inc/detecter_langue.php
new file mode 100644 (file)
index 0000000..6941076
--- /dev/null
@@ -0,0 +1,226 @@
+<?php
+
+$GLOBALS["ngrams"]['af'] = array("ie "," di","die","en ","ing","an "," en","van"," va","ng ","te ","n d","ver","er ","e v"," ge"," be","de "," ve","nde"," in"," te","le ","der","ers","et ","oor"," 'n","'n ","at ","eer","ste","ord","aar","sie"," wa","es ","e s","aan"," on","is ","in ","e o","rde","e b","asi","rin","ond","e w","el "," is","and","e e","eid","e d","om ","ke "," om","eri"," wo","e g","r d","ale","wat"," vo","id ","it ","rd "," aa","lik"," we","t d"," op","e t","ngs","se ","end","uit"," st"," le","ens","ter"," re","e a","ies","wor","g v","sta","n s"," na"," pr","n o"," me","al ","of "," vi","erd","lee","e k"," de","ite","erk","ik ","e r","e p","n v","e i","e n","een","eli","wer"," of"," da","tel","nie","ike","s e","taa","ge ","vir","hei","ir ","reg","ede","s v","ur ","pro","ele","ion","wet","e l"," mo","e m","daa","sio","s d"," he"," to","ent","ard","nge"," oo","eur","lle","ien","n b","eke","lin","raa"," ni","ont","bes","rdi","voo","ns ","n a","del","dig","nas"," sa"," gr","nis","kom"," ui","men","op ","ins","ona","ere","s o"," so","n g","ig ","moe"," ko","rs ","ges","nal","vol","e h","geb","rui","ang","ige","oet","ar ","wys","lig","as ","n w"," as","met","gs ","deu","t v","aal","erw","dit","ken","sse","kel"," hu","ewe","din","n t"," se","est","ika","n p","ntw","t i","eni"," ka","n e","doe","ali","eme","gro","nte"," ho","nsi","gen","ier","gew","n h","or "," ma","ind","ne ","ek ","aat","n '"," sk","ide"," ta","dat","ska","ger","soo","n k","s i"," af","tee","nd ","eel","hul","nee","woo","rik","d v","n m","re ","art","ebr","lan","kke","ron","aam","tre","str","kan","ree","lei","t o","gra","het","evo","tan","den","ist"," do","bru","toe","olg","rsk","uik","rwy","min","lge","g e","g o","nst","r v","gte","waa","we ","ans","esi","ese","voe","epa","gel"," hi","vin","nse","s w","s t","tei","eit","pre");
+$GLOBALS["ngrams"]['ar'] = array(" ال","الع","لعر","عرا","راق"," في","في ","ين ","ية ","ن ا","الم","ات ","من ","ي ا"," من","الأ","ة ا","اق "," وا","اء ","الإ"," أن","وال","ما "," عل","لى ","ت ا","ون ","هم ","اقي","ام ","ل ا","أن ","م ا","الت","لا ","الا","ان ","ها ","ال ","ة و","ا ا","رها","لام","يين"," ول","لأم","نا ","على","ن ي","الب","اد ","الق","د ا","ذا ","ه ا"," با","الد","ب ا","مري","لم "," إن"," لل","سلا","أمر","ريك","مة ","ى ا","ا ي"," عن"," هذ","ء ا","ر ا","كان","قتل","إسل","الح","وا "," إل","ا أ","بال","ن م","الس","رة ","لإس","ن و","هاب","ي و","ير "," كا","لة ","يات"," لا","انت","ن أ","يكي","الر","الو","ة ف","دة ","الج","قي ","وي ","الذ","الش","امي","اني","ذه ","عن ","لما","هذه","ول ","اف ","اوي","بري","ة ل"," أم"," لم"," ما","يد "," أي","إره","ع ا","عمل","ولا","إلى","ابي","ن ف","ختط","لك ","نه ","ني ","إن ","دين","ف ا","لذي","ي أ","ي ب"," وأ","ا ع","الخ","تل ","تي ","قد ","لدي"," كل"," مع","اب ","اخت","ار ","الن","علا","م و","مع ","س ا","كل ","لاء","ن ب","ن ت","ي م","عرب","م ب"," وق"," يق","ا ل","ا م","الف","تطا","داد","لمس","له ","هذا"," مح","ؤلا","بي ","ة م","ن ل","هؤل","كن ","لإر","لتي"," أو"," ان"," عم","ا ف","ة أ","طاف","عب ","ل م","ن ع","ور ","يا "," يس","ا ت","ة ب","راء","عال","قوا","قية","لعا","م ي","مي ","مية","نية","أي ","ابا","بغد","بل ","رب ","عما","غدا","مال","ملي","يس "," بأ"," بع"," بغ"," وم","بات","بية","ذلك","عة ","قاو","قيي","كي ","م م","ي ع"," عر"," قا","ا و","رى ","ق ا","وات","وم "," هؤ","ا ب","دام","دي ","رات","شعب","لان","لشع","لقو","ليا","ن ه","ي ت","ي ي"," وه"," يح","جرا","جما","حمد","دم ","كم ","لاو","لره","ماع","ن ق","نة ","هي "," بل"," به"," له"," وي","ا ك","اذا","اع ","ت م","تخا","خاب","ر م","لمت","مسل","ى أ","يست","يطا"," لأ"," لي","أمن","است","بعض","ة ت","ري ","صدا","ق و","قول","مد ","نتخ","نفس","نها","هنا","أعم","أنه","ائن","الآ","الك","حة ","د م","ر ع","ربي");
+$GLOBALS["ngrams"]['az'] = array("lər","in ","ın ","lar","da ","an ","ir ","də ","ki "," bi","ən ","əri","arı","ər ","dir","nda"," ki","rin","nın","əsi","ini"," ed"," qa"," tə"," ba"," ol","ası","ilə","rın"," ya","anı"," və","ndə","ni ","ara","ını","ınd"," bu","si ","ib ","aq ","dən","iya","nə ","rə ","n b","sın","və ","iri","lə ","nin","əli"," de"," mü","bir","n s","ri ","ək "," az"," sə","ar ","bil","zər","bu ","dan","edi","ind","man","un ","ərə"," ha","lan","yyə","iyy"," il"," ne","r k","ə b"," is","na ","nun","ır "," da"," hə","a b","inə","sin","yan","ərb"," də"," mə"," qə","dır","li ","ola","rba","azə","can","lı ","nla"," et"," gö","alı","ayc","bay","eft","ist","n i","nef","tlə","yca","yət","əcə"," la","ild","nı ","tin","ldi","lik","n h","n m","oyu","raq","ya ","əti"," ar","ada","edə","mas","sı ","ına","ə d","ələ","ayı","iyi","lma","mək","n d","ti ","yin","yun","ət ","azı","ft ","i t","lli","n a","ra "," cə"," gə"," ko"," nə"," oy","a d","ana","cək","eyi","ilm","irl","lay","liy","lub","n ə","ril","rlə","unu","ver","ün ","ə o","əni"," he"," ma"," on"," pa","ala","dey","i m","ima","lmə","mət","par","yə ","ətl"," al"," mi"," sa"," əl","adı","akı","and","ard","art","ayi","i a","i q","i y","ili","ill","isə","n o","n q","olu","rla","stə","sə ","tan","tel","yar","ədə"," me"," rə"," ve"," ye","a k","at ","baş","diy","ent","eti","həs","i i","ik ","la ","miş","n n","nu ","qar","ran","tər","xan","ə a","ə g","ə t"," dü","ama","b k","dil","era","etm","i b","kil","mil","n r","qla","r s","ras","siy","son","tim","yer","ə k"," gü"," so"," sö"," te"," xa","ai ","bar","cti","di ","eri","gör","gün","gəl","hbə","ihə","iki","isi","lin","mai","maq","n k","n t","n v","onu","qan","qəz","tə ","xal","yib","yih","zet","zır","ıb ","ə m","əze"," br"," in"," i̇r"," pr"," ta"," to"," üç","a o","ali","ani","anl","aql","azi","bri");
+$GLOBALS["ngrams"]['bg'] = array("на "," на","то "," пр"," за","та "," по","ите","те ","а п","а с"," от","за ","ата","ия "," в ","е н"," да","а н"," се"," ко","да ","от ","ани","пре","не ","ени","о н","ни ","се "," и ","но ","ане","ето","а в","ва ","ван","е п","а о","ото","ран","ат ","ред"," не","а д","и п"," до","про"," съ","ли ","при","ния","ски","тел","а и","по ","ри "," е "," ка","ира","кат","ние","нит","е з","и с","о с","ост","че "," ра","ист","о п"," из"," са","е д","ини","ки ","мин"," ми","а б","ава","е в","ие ","пол","ств","т н"," въ"," ст"," то","аза","е о","ов ","ст ","ът ","и н","ият","нат","ра "," бъ"," че","алн","е с","ен ","ест","и д","лен","нис","о о","ови"," об"," сл","а р","ато","кон","нос","ров","ще "," ре"," с "," сп","ват","еше","и в","иет","о в","ове","ста","а к","а т","дат","ент","ка ","лед","нет","ори","стр","стъ","ти ","тър"," те","а з","а м","ад ","ана","ено","и о","ина","ити","ма ","ска","сле","тво","тер","ция","ят "," бе"," де"," па","ате","вен","ви ","вит","и з","и и","нар","нов","ова","пов","рез","рит","са ","ята"," го"," ще","али","в п","гра","е и","еди","ели","или","каз","кит","лно","мен","оли","раз"," ве"," гр"," им"," ме"," пъ","ави","ако","ача","вин","во ","гов","дан","ди ","до ","ед ","ери","еро","жда","ито","ков","кол","лни","мер","нач","о з","ола","он ","она","пра","рав","рем","сия","сти","т п","тан","ха ","ше ","шен","ълг"," ба"," си","аро","бъл","в р","гар","е е","елн","еме","ико","има","ко ","кои","ла ","лга","о д","ози","оит","под","рес","рие","сто","т к","т м","т с","уст"," би"," дв"," дъ"," ма"," мо"," ни"," ос","ала","анс","ара","ати","аци","беш","вър","е р","едв","ема","жав","и к","иал","ица","иче","кия","лит","о б","ово","оди","ока","пос","род","сед","слу","т и","тов","ува","циа","чес","я з"," во"," ил"," ск"," тр"," це","ами","ари","бат","би ","бра","бъд");
+$GLOBALS["ngrams"]['br'] = array("ar "," a ","en ","an ","et "," ar","ez "," he"," ha"," an","n d"," ho"," da"," va"," eu","ur ","er "," pe"," de","nt "," ma","n e","var"," en"," be"," di"," ch"," e ","eur","ou ","uz ","it ","ho ","z a","he ","da ","a z","n a"," do","oue","ha ","n h"," ne","dou","t a"," ke"," ev","un ","ag ","t e","euz"," me"," ga"," : ","ant"," zo","ll ","ad ","ch ","oun","t h"," la","t d","r a","a d"," ve","r b","ed ","enn","hag"," re","ue ","zo ","a v","ra ","r p","ma "," go","r g","el ","cho","evi","a g","a r","hen","vez","deu","aou","c'h","eo ","z e","ent","z h","che","a b","vit","vel"," dr","eme","eve","r m","our","mp ","e a"," ra"," ka"," pa","omp","han","eun","den","ne ","r h","rou","a e","ist"," gu","d a","o d","uez","gan","az "," tr"," eo","e d","och","ell","e v","or ","va ","on "," br","r v","ro ","ket","ava","all","gou","o e","g a","re ","ude","e e","oud"," se"," ko","z d","eze","tra","lav","e h","kou","oul"," al","r e","lou","ken"," ze","iou","are","ud "," gr","u a","hou","ach","n t"," na","mar","r c","a l","ret","zou"," er","l a","mad","nn ","a c","ze ","oll","a h","r d","l e","ris","e g","per","eza","mez","a n","ech","oua","st ","ont","bed","at "," zi","t m","iz ","za ","bre","d e","o a","o k","hor","d h","rn ","a m","em ","ene"," c'","etr","e k","ara","in "," et","gue","t g","us "," em","e z","t k","cha","na ","ouz","as ","nte","ut "," ou"," ta"," le","ere","red"," ba"," sa","g e","rez","a k","nan"," sk","e m","rei"," te","t p","dre","ele","men","ran","o h","e c","e b","her","tro"," dh","ber","ste","o p","reu"," za","ui ","bar","hon","n n","out","spe","dis","alo","uel","a a","hol","ver","ezo","bez","hoa","i a","tre","ank","gal","kri","bet","ni ","dig","al ","a p","una","r s","env","net","ave","ten"," kr","rea","e p"," hi","tez","ta ","l d","u d","eud","r z","r r","ren");
+$GLOBALS["ngrams"]['ca'] = array(" de","es ","de ","la "," la","el ","que"," el"," co","ent","s d"," qu"," i ","en ","er "," a ","ls ","nt "," pe","e l","a d"," en","per","ci ","ar ","ue ","al "," se","est","at "," es","ts "," s "," pr","aci"," un","res","men","s e","del","s a","s p"," re","les"," l'","na ","a l"," ca"," d'","els","a p","ia ","ns ","con"," le","tat","a c","i d","a a","ra ","a e"," no","ant"," al","t d","s i"," di","ta ","re ","a s","com","s c","ita","ons","sta","ica"," po","r a"," in","pro","tre"," pa","ues","amb","ion","des","un "," ma","da ","s s","a i","an ","mb "," am","l d","e d","va ","pre","ter","e e","e c","a m","cia","una","i e","nci","tra"," te","ona","os ","t e","n e","l c","ca ","cio","l p"," tr","par","r l","t a","e p","aqu","nta"," so","ame","era","r e","e s","ada","n a","s q"," si"," ha","als","tes"," va"," m ","ici","nte","s l","s m","i a","or "," mo","ist","ect","lit","m s"," to","ir ","a t","esp","ran","str","om ","l s","st ","nts"," me","no ","r d","d'a","l'a","ats","ria","s t"," ta","sen","rs ","eix","tar","s n","n l","tal","e a","t p","art"," mi"," ll","tic","ten","ser"," aq","ina","ntr","a f","sti","ol ","a q","for","ura","ers","ari","int","act","l'e"," fi","r s","e t","tor","si ","ste","rec","a r"," fe","is ","em ","n d","car","bre"," fo"," vi"," an","ali","i p","ix ","ell","l m","pos","orm","l l","i l"," ac","fer","s r","ess","eu ","e m","ens","ara","eri","sa ","ssi","us ","ort","tot","ll ","por","ora"," ci","tan","ass","n c","ost","nes","rac","a u","ver","ont","ha "," ti","itz","gra","t c"," n ","a v","ren","cat","nal"," ri","qua","t l"," do","t s","rma","ual","i s","s f","n p","s v","te ","t i"," ba","cte","tam","man","l t","ial"," fa","ic "," ve","ble","a n","all","tza","ies"," s'","le ","omp","r c"," nc","rti","it ","rre","fic","any","on "," sa","r p","tur");
+$GLOBALS["ngrams"]['ceb'] = array("ng ","sa "," sa","ang","ga ","nga"," ka"," ng","an "," an"," na"," ma"," ni","a s","a n","on "," pa"," si","a k","a m"," ba","ong","a i","ila"," mg","mga","a p","iya","a a","ay ","ka ","ala","ing","g m","n s","g n","lan"," gi","na ","ni ","o s","g p","n n"," da","ag ","pag","g s","yan","ayo","o n","si "," mo","a b","g a","ail","g b","han","a d","asu","nag","ya ","man","ne ","pan","kon"," il"," la","aka","ako","ana","bas","ko ","od ","yo "," di"," ko"," ug","a u","g k","kan","la ","len","sur","ug "," ai","apa","aw ","d s","g d","g g","ile","nin"," iy"," su","ene","og ","ot ","aba","aha","as ","imo"," ki","a t","aga","ban","ero","nan","o k","ran","ron","sil","una","usa"," us","a g","ahi","ani","er ","ha ","i a","rer","yon"," pu","ini","nak","ro ","to ","ure"," ed"," og"," wa","ili","mo ","n a","nd ","o a"," ad"," du"," pr","aro","i s","ma ","n m","ulo","und"," ta","ara","asa","ato","awa","dmu","e n","edm","ina","mak","mun","niy","san","wa "," tu"," un","a l","bay","iga","ika","ita","kin","lis","may","os "," ar","ad ","ali","ama","ers","ipa","isa","mao","nim","t s","tin"," ak"," ap"," hi","abo","agp","ano","ata","g i","gan","gka","gpa","i m","iha","k s","law","or ","rs ","siy","tag"," al"," at"," ha"," hu"," im","a h","bu ","e s","gma","kas","lag","mon","nah","ngo","r s","ra ","sab","sam","sul","uba","uha"," lo"," re","ada","aki","aya","bah","ce ","d n","lab","pa ","pak","s n","s s","tan","taw","te ","uma","ura"," in"," lu","a c","abi","at ","awo","bat","dal","dla","ele","g t","g u","gay","go ","hab","hin","i e","i n","kab","kap","lay","lin","nil","pam","pas","pro","pul","ta ","ton","uga","ugm","unt"," co"," gu"," mi"," pi"," ti","a o","abu","adl","ado","agh","agk","ao ","art","bal","cit","di ","dto","dun","ent","g e","gon","gug","ia ","iba","ice","in ","inu","it ","kaa");
+$GLOBALS["ngrams"]['cs'] = array(" pr"," po","ní ","pro"," na","na "," př","ch "," je"," ne","že "," že"," se"," do"," ro"," st"," v "," ve","pře","se ","ho ","sta"," to"," vy"," za","ou "," a ","to "," by","la ","ce ","e v","ist","le ","pod","í p"," vl","e n","e s","je ","ké ","by ","em ","ých"," od","ova","řed","dy ","ení","kon","li ","ně ","str"," zá","ve "," ka"," sv","e p","it ","lád","oho","rov","roz","ter","vlá","ím "," ko","hod","nis","pří","ský"," mi"," ob"," so","a p","ali","bud","edn","ick","kte","ku ","o s","al ","ci ","e t","il ","ny ","né ","odl","ová","rot","sou","ání"," bu"," mo"," o ","ast","byl","de ","ek ","ost"," mí"," ta","es ","jed","ky ","las","m p","nes","ním","ran","rem","ros","ého"," de"," kt"," ni"," si"," vý","at ","jí ","ký ","mi ","pre","tak","tan","y v","řek"," ch"," li"," ná"," pa"," ře","da ","dle","dne","i p","i v","ly ","min","o n","o v","pol","tra","val","vní","ích","ý p","řej"," ce"," kd"," le","a s","a z","cen","e k","eds","ekl","emi","kl ","lat","lo ","mié","nov","pra","sku","ské","sti","tav","ti ","ty ","ván","vé ","y n","y s","í s","í v","ě p"," dn"," ně"," sp"," čs","a n","a t","ak ","dní","doh","e b","e m","ejn","ena","est","ini","m z","nal","nou","ná ","ovi","ové","ový","rsk","stá","tí ","tře","tů ","ude","za ","é p","ém ","í d"," ir"," zv","ale","aně","ave","cké","den","e z","ech","en ","erý","hla","i s","iér","lov","mu ","neb","nic","o b","o m","pad","pot","rav","rop","rý ","sed","si ","t p","tic","tu ","tě ","u p","u v","vá ","výš","zvý","ční","ří ","ům "," bl"," br"," ho"," ja"," re"," s "," z "," zd","a v","ani","ato","bla","bri","ečn","eře","h v","i n","ie ","ila","irs","ite","kov","nos","o o","o p","oce","ody","ohl","oli","ovo","pla","poč","prá","ra ","rit","rod","ry ","sd ","sko","ssd","tel","u s","vat","veř","vit","vla","y p","áln","čss","šen"," al");
+$GLOBALS["ngrams"]['cy'] = array("yn ","dd "," yn"," y ","ydd","eth","th "," i ","aet","d y","ch ","od ","ol ","edd"," ga"," gw","'r ","au ","ddi","ad "," cy"," gy"," ei"," o ","iad","yr ","an ","bod","wed"," bo"," dd","el ","n y"," am","di ","edi","on "," we"," ym"," ar"," rh","odd"," ca"," ma","ael","oed","dae","n a","dda","er ","h y","all","ei "," ll","am ","eu ","fod","fyd","l y","n g","wyn","d a","i g","mae","neu","os "," ne","d i","dod","dol","n c","r h","wyd","wyr","ai ","ar ","in ","rth"," fy"," he"," me"," yr","'n ","dia","est","h c","hai","i d","id ","r y","y b"," dy"," ha","ada","i b","n i","ote","rot","tes","y g","yd "," ad"," mr"," un","cyn","dau","ddy","edo","i c","i w","ith","lae","lla","nd ","oda","ryd","tho"," a "," dr","aid","ain","ddo","dyd","fyn","gyn","hol","io ","o a","wch","wyb","ybo","ych"," br"," by"," di"," fe"," na"," o'"," pe","art","byd","dro","gal","l e","lai","mr ","n n","r a","rhy","wn ","ynn"," on"," r ","cae","d g","d o","d w","gan","gwy","n d","n f","n o","ned","ni ","o'r","r d","ud ","wei","wrt"," an"," cw"," da"," ni"," pa"," pr"," wy","d e","dai","dim","eud","gwa","idd","im ","iri","lwy","n b","nol","r o","rwy"," ch"," er"," fo"," ge"," hy"," i'"," ro"," sa"," tr","bob","cwy","cyf","dio","dyn","eit","hel","hyn","ich","ll ","mdd","n r","ond","pro","r c","r g","red","rha","u a","u c","u y","y c","ymd","ymr","yw "," ac"," be"," bl"," co"," os","adw","ae ","af ","d p","efn","eic","en ","eol","es ","fer","gel","h g","hod","ied","ir ","laf","n h","na ","nyd","odo","ofy","rdd","rie","ros","stw","twy","yda","yng"," at"," de"," go"," id"," oe"," â ","'ch","ac ","ach","ae'","al ","bl ","d c","d l","dan","dde","ddw","dir","dla","ed ","ela","ell","ene","ewn","gyd","hau","hyw","i a","i f","iol","ion","l a","l i","lia","med","mon","n s","no ","obl","ola","ref","rn ","thi","un ");
+$GLOBALS["ngrams"]['da'] = array("er ","en "," de","et ","der","de ","for"," fo"," i ","at "," at","re ","det"," ha","nde","ere","ing","den"," me"," og","ger","ter"," er"," si","and"," af","or "," st"," ti"," en","og ","ar ","il ","r s","ige","til","ke ","r e","af ","kke"," ma"," på","om ","på ","ed ","ge ","end","nge","t s","e s","ler"," sk","els","ern","sig","ne ","lig","r d","ska"," vi","har"," be"," se","an ","ikk","lle","gen","n f","ste","t a","t d","rin"," ik","es ","ng ","ver","r b","sen","ede","men","r i"," he"," et","ig ","lan","med","nd ","rne"," da"," in","e t","mme","und"," om","e e","e m","her","le ","r f","t f","så ","te "," so","ele","t e"," ko","est","ske"," bl","e f","ekt","mar","bru","e a","el ","ers","ret","som","tte","ve "," la"," ud"," ve","age","e d","e h","lse","man","rug","sel","ser"," fi"," op"," pr","dt ","e i","n m","r m"," an"," re"," sa","ion","ner","res","t i","get","n s","one","orb","t h","vis","år "," fr","bil","e k","ens","ind","omm","t m"," hv"," je","dan","ent","fte","nin"," mi","e o","e p","n o","nte"," ku","ell","nas","ore","r h","r k","sta","sto","dag","eri","kun","lde","mer","r a","r v","rek","rer","t o","tor","tør"," få"," må"," to","boe","che","e v","i d","ive","kab","ns ","oel","se ","t v"," al"," bo"," un","ans","dre","ire","køb","ors","ove","ren","t b","ør "," ka","ald","bet","gt ","isk","kal","kom","lev","n d","n i","pri","r p","rbr","søg","tel"," så"," te"," va","al ","dir","eje","fis","gså","isc","jer","ker","ogs","sch","st ","t k","uge"," di","ag ","d a","g i","ill","l a","lsk","n a","on ","sam","str","tet","var"," mo","art","ash","att","e b","han","hav","kla","kon","n t","ned","r o","ra ","rre","ves","vil"," el"," kr"," ov","ann","e u","ess","fra","g a","g d","int","ngs","rde","tra"," år","akt","asi","em ","gel","gym","hol","kan","mna","n h","nsk","old");
+$GLOBALS["ngrams"]['de'] = array("en ","er "," de","der","ie "," di","die","sch","ein","che","ich","den","in ","te ","ch "," ei","ung","n d","nd "," be","ver","es "," zu","eit","gen","und"," un"," au"," in","cht","it ","ten"," da","ent"," ve","and"," ge","ine"," mi","r d","hen","ng ","nde"," vo","e d","ber","men","ei ","mit"," st","ter","ren","t d"," er","ere","n s","ste"," se","e s","ht ","des","ist","ne ","auf","e a","isc","on ","rte"," re"," we","ges","uch"," fü"," so","bei","e e","nen","r s","ach","für","ier","par","ür "," ha","as ","ert"," an"," pa"," sa"," sp"," wi","for","tag","zu ","das","rei","he ","hre","nte","sen","vor"," sc","ech","etz","hei","lan","n a","pd ","st ","sta","ese","lic"," ab"," si","gte"," wa","iti","kei","n e","nge","sei","tra","zen"," im"," la","art","im ","lle","n w","rde","rec","set","str","tei","tte"," ni","e p","ehe","ers","g d","nic","von"," al"," pr","an ","aus","erf","r e","tze","tür","uf ","ag ","als","ar ","chs","end","ge ","ige","ion","ls ","n m","ngs","nis","nt ","ord","s s","sse"," tü","ahl","e b","ede","em ","len","n i","orm","pro","rke","run","s d","wah","wer","ürk"," me","age","att","ell","est","hat","n b","oll","raf","s a","tsc"," es"," fo"," gr"," ja","abe","auc","ben","e n","ege","lie","n u","r v","re ","rit","sag"," am","agt","ahr","bra","de ","erd","her","ite","le ","n p","n v","or ","rbe","rt ","sic","wie","übe"," is"," üb","cha","chi","e f","e m","eri","ied","mme","ner","r a","sti","t a","t s","tis"," ko","arb","ds ","gan","n z","r f","r w","ran","se ","t i","wei","wir"," br"," np","am ","bes","d d","deu","e g","e k","efo","et ","eut","fen","hse","lte","n r","npd","r b","rhe","t w","tz "," fr"," ih"," ke"," ma","ame","ang","d s","eil","el ","era","erh","h d","i d","kan","n f","n l","nts","och","rag","rd ","spd","spr","tio"," ar"," en"," ka","ark","ass");
+$GLOBALS["ngrams"]['en'] = array(" th","the","he ","ed "," to"," in","er ","ing","ng "," an","nd "," of","and","to ","of "," co","at ","on ","in "," a ","d t"," he","e t","ion","es "," re","re ","hat"," sa"," st"," ha","her","tha","tio","or "," ''","en "," wh","e s","ent","n t","s a","as ","for","is ","t t"," be","ld ","e a","rs "," wa","ut ","ve ","ll ","al "," ma","e i"," fo","'s ","an ","est"," hi"," mo"," se"," pr","s t","ate","st ","ter","ere","ted","nt ","ver","d a"," wi","se ","e c","ect","ns "," on","ly ","tol","ey ","r t"," ca","ati","ts ","all"," no","his","s o","ers","con","e o","ear","f t","e w","was","ons","sta","'' ","sti","n a","sto","t h"," we","id ","th "," it","ce "," di","ave","d h","cou","pro","ad ","oll","ry ","d s","e m"," so","ill","cti","te ","tor","eve","g t","it "," ch"," de","hav","oul","ty ","uld","use"," al","are","ch ","me ","out","ove","wit","ys ","chi","t a","ith","oth"," ab"," te"," wo","s s","res","t w","tin","e b","e h","nce","t s","y t","e p","ele","hin","s i","nte"," li","le "," do","aid","hey","ne ","s w"," as"," fr"," tr","end","sai"," el"," ne"," su","'t ","ay ","hou","ive","lec","n't"," ye","but","d o","o t","y o"," ho"," me","be ","cal","e e","had","ple"," at"," bu"," la","d b","s h","say","t i"," ar","e f","ght","hil","igh","int","not","ren"," is"," pa"," sh","ays","com","n s","r a","rin","y a"," un","n c","om ","thi"," mi","by ","d i","e d","e n","t o"," by","e r","eri","old","ome","whe","yea"," gr","ar ","ity","mpl","oun","one","ow ","r s","s f","tat"," ba"," vo","bou","sam","tim","vot","abo","ant","ds ","ial","ine","man","men"," or"," po","amp","can","der","e l","les","ny ","ot ","rec","tes","tho","ica","ild","ir ","nde","ose","ous","pre","ste","era","per","r o","red","rie"," bo"," le","ali","ars","ore","ric","s m","str"," fa","ess","ie ","ist","lat","uri");
+$GLOBALS["ngrams"]['es'] = array(" de","de "," la","os ","la ","el ","es "," qu"," co","e l","as ","que"," el","ue ","en ","ent"," en"," se","nte","res","con","est"," es","s d"," lo"," pr","los"," y ","do ","ón ","ión"," un","ció","del","o d"," po","a d","aci","sta","te ","ado","pre","to ","par","a e","a l","ra ","al ","e e","se ","pro","ar ","ia ","o e"," re","ida","dad","tra","por","s p"," a ","a p","ara","cia"," pa","com","no "," di"," in","ien","n l","ad ","ant","e s","men","a c","on ","un ","las","nci"," tr","cio","ier","nto","tiv","n d","n e","or ","s c","enc","ern","io ","a s","ici","s e"," ma","dos","e a","e c","emp","ica","ivo","l p","n c","r e","ta ","ter","e d","esa","ez ","mpr","o a","s a"," ca"," su","ion"," cu"," ju","an ","da ","ene","ero","na ","rec","ro ","tar"," al"," an","bie","e p","er ","l c","n p","omp","ten"," em","ist","nes","nta","o c","so ","tes","era","l d","l m","les","ntr","o s","ore","rá ","s q","s y","sto","a a","a r","ari","des","e q","ivi","lic","lo ","n a","one","ora","per","pue","r l","re ","ren","una","ía ","ada","cas","ere","ide","min","n s","ndo","ran","rno"," ac"," ex"," go"," no","a t","aba","ble","ece","ect","l a","l g","lid","nsi","ons","rac","rio","str","uer","ust"," ha"," le"," mi"," mu"," ob"," pe"," pu"," so","a i","ale","ca ","cto","e i","e u","eso","fer","fic","gob","jo ","ma ","mpl","o p","obi","s m","sa ","sep","ste","sti","tad","tod","y s"," ci","and","ces","có ","dor","e m","eci","eco","esi","int","iza","l e","lar","mie","ner","orc","rci","ria","tic","tor"," as"," si","ce ","den","e r","e t","end","eri","esp","ial","ido","ina","inc","mit","o l","ome","pli","ras","s t","sid","sup","tab","uen","ues","ura","vo ","vor"," sa"," ti","abl","ali","aso","ast","cor","cti","cue","div","duc","ens","eti","imi","ini","lec","o q","oce","ort","ral","rma","roc","rod");
+$GLOBALS["ngrams"]['et'] = array("st "," ka","on ","ja "," va"," on"," ja"," ko","se ","ast","le ","es ","as ","is ","ud "," sa","da ","ga "," ta","aja","sta"," ku"," pe","a k","est","ist","ks ","ta ","al ","ava","id ","saa","mis","te ","val"," et","nud"," te","inn"," se"," tu","a v","alu","e k","ise","lu ","ma ","mes"," mi","et ","iku","lin","ad ","el ","ime","ne ","nna"," ha"," in"," ke"," võ","a s","a t","ab ","e s","esi"," la"," li","e v","eks","ema","las","les","rju","tle","tsi","tus","upa","use","ust","var"," lä","ali","arj","de ","ete","i t","iga","ilm","kui","li ","tul"," ei"," me"," sõ","aal","ata","dus","ei ","nik","pea","s k","s o","sal","sõn","ter","ul ","või"," el"," ne","a j","ate","end","i k","ita","kar","kor","l o","lt ","maa","oli","sti","vad","ään"," ju"," jä"," kü"," ma"," po"," üt","aas","aks","at ","ed ","eri","hoi","i s","ka ","la ","nni","oid","pai","rit","us ","ütl"," aa"," lo"," to"," ve","a e","ada","aid","ami","and","dla","e j","ega","gi ","gu ","i p","idl","ik ","ini","jup","kal","kas","kes","koh","s e","s p","sel","sse","ui "," pi"," si","aru","eda","eva","fil","i v","ida","ing","lää","me ","na ","nda","nim","ole","ots","ris","s l","sia","t p"," en"," mu"," ol"," põ"," su"," vä"," üh","a l","a p","aga","ale","aps","arv","e a","ela","ika","lle","loo","mal","pet","t k","tee","tis","vat","äne","õnn"," es"," fi"," vi","a i","a o","aab","aap","ala","alt","ama","anu","e p","e t","eal","eli","haa","hin","iva","kon","ku ","lik","lm ","min","n t","odu","oon","psa","ri ","si ","stu","t e","t s","ti ","ule","uur","vas","vee"," ki"," ni"," nä"," ra","aig","aka","all","atu","e e","eis","ers","i e","ii ","iis","il ","ima","its","kka","kuh","l k","lat","maj","ndu","ni ","nii","oma","ool","rso","ru ","rva","s t","sek","son","ste","t m","taj","tam","ude","uho","vai"," ag"," os"," pa"," re");
+$GLOBALS["ngrams"]['eu'] = array("en ","an ","eta","ta "," et","iza","n e","ko ","ide"," ba","a e","giz"," es"," gi","arr","bid","ren","rri","are","la ","sku"," be","asu","esk","sun","tas"," iz","ean","eko","ela","ik ","kub","n a","n i","tza","ubi","za ","zan"," er","a b","ask","era","n b","rre","ten","tze"," as"," ko","a a","a g","ald","ani","de ","dee","ea ","ek ","kat","kon","n d","ont","uan"," du"," na","ata","egi","est","k e","nik","ntu","ntz","ska","tua"," de"," di"," ez"," he","a d","a k","ak ","aki","ako","art","atu","azi","bat","ber","itz","kun","n h","o b","ria","rte","tat","une","zar"," al"," ar"," ha","aku","atz","bai","dar","dea","del","een","ema","err","iak","iar","in ","ina","kia","nar","naz","nea","o e","orr","ra ","ste","tek","zak","zek","zio"," da"," em"," hi"," ho"," ma"," oi","agu","ate","aur","bes","din","dir","dut","ert","ez ","ezi","har","her","hit","ia ","ien","ika","io ","ire","ite","k b","k g","kid","kor","lda","n o","nko","o a","oin","ori","rak","rea","rie","rik","rra","tan","tea","tu ","una","und","unt","urr","ute","z e","zko"," au"," eg"," gu"," ir"," ki"," or","a h","a j","abe","agi","ai ","ail","ait","ape","ari","dez","e e","ear","eek","erd","ere","eza","ezk","gir","git","hor","i e","ian","iek","ila","ink","int","ira","ita","itu","k n","kap","koa","kum","lan","lde","mai","man","men","n g","n u","na ","nta","o h","oa ","oro","pen","rdi","ri ","rta","sta","tel","tet","tik","tue","tzi","ume","un ","uzt","zea","zen","zia","zin"," az"," bi"," bu"," el"," ga"," jo"," mu"," ti"," un"," za"," zi","a n","a o","a s","a t","a z","aba","adi","ake","ala","and","ar ","aud","bak","bal","beg","beh","bul","dau","den","du ","dui","e b","e d","e h","e o","eak","eet","eha","elk","enb","ete","eti","gab","gin","go ","gus","gut","guz","hau","ibe","inb","ine","ioa","iru","iur","izi","izk","izo");
+$GLOBALS["ngrams"]['fa'] = array("ان ","ای ","ه ا"," اي"," در","به "," بر","در ","ران"," به","ی ا","از ","ين ","می "," از","ده ","ست ","است"," اس"," که","که ","اير","ند ","اين"," ها","يرا","ود "," را","های"," خو","ته ","را ","رای","رد ","ن ب","کرد"," و "," کر","ات ","برا","د ک","مان","ی د"," ان","خوا","شور"," با","ن ا"," سا","تمی","ری ","اتم","ا ا","واه"," ات"," عر","اق ","ر م","راق","عرا","ی ب"," تا"," تو","ار ","ر ا","ن م","ه ب","ور ","يد ","ی ک"," ام"," دا"," کن","اهد","هد "," آن"," می"," ني"," گف","د ا","گفت"," کش","ا ب","نی ","ها ","کشو"," رو","ت ک","نيو","ه م","وی ","ی ت"," شو","ال ","دار","مه ","ن ک","ه د","يه "," ما","امه","د ب","زار","ورا","گزا"," پي","آن ","انت","ت ا","فت ","ه ن","ی خ","اما","بات","ما ","ملل","نام","ير ","ی م","ی ه"," آم"," ای"," من","انس","اني","ت د","رده","ساز","ن د","نه ","ورد"," او"," بي"," سو"," شد","اده","اند","با ","ت ب","ر ب","ز ا","زما","سته","ن ر","ه س","وان","وز ","ی ر","ی س"," هس","ابا","ام ","اور","تخا","خاب","خود","د د","دن ","رها","روز","رگز","نتخ","ه ش","ه ه","هست","يت ","يم "," دو"," دي"," مو"," نو"," هم"," کا","اد ","اری","انی","بر ","بود","ت ه","ح ه","حال","رش ","عه ","لی ","وم ","ژان"," سل","آمر","اح ","توس","داد","دام","ر د","ره ","ريک","زی ","سلا","شود","لاح","مري","نند","ه ع","يما","يکا","پيم","گر "," آژ"," ال"," بو"," مق"," مل"," وی","آژا","ازم","ازی","بار","برن","ر آ","ز س","سعه","شته","مات","ن آ","ن پ","نس ","ه گ","وسع","يان","يوم","کا ","کام","کند"," خا"," سر","آور","ارد","اقد","ايم","ايی","برگ","ت ع","تن ","خت ","د و","ر خ","رک ","زير","فته","قدا","ل ت","مين","ن گ","ه آ","ه خ","ه ک","ورک","ويو","يور","يوي","يی ","ک ت","ی ش"," اق"," حا"," حق"," دس"," شک"," عم"," يک","ا ت","ا د","ارج","بين","ت م","ت و","تاي","دست","ر ح","ر س","رنا","ز ب","شکا","لل ","م ک","مز ","ندا","نوا","و ا","وره","ون ","وند","يمز"," آو"," اع"," فر"," مت"," نه"," هر"," وز"," گز");
+$GLOBALS["ngrams"]['fi'] = array("en ","in ","an ","on ","ist","ta ","ja ","n t","sa ","sta","aan","n p"," on","ssa","tta","tä "," ka"," pa","si "," ja","n k","lla","än ","een","n v","ksi","ett","nen","taa","ttä"," va","ill","itt"," jo"," ko","n s"," tu","ia "," su","a p","aa ","la ","lle","n m","le ","tte","na "," ta"," ve","at "," vi","utt"," sa","ise","sen"," ku"," nä"," pä","ste"," ol","a t","ais","maa","ti ","a o","oit","pää"," pi","a v","ala","ine","isi","tel","tti"," si","a k","all","iin","kin","stä","uom","vii"," ma"," se","enä"," mu","a s","est","iss","llä","lok","lä ","n j","n o","toi","ven","ytt"," li","ain","et ","ina","n a","n n","oll","plo","ten","ust","äll","ään"," to","den","men","oki","suo","sä ","tää","uks","vat"," al"," ke"," te","a e","lii","tai","tei","äis","ää "," pl","ell","i t","ide","ikk","ki ","nta","ova","yst","yt ","ä p","äyt"," ha"," pe"," tä","a n","aik","i p","i v","nyt","näy","pal","tee","un "," me","a m","ess","kau","pai","stu","ut ","voi"," et","a h","eis","hte","i o","iik","ita","jou","mis","nin","nut","sia","ssä","van"," ty"," yh","aks","ime","loi","me ","n e","n h","n l","oin","ome","ott","ouk","sit","sti","tet","tie","ukk","ä k"," ra"," ti","aja","asi","ent","iga","iig","ite","jan","kaa","kse","laa","lan","li ","näj","ole","tii","usi","äjä"," ov","a a","ant","ava","ei ","eri","kan","kku","lai","lis","läi","mat","ois","pel","sil","sty","taj","tav","ttu","työ","yös","ä o"," ai"," pu","a j","a l","aal","arv","ass","ien","imi","imm","itä","ka ","kes","kue","lee","lin","llo","one","ri ","t o","t p","tu ","val","vuo"," ei"," he"," hy"," my"," vo","ali","alo","ano","ast","att","auk","eli","ely","hti","ika","ken","kki","lys","min","myö","oht","oma","tus","umi","yks","ät ","ääl","ös "," ar"," eu"," hu"," na","aat","alk","alu","ans","arj","enn","han","kuu","n y","set","sim");
+$GLOBALS["ngrams"]['fr'] = array("es "," de","de "," le","ent","le ","nt ","la ","s d"," la","ion","on ","re "," pa","e l","e d"," l'","e p"," co"," pr","tio","ns "," en","ne ","que","r l","les","ur ","en ","ati","ue "," po"," d'","par"," a ","et ","it "," qu","men","ons","te "," et","t d"," re","des"," un","ie ","s l"," su","pou"," au"," à ","con","er "," no","ait","e c","se ","té ","du "," du"," dé","ce ","e e","is ","n d","s a"," so","e r","e s","our","res","ssi","eur"," se","eme","est","us ","sur","ant","iqu","s p","une","uss","l'a","pro","ter","tre","end","rs "," ce","e a","t p","un "," ma"," ru"," ré","ous","ris","rus","sse","ans","ar ","com","e m","ire","nce","nte","t l"," av"," mo"," te","il ","me ","ont","ten","a p","dan","pas","qui","s e","s s"," in","ist","lle","nou","pré","'un","air","d'a","ir ","n e","rop","ts "," da","a s","as ","au ","den","mai","mis","ori","out","rme","sio","tte","ux ","a d","ien","n a","ntr","omm","ort","ouv","s c","son","tes","ver","ère"," il"," m "," sa"," ve","a r","ais","ava","di ","n p","sti","ven"," mi","ain","enc","for","ité","lar","oir","rem","ren","rro","rés","sie","t a","tur"," pe"," to","d'u","ell","err","ers","ide","ine","iss","mes","por","ran","sit","st ","t r","uti","vai","é l","ési"," di"," n'"," ét","a c","ass","e t","in ","nde","pre","rat","s m","ste","tai","tch","ui ","uro","ès "," es"," fo"," tr","'ad","app","aux","e à","ett","iti","lit","nal","opé","r d","ra ","rai","ror","s r","tat","uté","à l"," af","anc","ara","art","bre","ché","dre","e f","ens","lem","n r","n t","ndr","nne","onn","pos","s t","tiq","ure"," tu","ale","and","ave","cla","cou","e n","emb","ins","jou","mme","rie","rès","sem","str","t i","ues","uni","uve","é d","ée "," ch"," do"," eu"," fa"," lo"," ne"," ra","arl","att","ec ","ica","l a","l'o","l'é","mmi","nta","orm","ou ","r u","rle");
+$GLOBALS["ngrams"]['ha'] = array(" da","da ","in ","an ","ya "," wa"," ya","na ","ar ","a d"," ma","wa ","a a","a k","a s"," ta","wan"," a "," ba"," ka","ta ","a y","n d"," ha"," na"," su"," sa","kin","sa ","ata"," ko","a t","su "," ga","ai "," sh","a m","uwa","iya","ma ","a w","asa","yan","ka ","ani","shi","a b","a h","a c","ama","ba ","nan","n a"," mu","ana"," yi","a g"," za","i d"," ku","aka","yi ","n k","ann","ke ","tar"," ci","iki","n s","ko "," ra","ki ","ne ","a z","mat","hak","nin","e d","nna","uma","nda","a n","ada","cik","ni ","rin","una","ara","kum","akk"," ce"," du","man","n y","nci","sar","aki","awa","ci ","kan","kar","ari","n m","and","hi ","n t","ga ","owa","ash","kam","dan","ewa","nsa","ali","ami"," ab"," do","anc","n r","aya","i n","sun","uka"," al"," ne","a'a","cew","cin","mas","tak","un ","aba","kow","a r","ra "," ja"," ƙa","en ","r d","sam","tsa"," ru","ce ","i a","abi","ida","mut","n g","n j","san","a ƙ","har","on ","i m","suk"," ak"," ji","yar","'ya","kwa","min"," 'y","ane","ban","ins","ruw","i k","n h"," ad","ake","n w","sha","utu"," ƴa","bay","tan","ƴan","bin","duk","e m","n n","oka","yin","ɗan"," fa","a i","kki","re ","za ","ala","asu","han","i y","mar","ran","ƙas","add","ars","gab","ira","mma","u d"," ts","abb","abu","aga","gar","n b"," ɗa","aci","aik","am ","dun","e s","i b","i w","kas","kok","wam"," am","amf","bba","din","fan","gwa","i s","wat","ano","are","dai","iri","ma'"," la","all","dam","ika","mi ","she","tum","uni"," an"," ai"," ke"," ki","dag","mai","mfa","no ","nsu","o d","sak","um "," bi"," gw"," kw","jam","yya","a j","fa ","uta"," hu","'a ","ans","aɗa","dda","hin","niy","r s","bat","dar","gan","i t","nta","oki","omi","sal","a l","kac","lla","wad","war","amm","dom","r m","ras","sai"," lo","ats","hal","kat","li ","lok","n c","nar","tin","afa","bub","i g","isa","mak");
+$GLOBALS["ngrams"]['haw'] = array(" ka","na "," o ","ka "," ma"," a "," la","a i","a m"," i ","la ","ana","ai ","ia ","a o","a k","a h","o k"," ke","a a","i k"," ho"," ia","ua "," na"," me","e k","e a","au ","ke ","ma ","mai","aku"," ak","ahi"," ha"," ko"," e ","a l"," no","me ","ku ","aka","kan","no ","i a","ho ","ou "," ai","i o","a p","o l","o a","ama","a n"," an","i m","han","i i","iho","kou","ne "," ih","o i","iki","ona","hoo","le ","e h"," he","ina"," wa","ea ","ako","u i","kah","oe ","i l","u a"," pa","hoi","e i","era","ko ","u m","kua","mak","oi ","kai","i n","a e","hin","ane"," ol","i h","mea","wah","lak","e m","o n","u l","ika","ki ","a w","mal","hi ","e n","u o","hik"," ku","e l","ele","ra ","ber","ine","abe","ain","ala","lo "," po","kon"," ab","ole","he ","pau","mah","va ","ela","kau","nak"," oe","kei","oia"," ie","ram"," oi","oa ","eho","hov","ieh","ova"," ua","una","ara","o s","awa","o o","nau","u n","wa ","wai","hel"," ae"," al","ae ","ta ","aik"," hi","ale","ila","lel","ali","eik","olo","onu"," lo","aua","e o","ola","hon","mam","nan"," au","aha","lau","nua","oho","oma"," ao","ii ","alu","ima","mau","ike","apa","elo","lii","poe","aia","noa"," in","o m","oka","'u ","aho","ei ","eka","ha ","lu ","nei","hol","ino","o e","ema","iwa","olu","ada","naa","pa ","u k","ewa","hua","lam","lua","o h","ook","u h"," li","ahu","amu","ui "," il"," mo"," se","eia","law"," hu"," ik","ail","e p","li ","lun","uli","io ","kik","noh","u e"," sa","aaw","awe","ena","hal","kol","lan"," le"," ne","a'u","ilo","kap","oko","sa "," pe","hop","loa","ope","pe "," ad"," pu","ahe","aol","ia'","lai","loh","na'","oom","aau","eri","kul","we ","ake","kek","laa","ri ","iku","kak","lim","nah","ner","nui","ono","a u","dam","kum","lok","mua","uma","wal","wi ","'i ","a'i","aan","alo","eta","mu ","ohe","u p","ula","uwa"," nu","amo");
+$GLOBALS["ngrams"]['hi'] = array("ें "," है","में"," मे","ने ","की ","के ","है "," के"," की"," को","ों ","को ","ा ह"," का","से ","ा क","े क","ं क","या "," कि"," से","का ","ी क"," ने"," और","और ","ना ","कि ","भी ","ी स"," जा"," पर","ार "," कर","ी ह"," हो","ही ","िया"," इस"," रह","र क","ुना","ता ","ान ","े स"," भी"," रा","े ह"," चु"," पा","पर ","चुन","नाव"," कह","प्र"," भा","राज","हैं","ा स","ै क","ैं ","नी ","ल क","ीं ","़ी ","था ","री ","ाव ","े ब"," प्","क्ष","पा ","ले "," दे","ला ","हा ","ाजप"," था"," नह","इस ","कर ","जपा","नही","भाज","यों","र स","हीं"," अम"," बा"," मा"," वि","रीक","िए ","े प","्या"," ही","ं म","कार","ा ज","े ल"," ता"," दि"," सा"," हम","ा न","ा म","ाक़","्ता"," एक"," सं"," स्","अमर","क़ी","ताज","मरी","स्थ","ा थ","ार्"," हु","इरा","एक ","न क","र म","राक","ी ज","ी न"," इर"," उन"," पह","कहा","ते ","े अ"," तो"," सु","ति ","ती ","तो ","मिल","िक ","ियो","्रे"," अप"," फ़"," लि"," लो"," सम","म क","र्ट","हो ","ा च","ाई ","ाने","िन ","्य "," उस"," क़"," सक"," सै","ं प","ं ह","गी ","त क","मान","र न","ष्ट","स क","स्त","ाँ ","ी ब","ी म","्री"," दो"," मि"," मु"," ले"," शा","ं स","ज़ा","त्र","थी ","लिए","सी ","़ा ","़ार","ांग","े द","े म","्व "," ना"," बन","ंग्","कां","गा ","ग्र","जा ","ज्य","दी ","न म","पार","भा ","रही","रे ","रेस","ली ","सभा","ा र","ाल ","ी अ","ीकी","े त","ेश "," अं"," तक"," या","ई ह","करन","तक ","देश","वर्","ाया","ी भ","ेस ","्ष "," गय"," जि"," थी"," बड"," यह"," वा","ंतर","अंत","क़ ","गया","टी ","निक","न्ह","पहल","बड़","मार","र प","रने","ाज़","ि इ","ी र","े ज","े व","्ट ","्टी"," अब"," लग"," वर"," सी","ं भ","उन्","क क","किय","देख","पूर","फ़्","यह ","यान","रिक","रिय","र्ड","लेक","सकत","हों","होग","ा अ","ा द","ा प","ाद ","ारा","ित ","ी त","ी प","ो क","ो द"," ते"," नि"," सर"," हा","ं द","अपन","जान","त म","थित","पनी","महल","र ह","लोग","व क","हना","हल ","हाँ","ाज्","ाना","िक्","िस्");
+$GLOBALS["ngrams"]['hr'] = array("je "," na"," pr"," po","na "," je"," za","ije","ne "," i ","ti ","da "," ko"," ne","li "," bi"," da"," u ","ma ","mo ","a n","ih ","za ","a s","ko ","i s","a p","koj","pro","ju ","se "," go","ost","to ","va "," do"," to","e n","i p"," od"," ra","no ","ako","ka ","ni "," ka"," se"," mo"," st","i n","ima","ja ","pri","vat","sta"," su","ati","e p","ta ","tsk","e i","nij"," tr","cij","jen","nos","o s"," iz","om ","tro","ili","iti","pos"," al","a i","a o","e s","ija","ini","pre","str","la ","og ","ovo"," sv","ekt","nje","o p","odi","rva"," ni","ali","min","rij","a t","a z","ats","iva","o t","od ","oje","ra "," hr","a m","a u","hrv","im ","ke ","o i","ovi","red","riv","te ","bi ","e o","god","i d","lek","umi","zvo","din","e u","ene","jed","ji ","lje","nog","su "," a "," el"," mi"," o ","a d","alu","ele","i u","izv","ktr","lum","o d","ori","rad","sto","a k","anj","ava","e k","men","nic","o j","oj ","ove","ski","tvr","una","vor"," di"," no"," s "," ta"," tv","i i","i o","kak","roš","sko","vod"," sa"," će","a b","adi","amo","eni","gov","iju","ku ","o n","ora","rav","ruj","smo","tav","tru","u p","ve "," in"," pl","aci","bit","de ","diš","ema","i m","ika","išt","jer","ki ","mog","nik","nov","nu ","oji","oli","pla","pod","st ","sti","tra","tre","vo "," sm"," št","dan","e z","i t","io ","ist","kon","lo ","stv","u s","uje","ust","će ","ći ","što"," dr"," im"," li","ada","aft","ani","ao ","ars","ata","e t","emo","i k","ine","jem","kov","lik","lji","mje","naf","ner","nih","nja","ogo","oiz","ome","pot","ran","ri ","roi","rtk","ska","ter","u i","u o","vi ","vrt"," me"," ug","ak ","ama","drž","e e","e g","e m","em ","eme","enj","ent","er ","ere","erg","eur","go ","i b","i z","jet","ksi","o u","oda","ona","pra","reb","rem","rop","tri","žav"," ci"," eu"," re"," te"," uv"," ve","aju","an ");
+$GLOBALS["ngrams"]['hu'] = array(" a "," az"," sz","az "," me","en "," el"," ho","ek ","gy ","tt ","ett","sze"," fe","és "," ki","tet"," be","et ","ter"," kö"," és","hog","meg","ogy","szt","te ","t a","zet","a m","nek","nt ","ség","szá","ak "," va","an ","eze","ra ","ta "," mi","int","köz"," is","esz","fel","min","nak","ors","zer"," te","a a","a k","is "," cs","ele","er ","men","si ","tek","ti "," ne","csa","ent","z e","a t","ala","ere","es ","lom","lte","mon","ond","rsz","sza","tte","zág","ány"," fo"," ma","ai ","ben","el ","ene","ik ","jel","tás","áll"," ha"," le"," ál","agy","alá","isz","y a","zte","ás "," al","e a","egy","ely","for","lat","lt ","n a","oga","on ","re ","st ","ság","t m","án ","ét ","ült"," je","gi ","k a","kül","lam","len","lás","más","s k","vez","áso","özö"," ta","a s","a v","asz","atá","ető","kez","let","mag","nem","szé","z m","át ","éte","ölt"," de"," gy"," ké"," mo"," vá"," ér","a b","a f","ami","at ","ato","att","bef","dta","gya","hat","i s","las","ndt","rt ","szo","t k","tár","tés","van","ásá","ól "," bé"," eg"," or"," pá"," pé"," ve","ban","eke","ekü","elő","erv","ete","fog","i a","kis","lád","nte","nye","nyi","ok ","omá","os ","rán","rás","sal","t e","vál","yar","ágo","ála","ége","ény","ött"," tá","adó","elh","fej","het","hoz","ill","jár","kés","llo","mi ","ny ","ont","ren","res","rin","s a","s e","ssz","zt "," ez"," ka"," ke"," ko"," re","a h","a n","den","dó ","efo","gad","gat","gye","hel","k e","ket","les","mán","nde","nis","ozz","t b","t i","t é","tat","tos","val","z o","zak","ád ","ály","ára","ési","ész"," ak"," am"," es"," há"," ny"," tö","aka","art","ató","azt","bbe","ber","ció","cso","em ","eti","eté","gal","i t","ini","ist","ja ","ker","ki ","kor","koz","l é","ljá","lye","n v","ni ","pál","ror","ról","rül","s c","s p","s s","s v","sok","t j","t t","tar","tel","vat");
+$GLOBALS["ngrams"]['id'] = array("an "," me","kan","ang","ng "," pe","men"," di"," ke"," da"," se","eng"," be","nga","nya"," te","ah ","ber","aka"," ya","dan","di ","yan","n p","per","a m","ita"," pa","da ","ata","ada","ya ","ta "," in","ala","eri","ia ","a d","n k","am ","ga ","at ","era","n d","ter"," ka","a p","ari","emb","n m","ri "," ba","aan","ak ","ra "," it","ara","ela","ni ","ali","ran","ar ","eru","lah","a b","asi","awa","eba","gan","n b"," ha","ini","mer"," la"," mi","and","ena","wan"," sa","aha","lam","n i","nda"," wa","a i","dua","g m","mi ","n a","rus","tel","yak"," an","dal","h d","i s","ing","min","ngg","tak","ami","beb","den","gat","ian","ih ","pad","rga","san","ua "," de","a t","arg","dar","elu","har","i k","i m","i p","ika","in ","iny","itu","mba","n t","ntu","pan","pen","sah","tan","tu ","a k","ban","edu","eka","g d","ka ","ker","nde","nta","ora","usa"," du"," ma","a s","ai ","ant","bas","end","i d","ira","kam","lan","n s","uli","al ","apa","ere","ert","lia","mem","rka","si ","tal","ung"," ak","a a","a w","ani","ask","ent","gar","haa","i i","isa","ked","mbe","ska","tor","uan","uk ","uka"," ad"," to","asa","aya","bag","dia","dun","erj","mas","na ","rek","rit","sih","us "," bi","a h","ama","dib","ers","g s","han","ik ","kem","ma ","n l","nit","r b","rja","sa "," ju"," or"," si"," ti","a y","aga","any","as ","cul","eme","emu","eny","epa","erb","erl","gi ","h m","i a","kel","li ","mel","nia","opa","rta","sia","tah","ula","un ","unt"," at"," bu"," pu"," ta","agi","alu","amb","bah","bis","er ","i t","ibe","ir ","ja ","k m","kar","lai","lal","lu ","mpa","ngk","nja","or ","pa ","pas","pem","rak","rik","seb","tam","tem","top","tuk","uni","war"," al"," ga"," ge"," ir"," ja"," mu"," na"," pr"," su"," un","ad ","adi","akt","ann","apo","bel","bul","der","ega","eke","ema","emp","ene","enj","esa");
+$GLOBALS["ngrams"]['is'] = array("að ","um "," að","ir ","ið ","ur "," ve"," í ","na "," á "," se"," er"," og","ar ","og ","ver"," mi","inn","nn "," fy","er ","fyr"," ek"," en"," ha"," he","ekk"," st","ki ","st ","ði "," ba"," me"," vi","ig ","rir","yri"," um","g f","leg","lei","ns ","ð s"," ei"," þa","in ","kki","r h","r s","egi","ein","ga ","ing","ra ","sta"," va"," þe","ann","en ","mil","sem","tjó","arð","di ","eit","haf","ill","ins","ist","llj","ndi","r a","r e","seg","un ","var"," bi"," el"," fo"," ge"," yf","and","aug","bau","big","ega","eld","erð","fir","foo","gin","itt","n s","ngi","num","od ","ood","sin","ta ","tt ","við","yfi","ð e","ð f"," hr"," sé"," þv","a e","a á","em ","gi ","i f","jar","jór","lja","m e","r á","rei","rst","rða","rði","rðu","stj","und","veg","ví ","ð v","það","því"," fj"," ko"," sl","eik","end","ert","ess","fjá","fur","gir","hús","jár","n e","ri ","tar","ð þ","ðar","ður","þes"," br"," hú"," kr"," le"," up","a s","egg","i s","irt","ja ","kið","len","með","mik","n b","nar","nir","nun","r f","r v","rið","rt ","sti","t v","ti ","una","upp","ða ","óna"," al"," fr"," gr","a v","all","an ","da ","eið","eð ","fa ","fra","g e","ger","gið","gt ","han","hef","hel","her","hra","i a","i e","i v","i þ","iki","jón","jör","ka ","kró","lík","m h","n a","nga","r l","ram","ru ","ráð","rón","svo","vin","í b","í h","ð h","ð k","ð m","örð"," af"," fa"," lí"," rá"," sk"," sv"," te","a b","a f","a h","a k","a u","afi","agn","arn","ast","ber","efu","enn","erb","erg","fi ","g a","gar","iðs","ker","kke","lan","ljó","llt","ma ","mið","n v","n í","nan","nda","ndu","nið","nna","nnu","nu ","r o","rbe","rgi","slö","sé ","t a","t h","til","tin","ugu","vil","ygg","á s","ð a","ð b","órn","ögn","öku"," at"," fi"," fé"," ka"," ma"," no"," sa"," si"," ti"," ák","a m","a t","a í","a þ","afa","afs","ald","arf");
+$GLOBALS["ngrams"]['it'] = array(" di","to ","la "," de","di ","no "," co","re ","ion","e d"," e ","le ","del","ne ","ti ","ell"," la"," un","ni ","i d","per"," pe","ent"," in","one","he ","ta ","zio","che","o d","a d","na ","ato","e s"," so","i s","lla","a p","li ","te "," al"," ch","er "," pa"," si","con","sta"," pr","a c"," se","el ","ia ","si ","e p"," da","e i","i p","ont","ano","i c","all","azi","nte","on ","nti","o s"," ri","i a","o a","un "," an","are","ari","e a","i e","ita","men","ri "," ca"," il"," no"," po","a s","ant","il ","in ","a l","ati","cia","e c","ro ","ann","est","gli","tà "," qu","e l","nta"," a ","com","o c","ra "," le"," ne","ali","ere","ist"," ma"," è ","io ","lle","me ","era","ica","ost","pro","tar","una"," pi","da ","tat"," mi","att","ca ","mo ","non","par","sti"," fa"," i "," re"," su","ess","ini","nto","o l","ssi","tto","a e","ame","col","ei ","ma ","o i","za "," st","a a","ale","anc","ani","i m","ian","o p","oni","sio","tan","tti"," lo","i r","oci","oli","ona","ono","tra"," l ","a r","eri","ett","lo ","nza","que","str","ter","tta"," ba"," li"," te","ass","e f","enz","for","nno","olo","ori","res","tor"," ci"," vo","a i","al ","chi","e n","lia","pre","ria","uni","ver"," sp","imo","l a","l c","ran","sen","soc","tic"," fi"," mo","a n","ce ","dei","ggi","gio","iti","l s","lit","ll ","mon","ola","pac","sim","tit","utt","vol"," ar"," fo"," ha"," sa","acc","e r","ire","man","ntr","rat","sco","tro","tut","va "," do"," gi"," me"," sc"," tu"," ve"," vi","a m","ber","can","cit","i l","ier","ità","lli","min","n p","nat","nda","o e","o f","o u","ore","oro","ort","sto","ten","tiv","van","art","cco","ci ","cos","dal","e v","i i","ila","ino","l p","n c","nit","ole","ome","po ","rio","sa "," ce"," es"," tr","a b","and","ata","der","ens","ers","gi ","ial","ina","itt","izi","lan","lor","mil");
+$GLOBALS["ngrams"]['kk'] = array("ан ","ен ","ың "," қа"," ба","ай ","нда","ын "," са"," ал","ді ","ары","ды ","ып "," мұ"," бі","асы","да ","най"," жа","мұн","ста","ған","н б","ұна"," бо","ның","ін ","лар","сын"," де","аға","тан"," кө","бір","ер ","мен","аза","ынд","ыны"," ме","анд","ері","бол","дың","қаз","аты","сы ","тын","ғы "," ке","ар ","зақ","ық ","ала","алы","аны","ара","ағы","ген","тар","тер","тыр","айд","ард","де ","ға "," қо","бар","ің ","қан"," бе"," қы","ақс","гер","дан","дар","лық","лға","ына","ір ","ірі","ғас"," та","а б","гі ","еді","еле","йды","н к","н т","ола","рын","іп ","қст","қта","ң б"," ай"," ол"," со","айт","дағ","иге","лер","лып","н а","ік ","ақт","бағ","кен","н қ","ны ","рге","рға","ыр "," ар","алғ","аса","бас","бер","ге ","еті","на ","нде","не ","ниг","рды","ры ","сай"," ау"," кү"," ни"," от"," өз","ауд","еп ","иял","лты","н ж","н о","осы","оты","рып","рі ","тке","ты ","ы б","ы ж","ылы","ысы","і с","қар"," бұ"," да"," же"," тұ"," құ","ады","айл","ап ","ата","ені","йла","н м","н с","нды","нді","р м","тай","тін","ы т","ыс ","інд"," би","а ж","ауы","деп","дің","еке","ери","йын","кел","лды","ма ","нан","оны","п ж","п о","р б","рия","рла","уда","шыл","ы а","ықт","і а","і б","із ","ілі","ң қ"," ас"," ек"," жо"," мә"," ос"," ре"," се","алд","дал","дег","дей","е б","ет ","жас","й б","лау","лда","мет","нын","сар","сі ","ті ","ыры","ыта","ісі","ң а","өте"," ат"," ел"," жү"," ма"," то"," шы","а а","алт","ама","арл","аст","бұл","дай","дық","ек ","ель","есі","зді","көт","лем","ль ","н е","п а","р а","рес","са ","та ","тте","тұр","шы ","ы д","ы қ","ыз ","қыт"," ко"," не"," ой"," ор"," сұ"," тү","аль","аре","атт","дір","ев ","егі","еда","екі","елд","ерг","ерд","ияд","кер","кет","лыс","ліс","мед","мпи","н д","ні ","нін","п т","пек","рел","рта","ріл","рін","сен","тал","шіл","ы к","ы м","ыст");
+$GLOBALS["ngrams"]['ky'] = array("ын ","ан "," жа","ен ","да "," та","ар ","ин "," ка","ары"," ал"," ба"," би","лар"," бо"," кы","ала","н к"," са","нда","ган","тар"," де","анд","н б"," ке","ард","мен","н т","ара","нын"," да"," ме","кыр"," че","н а","ры "," ко","ген","дар","кен","кта","уу ","ене","ери"," ша","алы","ат ","на "," кө"," эм","аты","дан","деп","дын","еп ","нен","рын"," бе","кан","луу","ргы","тан","шай","ырг","үн "," ар"," ма","агы","акт","аны","гы ","гыз","ды ","рда","ай ","бир","бол","ер ","н с","нды","ун ","ча ","ынд","а к","ага","айл","ана","ап ","га ","лге","нча","п к","рды","туу","ыны"," ан"," өз","ама","ата","дин","йт ","лга","лоо","оо ","ри ","тин","ыз ","ып ","өрү"," па"," эк","а б","алг","асы","ашт","биз","кел","кте","тал"," не"," су","акы","ент","инд","ир ","кал","н д","нде","ого","онд","оюн","р б","р м","ран","сал","ста","сы ","ура","ыгы"," аш"," ми"," сы"," ту","ал ","арт","бор","елг","ени","ет ","жат","йло","кар","н м","огу","п а","п ж","р э","сын","ык ","юнч"," бу"," ур","а а","ак ","алд","алу","бар","бер","бою","ге ","дон","еги","ект","ефт","из ","кат","лды","н ч","н э","н ө","ндо","неф","он ","сат","тор","ты ","уда","ул ","ула","ууд","ы б","ы ж","ы к","ыл ","ына","эке","ясы"," ат"," до"," жы"," со"," чы","аас","айт","аст","баа","баш","гар","гын","дө ","е б","ек ","жыл","и б","ик ","ияс","кыз","лда","лык","мда","н ж","нди","ни ","нин","орд","рдо","сто","та ","тер","тти","тур","тын","уп ","ушу","фти","ыкт","үп ","өн "," ай"," бү"," ич"," иш"," мо"," пр"," ре"," өк"," өт","а д","а у","а э","айм","амд","атт","бек","бул","гол","дег","еге","ейт","еле","енд","жак","и к","ини","ири","йма","кто","лик","мак","мес","н у","н ш","нтт","ол ","оло","пар","рак","рүү","сыр","ти ","тик","тта","төр","у ж","у с","шка","ы м","ызы","ылд","эме","үрү","өлү","өтө"," же"," тү"," эл"," өн","а ж","ады");
+$GLOBALS["ngrams"]['la'] = array("um ","us ","ut ","et ","is "," et"," in"," qu","tur"," pr","est","tio"," au","am ","em ","aut"," di","ent","in ","dic","t e"," es","ur ","ati","ion","st "," ut","ae ","qua"," de","nt "," su"," si","itu","unt","rum","ia ","es ","ter"," re","nti","rae","s e","qui","io ","pro","it ","per","ita","one","ici","ius"," co","t d","bus","pra","m e"," no","edi","tia","ue ","ibu"," se"," ad","er "," fi","ili","que","t i","de ","oru"," te","ali"," pe","aed","cit","m d","t s","tat","tem","tis","t p","sti","te ","cum","ere","ium"," ex","rat","ta ","con","cti","oni","ra ","s i"," cu"," sa","eni","nis","nte","eri","omi","re ","s a","min","os ","ti ","uer"," ma"," ue","m s","nem","t m"," mo"," po"," ui","gen","ict","m i","ris","s s","t a","uae"," do","m a","t c"," ge","as ","e i","e p","ne "," ca","ine","quo","s p"," al","e e","ntu","ro ","tri","tus","uit","atu","ini","iqu","m p","ost","res","ura"," ac"," fu","a e","ant","nes","nim","sun","tra","e a","s d"," pa"," uo","ecu"," om"," tu","ad ","cut","omn","s q"," ei","ex ","icu","tor","uid"," ip"," me","e s","era","eru","iam","ide","ips"," iu","a s","do ","e d","eiu","ica","im ","m c","m u","tiu"," ho","cat","ist","nat","on ","pti","reg","rit","s t","sic","spe"," en"," sp","dis","eli","liq","lis","men","mus","num","pos","sio"," an"," gr","abi","acc","ect","ri ","uan"," le","ecc","ete","gra","non","se ","uen","uis"," fa"," tr","ate","e c","fil","na ","ni ","pul","s f","ui ","at ","cce","dam","i e","ina","leg","nos","ori","pec","rop","sta","uia","ene","iue","iui","siu","t t","t u","tib","tit"," da"," ne","a d","and","ege","equ","hom","imu","lor","m m","mni","ndo","ner","o e","r e","sit","tum","utu","a p","bis","bit","cer","cta","dom","fut","i s","ign","int","mod","ndu","nit","rib","rti","tas","und"," ab","err","ers","ite","iti","m t","o p");
+$GLOBALS["ngrams"]['lt'] = array("as "," pa"," ka","ai ","us ","os ","is "," ne"," ir","ir ","ti "," pr","aus","ini","s p","pas","ių "," ta"," vi","iau"," ko"," su","kai","o p","usi"," sa","vo ","tai","ali","tų ","io ","jo ","s k","sta","iai"," bu"," nu","ius","mo "," po","ien","s s","tas"," me","uvo","kad"," iš"," la","to ","ais","ie ","kur","uri"," ku","ijo","čia","au ","met","je "," va","ad "," ap","and"," gr"," ti","kal","asi","i p","iči","s i","s v","ink","o n","ės ","buv","s a"," ga","aip","avi","mas","pri","tik"," re","etu","jos"," da","ent","oli","par","ant","ara","tar","ama","gal","imo","išk","o s"," at"," be"," į ","min","tin"," tu","s n"," jo","dar","ip ","rei"," te","dži","kas","nin","tei","vie"," li"," se","cij","gar","lai","art","lau","ras","no ","o k","tą "," ar","ėjo","vič","iga","pra","vis"," na","men","oki","raš","s t","iet","ika","int","kom","tam","aug","avo","rie","s b"," st","eim","ko ","nus","pol","ria","sau","api","me ","ne ","sik"," ši","i n","ia ","ici","oja","sak","sti","ui ","ame","lie","o t","pie","čiu"," di"," pe","gri","ios","lia","lin","s d","s g","ta ","uot"," ja"," už","aut","i s","ino","mą ","oje","rav","dėl","nti","o a","toj","ėl "," to"," vy","ar ","ina","lic","o v","sei","su "," mi"," pi","din","iš ","lan","si ","tus"," ba","asa","ata","kla","omi","tat"," an"," ji","als","ena","jų ","nuo","per","rig","s m","val","yta","čio"," ra","i k","lik","net","nė ","tis","tuo","yti","ęs ","ų s","ada","ari","do ","eik","eis","ist","lst","ma ","nes","sav","sio","tau"," ki","aik","aud","ies","ori","s r","ska"," ge","ast","eig","et ","iam","isa","mis","nam","ome","žia","aba","aul","ikr","ką ","nta","ra ","tur"," ma","die","ei ","i t","nas","rin","sto","tie","tuv","vos","ų p"," dė","are","ats","enė","ili","ima","kar","ms ","nia","r p","rod","s l"," o ","e p","es ","ide","ik ","ja ");
+$GLOBALS["ngrams"]['lv'] = array("as "," la"," pa"," ne","es "," un","un "," ka"," va","ar ","s p"," ar"," vi","is ","ai "," no","ja ","ija","iem","em ","tu ","tie","vie","lat","aks","ien","kst","ies","s a","rak","atv","tvi"," ja"," pi","ka "," ir","ir ","ta "," sa","ts "," kā","ās "," ti","ot ","s n"," ie"," ta","arī","par","pie"," pr","kā "," at"," ra","am ","inā","tā "," iz","jas","lai"," na","aut","ieš","s s"," ap"," ko"," st","iek","iet","jau","us ","rī ","tik","ība","na "," ga","cij","s i"," uz","jum","s v","ms ","var"," ku"," ma","jā ","sta","s u"," tā","die","kai","kas","ska"," ci"," da","kur","lie","tas","a p","est","stā","šan","nes","nie","s d","s m","val"," di"," es"," re","no ","to ","umu","vai","ši "," vē","kum","nu ","rie","s t","ām ","ad ","et ","mu ","s l"," be","aud","tur","vij","viņ","āju","bas","gad","i n","ika","os ","a v","not","oti","sts","aik","u a","ā a","āk "," to","ied","stu","ti ","u p","vēl","āci"," šo","gi ","ko ","pro","s r","tāj","u s","u v","vis","aun","ks ","str","zin","a a","adī","da ","dar","ena","ici","kra","nas","stī","šu "," mē","a n","eci","i s","ie ","iņa","ju ","las","r t","ums","šie","bu ","cit","i a","ina","ma ","pus","ra "," au"," se"," sl","a s","ais","eši","iec","iku","pār","s b","s k","sot","ādā"," in"," li"," tr","ana","eso","ikr","man","ne ","u k"," tu","an ","av ","bet","būt","im ","isk","līd","nav","ras","ri ","s g","sti","īdz"," ai","arb","cin","das","ent","gal","i p","lik","mā ","nek","pat","rēt","si ","tra","uši","vei"," br"," pu"," sk","als","ama","edz","eka","ešu","ieg","jis","kam","lst","nāk","oli","pre","pēc","rot","tās","usi","ēl ","ēs "," bi"," de"," me"," pā","a i","aid","ajā","ikt","kat","lic","lod","mi ","ni ","pri","rād","rīg","sim","trā","u l","uto","uz ","ēc ","ītā"," ce"," jā"," sv","a t","aga","aiz","atu","ba ","cie","du ","dzi","dzī");
+$GLOBALS["ngrams"]['mk'] = array("на "," на","та ","ата","ија"," пр","то ","ја "," за","а н"," и ","а с","те ","ите"," ко","от "," де"," по","а д","во ","за "," во"," од"," се"," не","се "," до","а в","ка ","ање","а п","о п","ува","циј","а о","ици","ето","о н","ани","ни "," вл","дек","ека","њет","ќе "," е ","а з","а и","ат ","вла","го ","е н","од ","пре"," го"," да"," ма"," ре"," ќе","али","и д","и н","иот","нат","ово"," па"," ра"," со","ове","пра","што","ње ","а е","да ","дат","дон","е в","е д","е з","е с","кон","нит","но ","они","ото","пар","при","ста","т н"," шт","а к","аци","ва ","вањ","е п","ени","ла ","лад","мак","нес","нос","про","рен","јат"," ин"," ме"," то","а г","а м","а р","аке","ако","вор","гов","едо","ена","и и","ира","кед","не ","ниц","ниј","ост","ра ","рат","ред","ска","тен"," ка"," сп"," ја","а т","аде","арт","е г","е и","кат","лас","нио","о с","ри "," ба"," би","ава","ате","вни","д н","ден","дов","држ","дув","е о","ен ","ере","ери","и п","и с","ина","кој","нци","о м","о о","одн","пор","ски","спо","ств","сти","тво","ти "," об"," ов","а б","алн","ара","бар","е к","ед ","ент","еѓу","и о","ии ","меѓ","о д","оја","пот","раз","раш","спр","сто","т д","ци "," бе"," гр"," др"," из"," ст","аа ","бид","вед","гла","еко","енд","есе","етс","зац","и т","иза","инс","ист","ки ","ков","кол","ку ","лиц","о з","о и","ова","олк","оре","ори","под","рањ","реф","ржа","ров","рти","со ","тор","фер","цен","цит"," а "," вр"," гл"," дп"," мо"," ни"," но"," оп"," от","а ќ","або","ада","аса","аша","ба ","бот","ваа","ват","вот","ги ","гра","де ","дин","дум","евр","еду","ено","ера","ес ","ење","же ","зак","и в","ила","иту","коа","кои","лан","лку","лож","мот","нду","нст","о в","оа ","оал","обр","ов ","ови","овн","ои ","ор ","орм","ој ","рет","сед","ст ","тер","тиј","тоа","фор","ции","ѓу "," ал"," ве"," вм"," ги"," ду");
+$GLOBALS["ngrams"]['mn'] = array("ын "," ба","йн ","бай","ийн","уул"," ул","улс","ан "," ха","ний","н х","гаа","сын","ий ","лсы"," бо","й б","эн ","ах ","бол","ол ","н б","оло"," хэ","онг","гол","гуу","нго","ыг ","жил"," мо","лаг","лла","мон"," тє"," ху","айд","ны ","он ","сан","хий"," аж"," ор","л у","н т","улг","айг","длы","йг "," за","дэс","н а","ндэ","ула","ээ ","ага","ийг","vй ","аа ","й а","лын","н з"," аю"," зє","аар","ад ","ар ","гvй","зєв","ажи","ал ","аюу","г х","лгv","лж ","сни","эсн","юул","йдл","лыг","нхи","ууд","хам"," нэ"," са","гий","лах","лєл","рєн","єгч"," та","илл","лий","лэх","рий","эх "," ер"," эр","влє","ерє","ийл","лон","лєг","євл","єнх"," хо","ари","их ","хан","эр ","єн ","vvл","ж б","тэй","х х","эрх"," vн"," нь","vнд","алт","йлє","нь ","тєр"," га"," су","аан","даа","илц","йгу","л а","лаа","н н","руу","эй "," то","н с","рил","єри","ааг","гч ","лээ","н о","рэг","суу","эрэ","їїл"," yн"," бу"," дэ"," ол"," ту"," ши","yнд","аши","г т","иг ","йл ","хар","шин","эг ","єр "," их"," хє"," хї","ам ","анг","ин ","йга","лса","н v","н е","нал","нд ","хуу","цаа","эд ","ээр","єл ","vйл","ада","айн","ала","амт","гах","д х","дал","зар","л б","лан","н д","сэн","улл","х б","хэр"," бv"," да"," зо","vрэ","аад","гээ","лэн","н и","н э","нга","нэ ","тал","тын","хур","эл "," на"," ни"," он","vлэ","аг ","аж ","ай ","ата","бар","г б","гад","гїй","й х","лт ","н м","на ","оро","уль","чин","эж ","энэ","ээд","їй ","їлэ"," би"," тэ"," эн","аны","дий","дээ","лал","лга","лд ","лог","ль ","н у","н ї","р б","рал","сон","тай","удл","элт","эрг","єлє"," vй"," в "," гэ"," хv","ара","бvр","д н","д о","л х","лс ","лты","н г","нэг","огт","олы","оёр","р т","рээ","тав","тог","уур","хоё","хэл","хээ","элэ","ёр "," ав"," ас"," аш"," ду"," со"," чи"," эв"," єр","аал","алд","амж","анд","асу","вэр","г у","двэ","жvv","лца","лэл");
+$GLOBALS["ngrams"]['nb'] = array("er ","en ","et "," de","det"," i ","for","il "," fo"," me","ing","om "," ha"," og","ter"," er"," ti"," st","og ","til","ne "," vi","re "," en"," se","te ","or ","de ","kke","ke ","ar ","ng ","r s","ene"," so","e s","der","an ","som","ste","at ","ed ","r i"," av"," in","men"," at"," ko"," på","har"," si","ere","på ","nde","and","els","ett","tte","lig","t s","den","t i","ikk","med","n s","rt ","ser","ska","t e","ker","sen","av ","ler","r a","ten","e f","r e","r t","ede","ig "," re","han","lle","ner"," bl"," fr","le "," ve","e t","lan","mme","nge"," be"," ik"," om"," å ","ell","sel","sta","ver"," et"," sk","nte","one","ore","r d","ske"," an"," la","del","gen","nin","r f","r v","se "," po","ir ","jon","mer","nen","omm","sjo"," fl"," sa","ern","kom","r m","r o","ren","vil","ale","es ","n a","t f"," le","bli","e e","e i","e v","het","ye "," ir","al ","e o","ide","iti","lit","nne","ran","t o","tal","tat","tt "," ka","ans","asj","ge ","inn","kon","lse","pet","t d","vi "," ut","ent","eri","oli","r p","ret","ris","sto","str","t a"," ga","all","ape","g s","ill","ira","kap","nn ","opp","r h","rin"," br"," op","e m","ert","ger","ion","kal","lsk","nes"," gj"," mi"," pr","ang","e h","e r","elt","enn","i s","ist","jen","kan","lt ","nal","res","tor","ass","dre","e b","e p","mel","n t","nse","ort","per","reg","sje","t p","t v"," hv"," nå"," va","ann","ato","e a","est","ise","isk","oil","ord","pol","ra ","rak","sse","toi"," gr","ak ","eg ","ele","g a","ige","igh","m e","n f","n v","ndr","nsk","rer","t m","und","var","år "," he"," no"," ny","end","ete","fly","g i","ghe","ier","ind","int","lin","n d","n p","rne","sak","sie","t b","tid"," al"," pa"," tr","ag ","dig","e d","e k","ess","hol","i d","lag","led","n e","n i","n o","pri","r b","st "," fe"," li"," ry","air","ake","d s","eas","egi");
+$GLOBALS["ngrams"]['ne'] = array("को ","का ","मा ","हरु"," ने","नेप","पाल","ेपा"," सम","ले "," प्","प्र","कार","ा स","एको"," भए"," छ "," भा","्रम"," गर","रुक"," र ","भार","ारत"," का"," वि","भएक","ाली","ली ","ा प","ीहर","ार्","ो छ","ना ","रु ","ालक","्या"," बा","एका","ने ","न्त","ा ब","ाको","ार ","ा भ","ाहर","्रो","क्ष","न् ","ारी"," नि","ा न","ी स"," डु","क्र","जना","यो ","ा छ","ेवा","्ता"," रा","त्य","न्द","हुन","ा क","ामा","ी न","्दा"," से","छन्","म्ब","रोत","सेव","स्त","स्र","ेका","्त "," बी"," हु","क्त","त्र","रत ","र्न","र्य","ा र","ाका","ुको"," एक"," सं"," सु","बीब","बीस","लको","स्य","ीबी","ीसी","ेको","ो स","्यक"," छन"," जन"," बि"," मु"," स्","गर्","ताह","न्ध","बार","मन्","मस्","रुल","लाई","ा व","ाई ","ाल ","िका"," त्"," मा"," यस"," रु","ताक","बन्","र ब","रण ","रुप","रेक","ष्ट","सम्","सी ","ाएक","ुका","ुक्"," अध"," अन"," तथ"," थि"," दे"," पर"," बै","तथा","ता ","दा ","द्द","नी ","बाट","यक्","री ","रीह","र्म","लका","समस","ा अ","ा ए","ाट ","िय ","ो प","ो म","्न ","्ने","्षा"," पा"," यो"," हा","अधि","डुव","त भ","त स","था ","धिक","पमा","बैठ","मुद","या ","युक","र न","रति","वान","सार","ा आ","ा ज","ा ह","ुद्","ुपम","ुले","ुवा","ैठक","ो ब","्तर","्य ","्यस"," क्"," मन"," रह","चार","तिय","दै ","निर","नु ","पर्","रक्","र्द","समा","सुर","ाउन","ान ","ानम","ारण","ाले","ि ब","ियो","ुन्","ुरक","्त्","्बन","्रा","्ष "," आर"," जल"," बे"," या"," सा","आएक","एक ","कर्","जलस","णका","त र","द्र","धान","धि ","नका","नमा","नि ","ममा","रम ","रहे","राज","लस्","ला ","वार","सका","हिल","हेक","ा त","ारे","िन्","िस्","े स","ो न","ो र","ोत ","्धि","्मी","्रस"," दु"," पन"," बत"," बन"," भन","ंयु","आरम","खि ","ण्ड","तका","ताल","दी ","देख","निय","पनि","प्त","बता","मी ","म्भ","र स","रम्","लमा","विश","षाक","संय","ा ड","ा म","ानक","ालम","ि भ","ित ","ी प","ी र","ु भ","ुने","े ग","ेखि","ेर ","ो भ","ो व","ो ह","्भ ","्र "," ता"," नम"," ना");
+$GLOBALS["ngrams"]['nl'] = array("en ","de "," de","et ","an "," he","er "," va","n d","van","een","het"," ge","oor"," ee","der"," en","ij ","aar","gen","te ","ver"," in"," me","aan","den"," we","at ","in "," da"," te","eer","nde","ter","ste","n v"," vo"," zi","ing","n h","voo","is "," op","tie"," aa","ede","erd","ers"," be","eme","ten","ken","n e"," ni"," ve","ent","ijn","jn ","mee","iet","n w","ng ","nie"," is","cht","dat","ere","ie ","ijk","n b","rde","ar ","e b","e a","met","t d","el ","ond","t h"," al","e w","op ","ren"," di"," on","al ","and","bij","zij"," bi"," hi"," wi","or ","r d","t v"," wa","e h","lle","rt ","ang","hij","men","n a","n z","rs "," om","e o","e v","end","est","n t","par"," pa"," pr"," ze","e g","e p","n p","ord","oud","raa","sch","t e","ege","ich","ien","aat","ek ","len","n m","nge","nt ","ove","rd ","wer"," ma"," mi","daa","e k","lij","mer","n g","n o","om ","sen","t b","wij"," ho","e m","ele","gem","heb","pen","ude"," bo"," ja","die","e e","eli","erk","le ","pro","rij"," er"," za","e d","ens","ind","ke ","n k","nd ","nen","nte","r h","s d","s e","t z"," b "," co"," ik"," ko"," ov","eke","hou","ik ","iti","lan","ns ","t g","t m"," do"," le"," zo","ams","e z","g v","it ","je ","ls ","maa","n i","nke","rke","uit"," ha"," ka"," mo"," re"," st"," to","age","als","ark","art","ben","e r","e s","ert","eze","ht ","ijd","lem","r v","rte","t p","zeg","zic","aak","aal","ag ","ale","bbe","ch ","e t","ebb","erz","ft ","ge ","led","mst","n n","oek","r i","t o","t w","tel","tte","uur","we ","zit"," af"," li"," ui","ak ","all","aut","doo","e i","ene","erg","ete","ges","hee","jaa","jke","kee","kel","kom","lee","moe","n s","ort","rec","s o","s v","teg","tij","ven","waa","wel"," an"," au"," bu"," gr"," pl"," ti","'' ","ade","dag","e l","ech","eel","eft","ger","gt ","ig ","itt","j d","ppe","rda");
+$GLOBALS["ngrams"]['nr'] = array("oku","la ","nga","a n"," ng","na ","ama","a i","ko "," uk","ele","lo ","ela","ang","a u","a k","uku","aba"," ku","wa ","enz","lel","ho ","ni ","ngo","ath","pha","eth","kha","ana","isa","nge"," na","o n","tho","e n","the","ha ","esi","nye","kwe","tjh"," kw","ise"," um","a a"," ne","le ","hla","a e","lan","ben","ndl"," no","imi","und","ung","thi","nzi","ye ","isi","uth","o e","ebe","het","kut","and","sa ","elo","fun","eko","seb","ban","ulu","aka","eli","wen","e i"," am","eni","ba ","we ","nel"," we","kuf","lwa","i n"," is","zi "," lo","kwa","lok","elw","gok","ona","lek","hi ","li ","gan","bon"," ii","ing","ka ","o i","akh","ane","thu","ula","kel","mth"," im","ga "," le","nda","fan","nok","i k","end","si ","o w","aph","hat","e u","ala","kub","lun","ikh","o l","ezi","a l","o u","sis","nam","emi"," ab","hul","kus"," wo","sek","azi","kho","iin","i u","asi","lol","ini","uph","uhl","khu","no ","o y","ako","a b","i e","o k","i l"," be","mal"," ye","i i","nde","iph","mel","eke","tha","kun","ngi","e k","eng","o s"," yo","so ","ma ","mkh","jha","isw","lwe"," ez","di ","a w","e a","kul","uny","ume","za ","any","ahl","kuh","een"," si","ili","itj","zok","ihl"," es","ke ","hlo","hak","phe","lul","dle","luk","da ","eka","amb"," se","zis","mbi","hon","dla","aku","jen","zin"," ba","ham","i a"," bo","o a","ali","use","ile","sik","han","wok","okh","hlu","nya","sit","ani","kuz","o o","ufa","swa","ind","zak","nis","lis","gab","mi "," em"," ko","ano"," el","hwa","ufu","a y","wo "," in","lim","tlo","kat","wak","kan","thw","o z","ith","ndi","yok","yo ","mit","mis","abo","eku","hab","iny","nan","eze","khe","alo","lu ","man","he ","ezo","kup","ubu"," zo","gam","hel","wan","omb","amk","nza","ola","hum","kuk","du "," la","kom","i y","obu","i b","odu","okw","gap"," ka","be "," il","alu","atj","e b");
+$GLOBALS["ngrams"]['nso'] = array("go "," go"," le"," a ","le "," di","a g","ya ","lo "," ya","a m","ka "," ka","la "," t ","o y","a t","a k","ba ","et ","wa "," mo"," e ","a b"," se"," ba"," ma"," bo","e g","t a"," o ","a l","o t","na ","o l","a d","elo","di ","a s","o g","o k","ele","o a","ng ","t e","o b","mo ","e t","e m","ego","eo ","e l","ngw","se ","e b","kgo","ela"," wa"," ga","e k","ago","o m"," kg","ga ","dit","olo","t h","e d","o d"," ye","ane","lel","we "," tl","thu","ona"," th","t w","hut","ana","tla","wan","aba","ola"," me","gwa","re ","ong","t o","lao","e s","o s","a y","alo","set","a p","i a","eng","a a","o e","tho"," ke","gwe"," ha","hlo","edi"," la","ao "," ts","aka","hla","ala","swa"," we"," bj","o o","gor","aga","hab","gob","let","ke ","dik","sa "," i ","oba"," hl","the","dir","a n","ith","bja","ye ","no "," sa","mol","lwa","ti ","man","ole","e e","tse","o w","ore","to ","at ","eth","e y","kan","tsh","gon","net","ano","kar","ge ","ho ","lok"," sw"," na","i b","dip","i o","oka"," ge"," om","ko ","emo","pel","nt ","e a","mel","leg","tlh","me ","ete","phe","a e","o n","o i","wal","oko","nya","bol","odi","weg","te ","e n","ta ","any","yeo","kga","pol","ang","ri ","it ","uto"," mm","iti","are","o f","ha ","gat","oth","ika","o h"," it","she","ath","ale","iri","pha","ahl"," te","ohl","tha"," re","bon","lha"," ph","din"," pe","ro ","mi ","omi","i t"," fa","aro","ase","i l","ne ","lal","ogo","kol"," wo","t i","omo"," be","mog","mok","len","ile","lwe","ma ","uta","nse","amo","a o"," fe","okg","ja ","pan","nag","ekg","i i","apa","get","lon","ra ","aem"," yo","atl","tlo","kel","tel"," kh"," po","e o","a w","ent","i e","bo ","gan","het","mal","a f","otl","uti","oga","sen","kwa","mae","eka","mme","kge","jal","a r","ing","lek","sep","lag","ofe","wag","g y","rol","epe","eko","bok","o p","adi","log");
+$GLOBALS["ngrams"]['pl'] = array("ie ","nie","em "," ni"," po"," pr","dzi"," na","że ","rze","na ","łem","wie"," w "," że","go "," by","prz","owa","ię "," do"," si","owi"," pa"," za","ch ","ego","ał ","się","ej ","wał","ym ","ani","ałe","to "," i "," to"," te","e p"," je"," z ","czy","był","pan","sta","kie"," ja","do "," ch"," cz"," wi","iał","a p","pow"," mi","li ","eni","zie"," ta"," wa","ło ","ać ","dy ","ak ","e w"," a "," od"," st","nia","rzy","ied"," kt","odz","cie","cze","ia ","iel","któ","o p","tór","ści"," sp"," wy","jak","tak","zy "," mo","ałę","pro","ski","tem","łęs"," tr","e m","jes","my "," ro","edz","eli","iej"," rz","a n","ale","an ","e s","est","le ","o s","i p","ki "," co","ada","czn","e t","e z","ent","ny ","pre","rzą","y s"," ko"," o ","ach","am ","e n","o t","oli","pod","zia"," go"," ka","by ","ieg","ier","noś","roz","spo","ych","ząd"," mn","acz","adz","bie","cho","mni","o n","ost","pra","ze ","ła "," so","a m","cza","iem","ić ","obi","ył ","yło"," mu"," mó","a t","acj","ci ","e b","ich","kan","mi ","mie","ośc","row","zen","zyd"," al"," re","a w","den","edy","ił ","ko ","o w","rac","śmy"," ma"," ra"," sz"," ty","e j","isk","ji ","ka ","m s","no ","o z","rez","wa ","ów ","łow","ść "," ob","ech","ecz","ezy","i w","ja ","kon","mów","ne ","ni ","now","nym","pol","pot","yde"," dl"," sy","a s","aki","ali","dla","icz","ku ","ocz","st ","str","szy","trz","wia","y p","za "," wt","chc","esz","iec","im ","la ","o m","sa ","wać","y n","zac","zec"," gd","a z","ard","co ","dar","e r","ien","m n","m w","mia","moż","raw","rdz","tan","ted","teg","wił","wte","y z","zna","zło","a r","awi","bar","cji","czą","dow","eż ","gdy","iek","je ","o d","tał","wal","wsz","zed","ówi","ęsa"," ba"," lu"," wo","aln","arn","ba ","dzo","e c","hod","igi","lig","m p","myś","o c","oni","rel","sku","ste","y w","yst","z w");
+$GLOBALS["ngrams"]['ps'] = array(" د ","اؤ "," اؤ","نو ","ې د","ره "," په","نه ","چې "," چې","په ","ه د","ته ","و ا","ونو","و د"," او","انو","ونه","ه ک"," دا","ه ا","دې ","ښې "," کې","ان ","لو ","هم ","و م","کښې","ه م","ى ا"," نو"," ته"," کښ","رون","کې ","ده ","له ","به ","رو "," هم","ه و","وى ","او ","تون","دا "," کو"," کړ","قام"," تر","ران","ه پ","ې و","ې پ"," به"," خو","تو ","د د","د ا","ه ت","و پ","يا "," خپ"," دو"," را"," مش"," پر","ارو","رې ","م د","مشر"," شو"," ور","ار ","دى "," اد"," دى"," مو","د پ","لي ","و ک"," مق"," يو","ؤ د","خپل","سره","ه چ","ور "," تا"," دې"," رو"," سر"," مل"," کا","ؤ ا","اره","برو","مه ","ه ب","و ت","پښت"," با"," دغ"," قب"," له"," وا"," پا"," پښ","د م","د ه","لې ","مات","مو ","ه ه","وي ","ې ب","ې ک"," ده"," قا","ال ","اما","د ن","قبر","ه ن","پار"," اث"," بي"," لا"," لر","اثا","د خ","دار","ريخ","شرا","مقا","نۍ ","ه ر","ه ل","ولو","يو ","کوم"," دد"," لو"," مح"," مر"," وو","اتو","اري","الو","اند","خان","د ت","سې ","لى ","نور","و ل","ي چ","ړي ","ښتو","ې ل"," جو"," سي","ام ","بان","تار","تر ","ثار","خو ","دو ","ر ک","ل د","مون","ندې","و ن","ول ","وه ","ى و","ي د","ې ا","ې ت","ې ي"," حک"," خب"," نه"," پو","ا د","تې ","جوړ","حکم","حکو","خبر","دان","ر د","غه ","قاف","محک","وال","ومت","ويل","ى د","ى م","يره","پر ","کول","ې ه"," تي"," خا"," وک"," يا"," ځا","ؤ ق","انۍ","بى ","غو ","ه خ","و ب","ودا","يدو","ړې ","کال"," بر"," قد"," مي"," وي"," کر","ؤ م","ات ","ايي","تى ","تيا","تير","خوا","دغو","دم ","ديم","ر و","قدي","م خ","مان","مې ","نيو","نږ ","ه ي","و س","و چ","وان","ورو","ونږ","پور","ړه ","ړو ","ۍ د","ې ن"," اه"," زي"," سو"," شي"," هر"," هغ"," ښا","اتل","اق ","اني","بري","بې ","ت ا","د ب","د س","ر م","رى ","عرا","لان","مى ","نى ","و خ","وئ ","ورک","ورې","ون ","وکړ","ى چ","يمه","يې ","ښتن","که ","کړي","ې خ","ے ش"," تح"," تو"," در"," دپ"," صو"," عر"," ول"," يؤ"," پۀ"," څو","ا ا");
+$GLOBALS["ngrams"]['pt'] = array("de "," de","os ","as ","que"," co","ão ","o d"," qu","ue "," a ","do ","ent"," se","a d","s d","e a","es "," pr","ra ","da "," es"," pa","to "," o ","em ","con","o p"," do","est","nte","ção"," da"," re","ma ","par"," te","ara","ida"," e ","ade","is "," um"," po","a a","a p","dad","no ","te "," no","açã","pro","al ","com","e d","s a"," as","a c","er ","men","s e","ais","nto","res","a s","ado","ist","s p","tem","e c","e s","ia ","o s","o a","o c","e p","sta","ta ","tra","ura"," di"," pe","ar ","e e","ser","uma","mos","se "," ca","o e"," na","a e","des","ont","por"," in"," ma","ect","o q","ria","s c","ste","ver","cia","dos","ica","str"," ao"," em","das","e t","ito","iza","pre","tos"," nã","ada","não","ess","eve","or ","ran","s n","s t","tur"," ac"," fa","a r","ens","eri","na ","sso"," si"," é ","bra","esp","mo ","nos","ro ","um ","a n","ao ","ico","liz","min","o n","ons","pri","ten","tic","ões"," tr","a m","aga","e n","ili","ime","m a","nci","nha","nta","spe","tiv","am ","ano","arc","ass","cer","e o","ece","emo","ga ","o m","rag","so ","são"," au"," os"," sa","ali","ca ","ema","emp","ici","ido","inh","iss","l d","la ","lic","m c","mai","onc","pec","ram","s q"," ci"," en"," fo","a o","ame","car","co ","der","eir","ho ","io ","om ","ora","r a","sen","ter"," br"," ex","a u","cul","dev","e u","ha ","mpr","nce","oca","ove","rio","s o","sa ","sem","tes","uni","ven","zaç","çõe"," ad"," al"," an"," mi"," mo"," ve"," à ","a i","a q","ala","amo","bli","cen","col","cos","cto","e m","e v","ede","gás","ias","ita","iva","ndo","o t","ore","r d","ral","rea","s f","sid","tro","vel","vid","ás "," ap"," ar"," ce"," ou"," pú"," so"," vi","a f","act","arr","bil","cam","e f","e i","el ","for","lem","lid","lo ","m d","mar","nde","o o","omo","ort","per","púb","r u","rei","rem","ros","rre","ssi");
+$GLOBALS["ngrams"]['pt_BR'] = array("eq ","ent"," en","q e","q i","g e","g i","ng "," id","ida","nte","te "," es"," in","ade","ag ","dad","de ","ia ","ing"," br"," sa","est","inq","lin","mo ","nq ","o a","seq"," co"," li"," ni"," o ","a a","a c","ado","asi","bra","dor","iq ","nta","o b","or ","q n","ras","sil","str","ta ","tre","us "," a "," ag"," an"," ca"," e "," eq"," g "," i "," ir"," nc"," q "," se"," ve","ant","ar ","cia","con","e a","eir","el ","ig ","ili","imo","io ","ir ","nci","o t","ro ","vel"," ap"," bo"," de"," fr"," tr","a b","a e","a g","a v","apo","as ","bus","ca ","cet","cin","des","e b","e s","eta","fre","i a","ibu","il ","iro","la ","liq","nib","nti","o c","o q","os ","ra ","re ","req","s a","s s","san","sim","tar","to ","ult"," ba"," ci"," el"," em"," fi"," gr"," gu"," ia"," mu"," pe"," po"," re"," ri"," si"," su"," te"," vi","a o","a s","abe","alc","and","ara","arg","ari","ben","boc","car","co ","do ","e f","e g","e l","e o","em ","emo","en ","es ","esp","exe","fic","g n","g s","gra","gua","ias","ica","idi","ila","ile","inh","l b","l e","lei","loq","mos","mul","nad","nio","nt ","nto","o g","o r","oce","ont","oq ","pos","q v","r b","r e","r i","r s","rad","ran","rem","rg ","ria","rio","s e","s p","sta","sti","tig","til","tra","ua ","ue ","va ","xeq"," ' "," ab"," ad"," ae"," al"," am"," aq"," ar"," b "," bi"," bl"," bu"," cc"," ch"," di"," et"," ex"," fa"," ic"," il"," im"," is"," it"," ll"," m "," me"," na"," ne"," ng"," nu"," ob"," ou"," pi"," qu"," ss"," st"," ti"," ub"," un"," v "," x ","' c","a d","a f","a i","a n","a p","a t","abr","aci","ad ","ada","adr","aer","afe","alv","amb","amp","an ","ana","ang","anh","ani","ano","anq","apa","aq ","ati","ato","azi","b n","ban","bar","big","bil","biq","bli","blu","bon","bre","bri","bse","buc","c f","c i","cad","caf","cag","cal","can","cc ");
+$GLOBALS["ngrams"]['pt_PT'] = array("equ","ent","que","qui","gui","uen"," li","ngu","qu ","uid"," co"," ve","de ","gue","ida","nte","o a","a a","ade","dad","el ","ing","mo ","nqu","nta","seq","u n","vel"," de"," o "," se","a c","ado","ar ","est","ia ","inq","io ","iqu","lin","o c","o p","ort","por","ta ","te "," ag"," eq"," nc"," pi"," po"," sa","a d","a e","ant","as ","ca ","cia","des","do ","gu ","imo","l p","nci","ro ","rtu","str","tug","u s","ues","ui "," a "," an"," ap"," ba"," bi"," ca"," fr"," gu"," in"," pe"," qu","agu","apa","con","dor","e f","e g","eir","fre","ho ","i a","ica","igu","iro","liq","nti","o b","o l","o s","or ","r o","ra ","req","s c","sim","tar","to ","ue ","uin","ult"," ci"," en"," ho"," mu"," ni"," re"," s "," si"," su","a s","a v","abe","ag ","al ","and","anh","apo","ata","ban","ben","bic","boi","cap","car","cin","co ","com","cto","dei","e b","e o","e s","eca","en ","er ","es ","exe","fic","for","gal","gra","ias","ich","ico","idi","ili","ir ","ira","isb","la ","lis","mbo","mul","na ","nho","nio","nt ","o q","o r","o t","oc ","oio","omb","oo ","os ","par","pe ","r b","r e","r s","ran","re ","rec","s a","s s","san","sbo","so ","sta","tan","tra","tre","u v","uga","ugu","xeq"," ab"," ad"," al"," am"," aq"," ar"," au"," b "," bo"," c "," ch"," ct"," cu"," el"," es"," ex"," fa"," fi"," ga"," gr"," id"," ir"," ne"," ng"," nu"," ob"," oo"," pa"," ps"," pt"," r "," ra"," ri"," ss"," st"," ta"," te"," tr"," ub"," un"," vi"," vo","a f","a i","a l","a m","a o","a r","ach","aci","act","ad ","afa","age","agr","alf","alh","am ","amb","ami","ana","ang","anq","aqu","ara","arb","arc","arg","ari","arr","asa","ati","aut","azi","b n","bar","bat","ber","big","bil","biq","bli","boa","boe","bor","bse","c i","c l","c p","cad","cam","cas","ch ","cha","che","chi","cio","coc","coi","cou","ctr","cue","cul");
+$GLOBALS["ngrams"]['ro'] = array(" de"," în","de "," a ","ul "," co","în ","re ","e d","ea "," di"," pr","le ","şi ","are","at ","con","ui "," şi","i d","ii "," cu","e a","lui","ern","te ","cu "," la","a c","că ","din","e c","or ","ulu","ne ","ter","la ","să ","tat","tre"," ac"," să","est","st ","tă "," ca"," ma"," pe","cur","ist","mân","a d","i c","nat"," ce","i a","ia ","in ","scu"," mi","ato","aţi","ie "," re"," se","a a","int","ntr","tru","uri","ă a"," fo"," pa","ate","ini","tul","ent","min","pre","pro","a p","e p","e s","ei ","nă ","par","rna","rul","tor"," in"," ro"," tr"," un","al ","ale","art","ce ","e e","e î","fos","ita","nte","omâ","ost","rom","ru ","str","ver"," ex"," na","a f","lor","nis","rea","rit"," al"," eu"," no","ace","cer","ile","nal","pri","ri ","sta","ste","ţie"," au"," da"," ju"," po","ar ","au ","ele","ere","eri","ina","n a","n c","res","se ","t a","tea"," că"," do"," fi","a s","ată","com","e ş","eur","guv","i s","ice","ili","na ","rec","rep","ril","rne","rti","uro","uve","ă p"," ar"," o "," su"," vi","dec","dre","oar","ons","pe ","rii"," ad"," ge","a m","a r","ain","ali","car","cat","ecu","ene","ept","ext","ilo","iu ","n p","ori","sec","u p","une","ă c","şti","ţia"," ch"," gu","ai ","ani","cea","e f","isc","l a","lic","liu","mar","nic","nt ","nul","ris","t c","t p","tic","tid","u a","ucr"," as"," dr"," fa"," nu"," pu"," to","cra","dis","enţ","esc","gen","it ","ivi","l d","n d","nd ","nu ","ond","pen","ral","riv","rte","sti","t d","ta ","to ","uni","xte","ând","îns","ă s"," bl"," st"," uc","a b","a i","a l","air","ast","bla","bri","che","duc","dul","e m","eas","edi","esp","i l","i p","ica","ică","ir ","iun","jud","lai","lul","mai","men","ni ","pus","put","ra ","rai","rop","sil","ti ","tra","u s","ua ","ude","urs","ân ","înt","ţă "," lu"," mo"," s "," sa"," sc","a u","an ","atu");
+$GLOBALS["ngrams"]['ru'] = array(" на"," пр","то "," не","ли "," по","но "," в ","на ","ть ","не "," и "," ко","ом ","про"," то","их "," ка","ать","ото"," за","ие ","ова","тел","тор"," де","ой ","сти"," от","ах ","ми ","стр"," бе"," во"," ра","ая ","ват","ей ","ет ","же ","иче","ия ","ов ","сто"," об","вер","го ","и в","и п","и с","ии ","ист","о в","ост","тра"," те","ели","ере","кот","льн","ник","нти","о с","рор","ств","чес"," бо"," ве"," да"," ин"," но"," с "," со"," сп"," ст"," чт","али","ами","вид","дет","е н","ель","еск","ест","зал","и н","ива","кон","ого","одн","ожн","оль","ори","ров","ско","ся ","тер","что"," мо"," са"," эт","ант","все","ерр","есл","иде","ина","ино","иро","ите","ка ","ко ","кол","ком","ла ","ния","о т","оло","ран","ред","сь ","тив","тич","ых "," ви"," вс"," го"," ма"," сл","ако","ани","аст","без","дел","е д","е п","ем ","жно","и д","ика","каз","как","ки ","нос","о н","опа","при","рро","ски","ти ","тов","ые "," вы"," до"," ме"," ни"," од"," ро"," св"," чи","а н","ает","аза","ате","бес","в п","ва ","е в","е м","е с","ез ","ени","за ","зна","ини","кам","ках","кто","лов","мер","мож","нал","ниц","ны ","ным","ора","оро","от ","пор","рав","рес","рис","рос","ска","т н","том","чит","шко"," бы"," о "," тр"," уж"," чу"," шк","а б","а в","а р","аби","ала","ало","аль","анн","ати","бин","вес","вно","во ","вши","дал","дат","дно","е з","его","еле","енн","ент","ете","и о","или","ись","ит ","ици","ков","лен","льк","мен","мы ","нет","ни ","нны","ног","ной","ном","о п","обн","ове","овн","оры","пер","по ","пра","пре","раз","роп","ры ","се ","сли","сов","тре","тся","уро","цел","чно","ь в","ько","ьно","это","ют ","я н"," ан"," ес"," же"," из"," кт"," ми"," мы"," пе"," се"," це","а м","а п","а т","авш","аже","ак ","ал ","але","ане","ачи","ают","бна","бол","бы ","в и","в с","ван","гра","даж","ден","е к");
+$GLOBALS["ngrams"]['sk'] = array(" pr"," po"," ne"," a ","ch "," na"," je","ní ","je "," do","na ","ova"," v ","to ","ho ","ou "," to","ick","ter","že "," st"," za","ost","ých"," se","pro"," te","e s"," že","a p"," kt","pre"," by"," o ","se ","kon"," př","a s","né ","ně ","sti","ako","ist","mu ","ame","ent","ky ","la ","pod"," ve"," ob","om ","vat"," ko","sta","em ","le ","a v","by ","e p","ko ","eri","kte","sa ","ého","e v","mer","tel"," ak"," sv"," zá","hla","las","lo "," ta","a n","ej ","li ","ne "," sa","ak ","ani","ate","ia ","sou"," so","ení","ie "," re","ce ","e n","ori","tic"," vy","a t","ké ","nos","o s","str","ti ","uje"," sp","lov","o p","oli","ová"," ná","ale","den","e o","ku ","val"," am"," ro"," si","nie","pol","tra"," al","ali","o v","tor"," mo"," ni","ci ","o n","ím "," le"," pa"," s ","al ","ati","ero","ove","rov","ván","ích"," ja"," z ","cké","e z"," od","byl","de ","dob","nep","pra","ric","spo","tak"," vš","a a","e t","lit","me ","nej","no ","nýc","o t","a j","e a","en ","est","jí ","mi ","slo","stá","u v","for","nou","pos","pře","si ","tom"," vl","a z","ly ","orm","ris","za ","zák"," k ","at ","cký","dno","dos","dy ","jak","kov","ny ","res","ror","sto","van"," op","da ","do ","e j","hod","len","ný ","o z","poz","pri","ran","u s"," ab","aj ","ast","it ","kto","o o","oby","odo","u p","va ","ání","í p","ým "," in"," mi","ať ","dov","ka ","nsk","áln"," an"," bu"," sl"," tr","e m","ech","edn","i n","kýc","níc","ov ","pří","í a"," aj"," bo","a d","ide","o a","o d","och","pov","svo","é s"," kd"," vo"," vý","bud","ich","il ","ili","ni ","ním","od ","osl","ouh","rav","roz","st ","stv","tu ","u a","vál","y s","í s","í v"," hl"," li"," me","a m","e b","h s","i p","i s","iti","lád","nem","nov","opo","uhl","eno","ens","men","nes","obo","te ","ved","vlá","y n"," ma"," mu"," vá","bez","byv","cho");
+$GLOBALS["ngrams"]['sl'] = array("je "," pr"," po"," je"," v "," za"," na","pre","da "," da","ki ","ti ","ja ","ne "," in","in ","li ","no ","na ","ni "," bi","jo "," ne","nje","e p","i p","pri","o p","red"," do","anj","em ","ih "," bo"," ki"," iz"," se"," so","al "," de","e v","i s","ko ","bil","ira","ove"," br"," ob","e b","i n","ova","se ","za ","la "," ja","ati","so ","ter"," ta","a s","del","e d"," dr"," od","a n","ar ","jal","ji ","rit"," ka"," ko"," pa","a b","ani","e s","er ","ili","lov","o v","tov"," ir"," ni"," vo","a j","bi ","bri","iti","let","o n","tan","še "," le"," te","eni","eri","ita","kat","por","pro","ali","ke ","oli","ov ","pra","ri ","uar","ve "," to","a i","a v","ako","arj","ate","di ","do ","ga ","le ","lo ","mer","o s","oda","oro","pod"," ma"," mo"," si","a p","bod","e n","ega","ju ","ka ","lje","rav","ta ","a o","e t","e z","i d","i v","ila","lit","nih","odo","sti","to ","var","ved","vol"," la"," no"," vs","a d","agu","aja","dej","dnj","eda","gov","gua","jag","jem","kon","ku ","nij","omo","oči","pov","rak","rja","sta","tev","a t","aj ","ed ","eja","ent","ev ","i i","i o","ijo","ist","ost","ske","str"," ra"," s "," tr"," še","arn","bo ","drž","i j","ilo","izv","jen","lja","nsk","o d","o i","om ","ora","ovo","raz","rža","tak","va ","ven","žav"," me"," če","ame","avi","e i","e o","eka","gre","i t","ija","il ","ite","kra","lju","mor","nik","o t","obi","odn","ran","re ","sto","stv","udi","v i","van"," am"," sp"," st"," tu"," ve"," že","ajo","ale","apo","dal","dru","e j","edn","ejo","elo","est","etj","eva","iji","ik ","im ","itv","mob","nap","nek","pol","pos","rat","ski","tič","tom","ton","tra","tud","tve","v b","vil","vse","čit"," av"," gr","a z","ans","ast","avt","dan","e m","eds","for","i z","kot","mi ","nim","o b","o o","od ","odl","oiz","ot ","par","pot","rje","roi","tem","val");
+$GLOBALS["ngrams"]['so'] = array("ka ","ay ","da "," ay","aal","oo ","aan"," ka","an ","in "," in","ada","maa","aba"," so","ali","bad","add","soo"," na","aha","ku ","ta "," wa","yo ","a s","oma","yaa"," ba"," ku"," la"," oo","iya","sha","a a","dda","nab","nta"," da"," ma","nka","uu ","y i","aya","ha ","raa"," dh"," qa","a k","ala","baa","doo","had","liy","oom"," ha"," sh","a d","a i","a n","aar","ee ","ey ","y k","ya "," ee"," iy","aa ","aaq","gaa","lam"," bu","a b","a m","ad ","aga","ama","iyo","la ","a c","a l","een","int","she","wax","yee"," si"," uu","a h","aas","alk","dha","gu ","hee","ii ","ira","mad","o a","o k","qay"," ah"," ca"," wu","ank","ash","axa","eed","en ","ga ","haa","n a","n s","naa","nay","o d","taa","u b","uxu","wux","xuu"," ci"," do"," ho"," ta","a g","a u","ana","ayo","dhi","iin","lag","lin","lka","o i","san","u s","una","uun"," ga"," xa"," xu","aab","abt","aq ","aqa","ara","arl","caa","cir","eeg","eel","isa","kal","lah","ney","qaa","rla","sad","sii","u d","wad"," ad"," ar"," di"," jo"," ra"," sa"," u "," yi","a j","a q","aad","aat","aay","ah ","ale","amk","ari","as ","aye","bus","dal","ddu","dii","du ","duu","ed ","ege","gey","hay","hii","ida","ine","joo","laa","lay","mar","mee","n b","n d","n m","no ","o b","o l","oog","oon","rga","sh ","sid","u q","unk","ush","xa ","y d"," bi"," gu"," is"," ke"," lo"," me"," mu"," qo"," ug","a e","a o","a w","adi","ado","agu","al ","ant","ark","asa","awi","bta","bul","d a","dag","dan","do ","e s","gal","gay","guu","h e","hal","iga","ihi","iri","iye","ken","lad","lid","lsh","mag","mun","n h","n i","na ","o n","o w","ood","oor","ora","qab","qor","rab","rit","rta","s o","sab","ska","to ","u a","u h","u u","ud ","ugu","uls","uud","waa","xus","y b","y q","y s","yad","yay","yih"," aa"," bo"," br"," go"," ji"," mi"," of"," ti"," um"," wi"," xo","a x");
+$GLOBALS["ngrams"]['sq'] = array("të "," të","në ","për"," pë"," e ","sht"," në"," sh","se ","et ","ë s","ë t"," se","he ","jë ","ër ","dhe"," pa","ë n","ë p"," që"," dh","një","ë m"," nj","ësh","in "," me","që "," po","e n","e t","ish","më ","së ","me ","htë"," ka"," si","e k","e p"," i ","anë","ar "," nu","und","ve "," ës","e s"," më","nuk","par","uar","uk ","jo ","rë ","ta ","ë f","en ","it ","min","het","n e","ri ","shq","ë d"," do"," nd","sh ","ën ","atë","hqi","ist","ë q"," gj"," ng"," th","a n","do ","end","imi","ndi","r t","rat","ë b","ëri"," mu","art","ash","qip"," ko","e m","edh","eri","je ","ka ","nga","si ","te ","ë k","ësi"," ma"," ti","eve","hje","ira","mun","on ","po ","re "," pr","im ","lit","o t","ur ","ë e","ë v","ët "," ku"," së","e d","es ","ga ","iti","jet","ndë","oli","shi","tje"," bë"," z ","gje","kan","shk","ënd","ës "," de"," kj"," ru"," vi","ara","gov","kjo","or ","r p","rto","rug","tet","ugo","ali","arr","at ","d t","ht ","i p","ipë","izi","jnë","n n","ohe","shu","shë","t e","tik","a e","arë","etë","hum","nd ","ndr","osh","ova","rim","tos","va "," fa"," fi","a s","hen","i n","mar","ndo","por","ris","sa ","sis","tës","umë","viz","zit"," di"," mb","aj ","ana","ata","dër","e a","esh","ime","jes","lar","n s","nte","pol","r n","ran","res","rrë","tar","ë a","ë i"," at"," jo"," kë"," re","a k","ai ","akt","hë ","hën","i i","i m","ia ","men","nis","shm","str","t k","t n","t s","ë g","ërk","ëve"," ai"," ci"," ed"," ja"," kr"," qe"," ta"," ve","a p","cil","el ","erë","gji","hte","i t","jen","jit","k d","mën","n t","nyr","ori","pas","ra ","rie","rës","tor","uaj","yre","ëm ","ëny"," ar"," du"," ga"," je","dës","e e","e z","ha ","hme","ika","ini","ite","ith","koh","kra","ku ","lim","lis","qën","rën","s s","t d","t t","tir","tën","ver","ë j"," ba"," in"," tr"," zg","a a","a m","a t","abr");
+$GLOBALS["ngrams"]['sr'] = array(" на"," је"," по","је "," и "," не"," пр","га "," св","ог ","а с","их ","на ","кој","ога"," у ","а п","не ","ни ","ти "," да","ом "," ве"," ср","и с","ско"," об","а н","да ","е н","но ","ног","о ј","ој "," за","ва ","е с","и п","ма ","ник","обр","ова"," ко","а и","диј","е п","ка ","ко ","ког","ост","све","ств","сти","тра","еди","има","пок","пра","раз","те "," бо"," ви"," са","аво","бра","гос","е и","ели","ени","за ","ики","ио ","пре","рав","рад","у с","ју ","ња "," би"," до"," ст","аст","бој","ебо","и н","им ","ку ","лан","неб","ово","ого","осл","ојш","пед","стр","час"," го"," кр"," мо"," чл","а м","а о","ако","ача","вел","вет","вог","еда","ист","ити","ије","око","сло","срб","чла"," бе"," ос"," от"," ре"," се","а в","ан ","бог","бро","вен","гра","е о","ика","ија","ких","ком","ли ","ну ","ота","ојн","под","рбс","ред","рој","са ","сни","тач","тва","ја ","ји "," ка"," ов"," тр","а ј","ави","аз ","ано","био","вик","во ","гов","дни","е ч","его","и о","ива","иво","ик ","ине","ини","ипе","кип","лик","ло ","наш","нос","о т","од ","оди","она","оји","поч","про","ра ","рис","род","рст","се ","спо","ста","тић","у д","у н","у о","чин","ша ","јед","јни","ће "," м "," ме"," ни"," он"," па"," сл"," те","а у","ава","аве","авн","ана","ао ","ати","аци","ају","ања","бск","вор","вос","вск","дин","е у","едн","ези","ека","ено","ето","ења","жив","и г","и и","и к","и т","ику","ичк","ки ","крс","ла ","лав","лит","ме ","мен","нац","о н","о п","о у","одн","оли","орн","осн","осп","оче","пск","реч","рпс","сво","ски","сла","срп","су ","та ","тав","тве","у б","јез","ћи "," ен"," жи"," им"," му"," од"," су"," та"," хр"," ча"," шт"," ње","а д","а з","а к","а т","аду","ало","ани","асо","ван","вач","вањ","вед","ви ","вно","вот","вој","ву ","доб","дру","дсе","ду ","е б","е д","е м","ем ","ема","ент","енц");
+$GLOBALS["ngrams"]['ss'] = array(" ku"," le","la ","eku","a k","nga"," ng","a n","nge","a l","lo "," ne","eti","kwe","ndz","e n","o l"," lo","ela","ema","ent","si "," kw","tsi","i l","wa ","lel","kut","e k","und","ni ","elo","fun","esi"," si","ele","tin","tfo"," ti","le ","kha","tse","e l","pha","ung","i k"," em","ti ","sa "," um","isa","eli","ndl","ing","set","we ","ise","na ","ang","etf","khe","and","o n"," we","nti","nye","tfu","ben","a e","uts","let","dza","imi","sek","ko ","lok","eni","ye ","ba ","nkh","ebe","alo","o k","lan","ga ","aba","seb"," ye","he ","lwa","kel"," te"," la","kus","wem","ati","ikh","nek","ala","kuf","i n","oku","ats","mts","hla","wen","a t"," na","gek","uhl","kub","ngu","ka ","aka","fut","kan","kwa"," li","kuc","onk","ban","ana","ulu"," se"," im","akh","ume","a i","les","tim","ula","ini","lwe","za ","fo ","hul"," no","han","li ","iph","a s","tis","khu","ta ","dzi","be ","emi","ma ","end","o t","eke","a u"," ka","ane","lek","mel","elw","kun","sis","lon","utf","any","kho","kul","hlo"," ba","ufu","aph","lun","e s","hal","ind","isw","o s","use","ekw","me ","ndv","eng","uph","hat","ne ","so ","lul","nom","te ","lol","awu","nel","lu ","ha ","wat","men","ete"," lw","nem","ako","zin","kuh","sha","bha","gab"," in","ale","mis","tem","e e","o e","e t","wek","dze","ome","wel"," lu","emb","nis"," ek","tsa","u l","o y","dle","ute","len","swa","phe","mkh","ntf","uke","sit","iny","e i","wo ","ani","phi","wet","sin","nhl","mal","mba","mfu","fu ","lab","sik","taw","no ","hle","e u","eki","ase","ali","ulw","ve ","eka","zel","nta","bon","tek","bo ","sig","ama","ile","ule","tfw","mph","uma","kup","emt","asi","dlu","ish","umt","gen","o w","ike","iga","hak","abe","net","gan","kis","nde","ngi","ukh","bek","mo ","phu","sel","elu","i t","ant","dvo","a y","vo ","hum","lis","dla","gam","ive","jen","ket");
+$GLOBALS["ngrams"]['st'] = array("ng ","ho "," le","le "," ho"," ts","a m","sa ","la "," ka","a h"," di","ya ","ka "," ya","a t","eng","ets"," ba"," mo","a l"," se","lo "," bo","wa ","tsa","a b","na ","ba "," e "," a ","a k"," ma","ang","tse","se ","o t","a d","a s","ha ","so ","o l","e h","o y","e t","tla","tsh","olo","e l","e m","o b","o e","seb","ebe","ela","thu","ele","e k","ana","e b"," th"," ha","tso","o a","o k"," wa","kgo","tsw","tho","o h","ong"," la","hut","dit","ane"," me","a e"," tl","ola","edi","elo","di ","ona"," ke","wan"," o ","a p","apa","tjh","hlo"," sa","she","let","aba","lok","lao","eo ","a a","o s","man","to "," hl","a n","isa","e d","swe","set","pa "," na","o m","g l","het"," kg","got","aha","eth","re ","e e","jha","phe","lan","otl","g k","lek","its","ekg","sen","ao ","dis","g m","oth","e a","ith","hla","e s","ke ","mol","pel","g h","hab","bet","san","ats","mo ","lwa","we ","ala","len","nts","dip","kap","iso"," mm","uto","alo","e n","si ","ta ","o w","emo","swa","tsi","oke","bed","the"," ph","a y","wen","ken","ena","hwa","ne ","ore","atl","ano","hel","mot","bo ","g t","i b","kga","hor","ngo","nan","no ","o n","tlh","shw","kel","pha","etj","bon","ell","g s","gol","tha","ale","dik","kol","bak"," nt","ika","o d"," te","ohl","g y"," lo","ti ","his","ile","g b","oko"," et","han","a o","mat","oho","odi","lel","mel","din","kar","o o","uo ","mon","hah","te ","me "," it","o f","nen","heb","ing","bol","bel","hle","puo","lal","tlo","hal","oph","eba","hat","heo","aro","bat","ko ","ban","leh","o i","ole","tle"," fe","kge","pan","ake","g e","aka","eko"," pe","rik","e y","mme","ama","lha","eha"," fa","ebo","moh","mae","ete","aem","ots","ahi","o p","uta","okg","ntl","pal","get","i l","e f","oka","sep","lat","ahl","bot","ese","lah","lon","akg","a f"," pu","ase","g a","mor","kan","nah","boh","e p");
+$GLOBALS["ngrams"]['sv'] = array("en "," de","et ","er ","tt ","om ","för","ar ","de ","att"," fö","ing"," in"," at"," i ","det","ch ","an ","gen"," an","t s","som","te "," oc","ter"," ha","lle","och"," sk"," so","ra ","r a"," me","var","nde","är "," ko","on ","ans","int","n s","na "," en"," fr"," på"," st"," va","and","nte","på ","ska","ta "," vi","der","äll","örs"," om","da ","kri","ka ","nst"," ho","as ","stä","r d","t f","upp"," be","nge","r s","tal","täl","ör "," av","ger","ill","ng ","e s","ekt","ade","era","ers","har","ll ","lld","rin","rna","säk","und","inn","lig","ns "," ma"," pr"," up","age","av ","iva","kti","lda","orn","son","ts ","tta","äkr"," sj"," ti","avt","ber","els","eta","kol","men","n d","t k","vta","år ","juk","man","n f","nin","r i","rsä","sju","sso"," är","a s","ach","ag ","bac","den","ett","fte","hor","nba","oll","rnb","ste","til"," ef"," si","a a","e h","ed ","eft","ga ","ig ","it ","ler","med","n i","nd ","så ","tiv"," bl"," et"," fi"," sä","at ","des","e a","gar","get","lan","lss","ost","r b","r e","re ","ret","sta","t i"," ge"," he"," re","a f","all","bos","ets","lek","let","ner","nna","nne","r f","rit","s s","sen","sto","tor","vav","ygg"," ka"," så"," tr"," ut","ad ","al ","are","e o","gon","kom","n a","n h","nga","r h","ren","t d","tag","tar","tre","ätt"," få"," hä"," se","a d","a i","a p","ale","ann","ara","byg","gt ","han","igt","kan","la ","n o","nom","nsk","omm","r k","r p","r v","s f","s k","t a","t p","ver"," bo"," br"," ku"," nå","a b","a e","del","ens","es ","fin","ige","m s","n p","någ","or ","r o","rbe","rs ","rt ","s a","s n","skr","t o","ten","tio","ven"," al"," ja"," p "," r "," sa","a h","bet","cke","dra","e f","e i","eda","eno","erä","ess","ion","jag","m f","ne ","nns","pro","r t","rar","riv","rät","t e","t t","ust","vad","öre"," ar"," by"," kr"," mi","arb");
+$GLOBALS["ngrams"]['sw'] = array(" wa","wa ","a k","a m"," ku"," ya","a w","ya ","ni "," ma","ka ","a u","na ","za ","ia "," na","ika","ma ","ali","a n"," am","ili","kwa"," kw","ini"," ha","ame","ana","i n"," za","a h","ema","i m","i y","kuw","la ","o w","a y","ata","sem"," la","ati","chi","i w","uwa","aki","li ","eka","ira"," nc","a s","iki","kat","nch"," ka"," ki","a b","aji","amb","ra ","ri ","rik","ada","mat","mba","mes","yo ","zi ","da ","hi ","i k","ja ","kut","tek","wan"," bi","a a","aka","ao ","asi","cha","ese","eza","ke ","moj","oja"," hi","a z","end","ha ","ji ","mu ","shi","wat"," bw","ake","ara","bw ","i h","imb","tik","wak","wal"," hu"," mi"," mk"," ni"," ra"," um","a l","ate","esh","ina","ish","kim","o k"," ir","a i","ala","ani","aq ","azi","hin","i a","idi","ima","ita","rai","raq","sha"," ms"," se","afr","ama","ano","ea ","ele","fri","go ","i i","ifa","iwa","iyo","kus","lia","lio","maj","mku","no ","tan","uli","uta","wen"," al","a j","aad","aid","ari","awa","ba ","fa ","nde","nge","nya","o y","u w","ua ","umo","waz","ye "," ut"," vi","a d","a t","aif","di ","ere","ing","kin","nda","o n","oa ","tai","toa","usa","uto","was","yak","zo "," ji"," mw","a p","aia","amu","ang","bik","bo ","del","e w","ene","eng","ich","iri","iti","ito","ki ","kir","ko ","kuu","mar","mbo","mil","ngi","ngo","o l","ong","si ","ta ","tak","u y","umu","usi","uu ","wam"," af"," ba"," li"," si"," zi","a v","ami","atu","awi","eri","fan","fur","ger","i z","isi","izo","lea","mbi","mwa","nye","o h","o m","oni","rez","saa","ser","sin","tat","tis","tu ","uin","uki","ur ","wi ","yar"," da"," en"," mp"," ny"," ta"," ul"," we","a c","a f","ais","apo","ayo","bar","dhi","e a","eke","eny","eon","hai","han","hiy","hur","i s","imw","kal","kwe","lak","lam","mak","msa","ne ","ngu","ru ","sal","swa","te ","ti ","uku","uma","una","uru");
+$GLOBALS["ngrams"]['tl'] = array("ng ","ang"," na"," sa","an ","nan","sa ","na "," ma"," ca","ay ","n g"," an","ong"," ga","at "," pa","ala"," si","a n","ga ","g n","g m","ito","g c","man","san","g s","ing","to ","ila","ina"," di"," ta","aga","iya","aca","g t"," at","aya","ama","lan","a a","qui","a c","a s","nag"," ba","g i","tan","'t "," cu","aua","g p"," ni","os ","'y ","a m"," n ","la "," la","o n","yan"," ay","usa","cay","on ","ya "," it","al ","apa","ata","t n","uan","aha","asa","pag"," gu","g l","di ","mag","aba","g a","ara","a p","in ","ana","it ","si ","cus","g b","uin","a t","as ","n n","hin"," hi","a't","ali"," bu","gan","uma","a d","agc","aqu","g d"," tu","aon","ari","cas","i n","niy","pin","a i","gca","siy","a'y","yao","ag ","ca ","han","ili","pan","sin","ual","n s","nam"," lu","can","dit","gui","y n","gal","hat","nal"," is","bag","fra"," fr"," su","a l"," co","ani"," bi"," da","alo","isa","ita","may","o s","sil","una"," in"," pi","l n","nil","o a","pat","sac","t s"," ua","agu","ail","bin","dal","g h","ndi","oon","ua "," ha","ind","ran","s n","tin","ulo","eng","g f","ini","lah","lo ","rai","rin","ton","g u","inu","lon","o'y","t a"," ar","a b","ad ","bay","cal","gya","ile","mat","n a","pau","ra ","tay","y m","ant","ban","i m","nas","nay","no ","sti"," ti","ags","g g","ta ","uit","uno"," ib"," ya","a u","abi","ati","cap","ig ","is ","la'"," do"," pu","api","ayo","gos","gul","lal","tag","til","tun","y c","y s","yon","ano","bur","iba","isi","lam","nac","nat","ni ","nto","od ","pa ","rgo","urg"," m ","adr","ast","cag","gay","gsi","i p","ino","len","lin","m g","mar","nah","to'"," de","a h","cat","cau","con","iqu","lac","mab","min","og ","par","sal"," za","ao ","doo","ipi","nod","nte","uha","ula"," re","ill","lit","mac","nit","o't","or ","ora","sum","y p"," al"," mi"," um","aco","ada","agd","cab");
+$GLOBALS["ngrams"]['tlh'] = array("tlh","e' ","gh ","i' "," 'e","u' "," vi","atl","a' "," gh","ej "," ho"," ch"," mu"," tl","nga","mey","wi'","be'","an ","ch ","gan","chu","lh ","ing","'e'","hin","jat","lhi"," da"," ja","o' ","ugh","aq ","cha"," po","ey "," 'a"," je","'ej"," pa","ng ","ad "," qa","oh ","eh ","ah ","gha","je "," lu","hol","aw'"," ji","ong","pu'","aj ","vad","w' ","' j","ha'","is ","tah","' '","ang","h '","pon","am ","law","mo'","qu'","hbe","ol ","vam","agh","mu'","ahv","bej","ogh","uch","' v","ach","hug"," lo"," qu","cho","hva","ij "," la","lu'","vis"," ne"," pu"," so"," ta"," va","'ac","di'","hu'","lah","moh"," 'o","' m","daq","hah","n h","neh","u'm","ay'","gho","h v","meh","oy "," ma"," nu","'me","el "," ba"," be"," de"," ng","' t","h d","hvi","oq "," wa","' l","'wi","hme","li'","uq "," bo","bog","del","h p","h t","ich","vil"," qe"," wi","ahb","ban","eng","haq","hoh","ov ","viq"," ha"," ti","' n","' p","'a'","hwi","igh","lo'","y' "," du"," no"," yu","'mo","'va","daj","das","egh","hom","muc","om ","otl","us "," bi"," tu","' h","chm","h q","hov","nis","qar","uj ","' q","'ch","h m","hmo","jih","par","wij"," hu","' d","'a ","etl","h g","h j","h l","lod","maq","och","wa'","yuq"," di"," le"," pe"," ya","'di","che","ech","ih ","ija","in ","j '","j m","lhw","pa'"," 'i"," mi"," qi"," ro"," ru","'be","anp","ghi","ghu","h b","hay","hch","iq ","npu","od ","paq","qay","rda","soh"," do"," me"," qo"," sa","' c","' g","' s","'lu","aml","ard","as ","d p","gme","h n","hta","i'v","j j","jij","len","ngm","qan","qme","vaj","wiv"," mo"," ni","'la","'pu","'qu","ar ","arm","dwi","g p","ghd","h c","ham","hla","hqu","ilo","iqa","iqi","j p","j t","j v","lad","lho","mar","mug","pus","q s","q t","rgh","rma","sov","ta'","tin","tu'","u'd","vet","yli","yu'"," to","'oh","aqq","art","at ","ayl","ayt","et ","haj","har");
+$GLOBALS["ngrams"]['tn'] = array(" di"," le","go ","le "," go","ng "," ts","ya "," ya","sa ","tlh"," mo"," bo","a m","lo ","tsa"," e ","o t","a b","wa "," ka","a k","a t","ka ","a g","eng","olo","o y","la "," a ","a d","ets","mo ","se "," tl"," ba","tsh"," ma","ba ","a l","tse","so ","na ","elo"," se","ele","e d","o l","lho","e t","di ","e g"," kg","dit","kgo","o k","ang","lha","e m","e e","we ","ane","o m","e k","e l","ong","set","wan","ela","tso","tla","o d","e b","ola","ngw","gwe","o b","aba","atl","a p"," o ","a a","o a","otl","a s","o e","dir","thu","ga "," ga","shw","ots","aka","hab","hwa","aga","o g","gan","tsw","ana","mol"," ke","hut"," me","ona","lel","its","lao","kga","dik","got"," fa","let"," wa","ose","no ","t h","swe","edi","ats","a n","e s","oko","oth","kwa","kar"," th","a e","ala","tir","o n","dip","isa","gat","ti ","ano","bot"," nn"," ha","len","alo","any","aro","iti","iri","o s","sen","net","ke ","ho ","mai","ika","eka","to ","ith","re ","g m","hat","bo ","g l","et ","emo","ama","iso","rol","fa ","iwa","kan","she","si ","ao ","g k","wen","lol","o o","bos","itl","a y","the","lwa","e n"," la","ore"," mm","ko ","tha","e a","eo ","lhe","bol","ha "," po","isi","i b","lan"," na","i t","ale","ne ","gon","ris","ira","bon"," sa","g y","g g","pha","oga","mel","ro ","gol","o w"," kw","i l"," ti","tlo","log","por"," ja","a f"," ne","hok","lot"," pu","e y","uto","g t","hom","okg"," ko","o f","ame","gor","ta "," pe","nts"," kh","tho","gel","adi","are","ete","ase","mon","heo","oro","omo","nen","nel","ile","nng","ntl","abo","ogo","ara","nse","ego","hel","uo ","mog","san","ula","rag","kol","te ","etl","bat"," te","puo","amo","ofe","lat","ati","ole","rab","tsi","iro","man","ael","ega","lwe","ra ","din","tle","sek","ing","yo ","a o"," re","aot","uso","o r","ere","jwa","aem","lam","lek"," jw","gwa","mok");
+$GLOBALS["ngrams"]['tr'] = array("lar","en ","ler","an ","in "," bi"," ya","eri","de "," ka","ir ","arı"," ba"," de"," ha","ın ","ara","bir"," ve"," sa","ile","le ","nde","da "," bu","ana","ini","ını","er ","ve "," yı","lma","yıl"," ol","ar ","n b","nda","aya","li ","ası"," ge","ind","n k","esi","lan","nla","ak ","anı","eni","ni ","nı ","rın","san"," ko"," ye","maz","baş","ili","rin","alı","az ","hal","ınd"," da"," gü","ele","ılm","ığı","eki","gün","i b","içi","den","kar","si "," il","e y","na ","yor","ek ","n s"," iç","bu ","e b","im ","ki ","len","ri ","sın"," so","ün "," ta","nin","iği","tan","yan"," si","nat","nın","kan","rı ","çin","ğı ","eli","n a","ır "," an","ine","n y","ola"," ar","al ","e s","lik","n d","sin"," al"," dü","anl","ne ","ya ","ım ","ına"," be","ada","ala","ama","ilm","or ","sı ","yen"," me","atı","di ","eti","ken","la ","lı ","oru"," gö"," in","and","e d","men","un ","öne","a d","at ","e a","e g","yar"," ku","ayı","dan","edi","iri","ünü","ği ","ılı","eme","eği","i k","i y","ıla"," ça","a y","alk","dı ","ede","el ","ndı","ra ","üne"," sü","dır","e k","ere","ik ","imi","işi","mas","n h","sür","yle"," ad"," fi"," gi"," se","a k","arl","aşı","iyo","kla","lığ","nem","ney","rme","ste","tı ","unl","ver"," sı"," te"," to","a s","aşk","ekl","end","kal","liğ","min","tır","ulu","unu","yap","ye ","ı i","şka","ştı"," bü"," ke"," ki","ard","art","aşa","n i","ndi","ti ","top","ı b"," va"," ön","aki","cak","ey ","fil","isi","kle","kur","man","nce","nle","nun","rak","ık "," en"," yo","a g","lis","mak","n g","tir","yas"," iş"," yö","ale","bil","bul","et ","i d","iye","kil","ma ","n e","n t","nu ","olu","rla","te ","yön","çık"," ay"," mü"," ço"," çı","a a","a b","ata","der","gel","i g","i i","ill","ist","ldı","lu ","mek","mle","n ç","onu","opl","ran","rat","rdı","rke","siy","son","ta ","tçı","tın");
+$GLOBALS["ngrams"]['ts'] = array(" ku","ku ","na ","ka ","wa ","a n"," sw","a m","ya ","a k"," ti","swi","hi ","la "," ya"," le"," hi","a t","a v"," va","ni "," na","ndz"," ma","a h"," xi","a s","i n","ele","i k","ana","a l","nga","lo ","va ","le ","aka","ela","irh","eka"," vu","iwa","a x"," ka","yi "," wa","isa","sa ","ko ","ta ","ga ","wu ","wi ","tir"," ek"," mi"," ni","o y","elo","awu","isi","swa","i t","hla","a e"," ta"," ng"," la","a y","ri ","eri"," ri","rhi","eke","umb","u t","ndl"," yi","lan","i v","esw","mbe","i l","a r","e k","ang","les","ula","ti ","yon","o w","ona","law","xa ","nel","yo ","lel","iko"," lo","amb"," a ","i y"," xa","ane","wan","i s","ond","fan","end","i h","o l","u k","mbi","n'w","ke ","dyo"," fa","lam","nhl","o s","ong","no "," ko","u n"," ha","ho ","oko","u h","i m","o n"," yo","ngu","o k","u y","ati","u l","van","ulu","and","mba","kum","u v","wo ","be ","ha ","riw","dza","si "," en","o h"," hl","o t","eyi"," nt","ila","lok","dzi","nge"," mu","ala","to ","a w"," by","arh","aku","tsa","wak","rho","'wa"," nd","min","lav","tim","ley","tik","dle","tin","mat","ler","let","sel","his","mel","lu ","ika","a a","ngo","eng","o x"," nk","amu","siw","ani","eni","ma "," nh","mi ","swo","eti","tan","mo ","ham","iwe"," kh","han","lek","nti","ung","hak","dzo","ete"," ts","ava","hu ","fum","kar","vul"," wu","kul","und","i x","nhu","yis","xik","bis","xi ","e y","ra ","hle"," hu","wek","ano","yen","a d","sis","olo","pfu","i w","nyi","e n","so ","ki ","fun","iso","tsh","kon","nku","hel","i b","e h","ari","imi","i e","ind","vum","nts","ime","kom","mfu","ise"," mf","hin","dla","vut","gan","i r","ban","bya","mil","int","ats"," dy","u s","e x","ile","kel","kwa"," no","i f","asi","za ","uri","o m","rha","e l","in'","eta","von","i a","kho"," wo","iki"," ra","u e","o e","zo ","yin","ink","any","ket");
+$GLOBALS["ngrams"]['uk'] = array(" на"," за","ння","ня ","на "," пр","ого","го ","ськ"," по"," у ","від","ере"," мі"," не","их ","ть ","пер"," ві","ів "," пе"," що","льн","ми ","ні ","не ","ти ","ати","енн","міс","пра","ува","ник","про","рав","івн"," та","буд","влі","рів"," ко"," рі","аль","но ","ому","що "," ви","му ","рев","ся ","інн"," до"," уп","авл","анн","ком","ли ","лін","ног","упр"," бу"," з "," ро","за ","и н","нов","оро","ост","ста","ті ","ють"," мо"," ні"," як","бор","ва ","ван","ень","и п","нь ","ові","рон","сті","та ","у в","ько","іст"," в "," ре","до ","е п","заб","ий ","нсь","о в","о п","при","і п"," ку"," пі"," сп","а п","або","анс","аці","ват","вни","и в","ими","ка ","нен","ніч","она","ої ","пов","ьки","ьно","ізн","ічн"," ав"," ма"," ор"," су"," чи"," ін","а з","ам ","ає ","вне","вто","дом","ент","жит","зни","им ","итл","ла ","них","ниц","ова","ови","ом ","пор","тьс","у р","ься","ідо","іль","ісь"," ва"," ді"," жи"," че"," і ","а в","а н","али","вез","вно","еве","езе","зен","ицт","ки ","ких","кон","ку ","лас","ля ","мож","нач","ним","ної","о б","ову","оди","ою ","ро ","рок","сно","спо","так","тва","ту ","у п","цтв","ьни","я з","і м","ії "," вс"," гр"," де"," но"," па"," се"," ук"," їх","а о","авт","аст","ают","вар","ден","ди ","ду ","зна","и з","ико","ися","ити","ког","мен","ном","ну ","о н","о с","обу","ово","пла","ран","рив","роб","ска","тан","тим","тис","то ","тра","удо","чин","чни","і в","ію "," а "," во"," да"," кв"," ме"," об"," ск"," ти"," фі"," є ","а р","а с","а у","ак ","ані","арт","асн","в у","вик","віз","дов","дпо","дів","еві","енс","же ","и м","и с","ика","ичн","кі ","ків","між","нан","нос","о у","обл","одн","ок ","оло","отр","рен","рим","роз","сь ","сі ","тла","тів","у з","уго","уді","чи ","ше ","я н","я у","ідп","ій ","іна","ія "," ка"," ни"," ос"," си"," то"," тр"," уг");
+$GLOBALS["ngrams"]['ur'] = array("یں "," کی","کے "," کے","نے "," کہ","ے ک","کی ","میں"," می","ہے ","وں ","کہ "," ہے","ان ","ہیں","ور "," کو","یا "," ان"," نے","سے "," سے"," کر","ستا"," او","اور","تان","ر ک","ی ک"," اس","ے ا"," پا"," ہو"," پر","رف "," کا","ا ک","ی ا"," ہی","در ","کو "," ای","ں ک"," مش"," مل","ات ","صدر","اکس","شرف","مشر","پاک","کست","ی م"," دی"," صد"," یہ","ا ہ","ن ک","وال","یہ ","ے و"," بھ"," دو","اس ","ر ا","نہی","کا ","ے س","ئی ","ہ ا","یت ","ے ہ","ت ک"," سا","لے ","ہا ","ے ب"," وا","ار ","نی ","کہا","ی ہ","ے م"," سی"," لی","انہ","انی","ر م","ر پ","ریت","ن م","ھا ","یر "," جا"," جن","ئے ","پر ","ں ن","ہ ک","ی و","ے د"," تو"," تھ"," گی","ایک","ل ک","نا ","کر ","ں م","یک "," با","ا ت","دی ","ن س","کیا","یوں","ے ج","ال ","تو ","ں ا","ے پ"," چا","ام ","بھی","تی ","تے ","دوس","س ک","ملک","ن ا","ہور","یے "," مو"," وک","ائی","ارت","الے","بھا","ردی","ری ","وہ ","ویز","ں د","ھی ","ی س"," رہ"," من"," نہ"," ور"," وہ"," ہن","ا ا","است","ت ا","ت پ","د ک","ز م","ند ","ورد","وکل","گی ","گیا","ہ پ","یز ","ے ت"," اع"," اپ"," جس"," جم"," جو"," سر","اپن","اکث","تھا","ثری","دیا","ر د","رت ","روی","سی ","ملا","ندو","وست","پرو","چاہ","کثر","کلا","ہ ہ","ہند","ہو ","ے ل"," اک"," دا"," سن"," وز"," پی","ا چ","اء ","اتھ","اقا","اہ ","تھ ","دو ","ر ب","روا","رے ","سات","ف ک","قات","لا ","لاء","م م","م ک","من ","نوں","و ا","کرن","ں ہ","ھار","ہوئ","ہی ","یش "," ام"," لا"," مس"," پو"," پہ","انے","ت م","ت ہ","ج ک","دون","زیر","س س","ش ک","ف ن","ل ہ","لاق","لی ","وری","وزی","ونو","کھن","گا ","ں س","ں گ","ھنے","ھے ","ہ ب","ہ ج","ہر ","ی آ","ی پ"," حا"," وف"," گا","ا ج","ا گ","اد ","ادی","اعظ","اہت","جس ","جمہ","جو ","ر س","ر ہ","رنے","س م","سا ","سند","سنگ","ظم ","عظم","ل م","لیے","مل ","موہ","مہو","نگھ","و ص","ورٹ","وہن","کن ","گھ ","گے ","ں ج","ں و","ں ی","ہ د","ہن ","ہوں","ے ح","ے گ","ے ی"," اگ"," بع"," رو"," شا");
+$GLOBALS["ngrams"]['uz'] = array("ан ","ган","лар","га ","нг ","инг","нин","да ","ни ","ида","ари","ига","ини","ар ","ди "," би","ани"," бо","дан","лга"," ҳа"," ва"," са","ги ","ила","н б","и б"," кў"," та","ир "," ма","ага","ала","бир","ри ","тга","лан","лик","а к","аги","ати","та ","ади","даг","рга"," йи"," ми"," па"," бў"," қа"," қи","а б","илл","ли ","аси","и т","ик ","или","лла","ард","вчи","ва ","иб ","ири","лиг","нга","ран"," ке"," ўз","а с","ахт","бўл","иги","кўр","рда","рни","са "," бе"," бу"," да"," жа","а т","ази","ери","и а","илг","йил","ман","пах","рид","ти ","увч","хта"," не"," со"," уч","айт","лли","тла"," ай"," фр"," эт"," ҳо","а қ","али","аро","бер","бил","бор","ими","ист","он ","рин","тер","тил","ун ","фра","қил"," ба"," ол","анс","ефт","зир","кат","мил","неф","саг","чи ","ўра"," на"," те"," эн","а э","ам ","арн","ат ","иш ","ма ","нла","рли","чил","шга"," иш"," му"," ўқ","ара","ваз","и у","иқ ","моқ","рим","учу","чун","ши ","энг","қув","ҳам"," сў"," ши","бар","бек","дам","и ҳ","иши","лад","оли","олл","ори","оқд","р б","ра ","рла","уни","фт ","ўлг","ўқу"," де"," ка"," қў","а ў","аба","амм","атл","б к","бош","збе","и в","им ","ин ","ишл","лаб","лей","мин","н д","нда","оқ ","р м","рил","сид","тал","тан","тид","тон","ўзб"," ам"," ки","а ҳ","анг","анд","арт","аёт","дир","ент","и д","и м","и о","и э","иро","йти","нсу","оди","ор ","си ","тиш","тоб","эти","қар","қда"," бл"," ге"," до"," ду"," но"," пр"," ра"," фо"," қо","а м","а о","айд","ало","ама","бле","г н","дол","ейр","ек ","ерг","жар","зид","и к","и ф","ий ","ило","лди","либ","лин","ми ","мма","н в","н к","н ў","н ҳ","ози","ора","оси","рас","риш","рка","роқ","сто","тин","хат","шир"," ав"," рў"," ту"," ўт","а п","авт","ада","аза","анл","б б","бой","бу ","вто","г э","гин","дар","ден","дун","иде","ион","ирл","ишг","йха","кел","кўп","лио");
+$GLOBALS["ngrams"]['ve'] = array("ha "," vh","a m","na "," u ","a n","tsh","wa ","a u"," na","nga","vha"," ts"," dz"," kh","dza","a v","ya "," ya","a t","ho ","la "," zw"," mu","edz","vhu","ga ","shi","za ","a k"," ng","kha"," ma","hum","ne "," nd","o n","lo ","dzi","shu"," ha","a d","o y","nda","ele","zwi","aho","ang","no "," a ","ela","a z","hu ","sha","i n"," wa","ana","hi ","kan","o d","ano","a h","zwa"," th"," mi","gan","a l","sa ","han","di ","u t","and","ndi","yo ","the","do ","ri ","vho","ni ","ka ","uri","si ","o t","mbe","o w","ane","we ","zo ","i t","e n","i h","she","ush","o k","zi ","da ","a a","thu"," la","a p","zan"," i ","a s","lwa","ula","i d","aka"," do","mis","hed","ita","li "," hu","iwa"," lu","i v","he "," ka","elo","so ","amb","avh"," sh","o v","i k","lel","u v","dzo","u s"," fh","mo ","nwe","o l","umi","wah","isi","hel","a i","vel","adz","tan","i m","ath","thi","wi "," ur","hat","ine","le ","vhe","any","a y","hon","isa","ala","o a","alu","udi","umb"," bv","ash"," te"," li","lus","nya","has","led","swa","hus","o i","umo","one","nde","tha"," it","kho","ngo","mus","hak","e y","ea ","ivh","o m","u n","hin","tho","mut","ayo","fhi"," sa","tel","hul","hun","ulo","ith","ma "," yo","lan","e v"," ph","go ","i a","o u","hud"," pf","uka","zhi","uvh","dzw","ing","elw","ila","wo ","mbo","u d","ite","isw","asi","e k","ndu","fhe","o h","mel","u b","ika","bo ","gud","dzh","kon","ifh"," ta","e d","uth"," ho","i z","wan","ulu","mad","inw","oth","ani","dis","wit","ou ","bve","ets","u i","adi","e m","fha","nah","dal","win"," si","sho"," in","yam","lay","eka","a f","i u","end","i y","alo","i l","uso","mul","ta ","del","u k"," mb","pha"," di","dad","ali","o s","pfu","khw","e a"," ko"," ne","hen","mas","ume","ini","ish","udz","ira","oni","luk","nel","iso","mba","dzu","hom","i s","zwo","ngu","ara","unz");
+$GLOBALS["ngrams"]['xh'] = array("la "," ku","lo ","nga","a k"," ng","oku"," kw"," uk","a n","uku","ye ","a i","yo ","ela","ele","a u","nye","we ","wa ","ama","e n","ise","aba","ba ","ho ","enz","o n","ngo","kub","nge","ath","fun","o e","lel","ung","uba","ko ","elo","ezi","o k","the","kwa","na ","kwe","ang","e i","le ","ka ","esi","o y"," na","e k","eth","pha"," in","kun","nzi","and","ni ","ban"," ye"," no","lwa","lun"," ok","any","zi ","li "," ne","ulu","a e","eli","gok","o l","ebe","und","isa","seb","ndo"," ez","tho","o i","do ","ben","ing","kwi","ndl","uny","ala","a a","eyo","e u","kan"," ab","thi","i k","i n","o u","o z","elw","sa ","sek","ayo","het","o o","eka"," um","hi ","bo ","so ","isi","wen","lwe","aph","a l","ya ","eko","ana"," yo","kuf","ini","imi","ali","ha ","awu","wan","ent","uth","tha","za ","ula","kho"," ii","ane","e a","iso","uph"," le","ile","zin","nts"," si","eng","nok","ong","hla","zwe"," el","oka","eki","lis","azi"," lo","tsh"," am","ufu","ant","isw","o a","ngu","o s"," ba","int","eni","une","wul","hul","sel","i e","use","lan","ke ","nis","emi"," li"," is","iph"," im","a o","aka","mfu"," zi","ink","mal","ley","man","nya","nek","akh","ume"," ko","alo","tu ","i u","ntu","izw","kel","izi","i i","si ","gan","ase","ind","i a","ndi","nel","alu","sis","ubo","kut","mth","kus","lek","mis","nde"," zo"," we","ani","ga ","iko","siz","no ","phu","e e","hon","ond","ne ","ith","kul","gam","gen","pho"," iz","phe","hat","khu","iin","han","zo ","lu ","ulo","nda","qo ","zik","hel","o m"," lw","zis","dle","uhl","men","olo","mel","del","nza","oko","okw","olu","kuk","nte","swa","law","enk"," ya","i y","gaq","sha","aqo","e l","ikh","nkq","ule"," ka","onk","thu","wo ","bon","kup","qub","a y","kqu","dla"," es","he ","ano","lum","be ","iga"," ze","o w","aku","mga","nke","te "," ol","ze ","kum","emf","esh");
+$GLOBALS["ngrams"]['zu'] = array("oku","la ","nga"," ng","a n"," ku","a k","thi"," uk","ezi","e n","uku","le ","lo ","hi ","wa "," no","a u","ela","we ","a i","ni ","ele","zin","uth","ama","elo","pha","ing","aba","ath","and","enz","eth","esi","ma ","lel"," um"," ka","the","ung","nge","ngo","tho","nye","kwe","eni","izi","ye "," kw","ndl","ho ","a e","na ","zi ","het","kan","e u","e i","und","ise","isi","nda","kha","ba ","i k","nom","fun"," ez"," iz","ke ","ben","o e","isa","zwe","kel","ka ","aka","nzi","o n","e k","oma","kwa"," ne","any","ang","hla","i u","mth","kub","o k","ana","ane","ikh","ebe","kut","ha "," is","azi","ulu","seb","ala","onk","ban","i e","azw","wen"," ab","han","a a","i n","imi","lan","hat","lwa"," na","ini","akh","li ","ngu","nke","nok","ume","eke","elw","yo ","aph","kus"," es"," ok","iph"," im","mel","i i"," lo"," in"," am","kho","za ","gok","sek","lun","kun","lwe","sha","sik","kuf","hak","a y","thu","sa ","o u","khu","ayo","hul","e a","ali","eng","lu ","ne "," ko","eli","uba","dle","e e","ith"," yo","a l","nel","mis"," si","kul","a o","sis","lok","gen","o z","i a","emi","uma","eka","alo","man","isw","tha","o i","lon","so ","uph","uhl","ntu","zim","mal","ind","wez"," ba","o o"," yi"," we","ula","phe","o y","ile","o l","wo ","wel","ga ","tu ","hle","okw","fan"," le","kaz","ase","ani","nde","bo ","ngi","ule"," em","men","iny","amb","mbi","gan","ifu","o s","ant","hel","ika","ona","i l","fut"," fu","ze ","u a","nhl","nin"," zo","end","sig","u k","gab","ufa","ish","ush","kuz","no ","gam","kuh"," ye","nya","nez","zis","dlu","kat","dla","tsh"," se","ike","kuq","gu ","osi","swa","lul"," zi","ima","e l","kup","mo ","nza","asi","ko ","kum","lek","she","umt","uny","yok","wan","wam","ame","ong","lis","mkh","ahl","ale","use","o a","alu","gap","si ","hlo","nje","omt","o w","okh","he ","kom","i s");
+
+function createNGrams($string, $ng_number=300, $ng_max_chars=4) {
+
+       // Attention: $string n'est pas un mot, mais le texte complet
+       // On va le couper pour éviter les timeout, 
+       // mais il faut qu'il reste suffisamment long pour que la détection reste qualitative
+       // Au passage: on fait les calculs en multibyte.
+       $string = mb_substr($string, 0, 5000, "utf-8");
+       
+       // Attention: il faut traiter les chaines en utf-8 !!!
+    //iterate over each word, each character, all possible n-grams
+       $word = " ". $string . " ";
+       $length = mb_strlen($word, "utf-8");
+       for ($pos=0; $pos < $length; $pos++){ //start position within word
+               $chars = 3;
+               if (($pos + $chars) < $length) { //if not beyond end of word
+                        $array_ngram[] = mb_substr($word, $pos, $chars, "utf-8");
+                }
+        }
+    //count-> value(frequency, int)... key(ngram, string)
+    $ng_frequency = array_count_values($array_ngram);
+    //sort array by value(frequency) desc
+    arsort($ng_frequency);
+    //use only top frequent ngrams
+    $most_frequent = array_slice($ng_frequency, 0, $ng_number);
+    foreach ($most_frequent as $ng => $number_frequencey){
+        $sub_ng[] = $ng;
+    }
+    
+    return $sub_ng;
+}
+function compareNGrams($sub_ng, $lm_ng, $max_delta = 140000) {
+    foreach ($lm_ng as $lm_basename => $language) {
+        $delta = 0;
+        //compare each ngram of input text to current lm-array
+        foreach ($sub_ng as $key => $existing_ngram){
+            //match
+            if(in_array($existing_ngram, $language)) {
+                $delta += abs($key - array_search($existing_ngram, $language));
+            //no match
+            } else {
+                $delta += 400;
+            }
+            //abort: this language already differs too much
+            if ($delta > $max_delta) {
+                break;
+             }
+        } // End comparison with current language
+        //include only non-aborted languages in result array
+        if ($delta < ($max_delta - 400)) {
+            $result[$lm_basename] = $delta;
+        }
+    } //End comparison all languages
+    if(!isset($result)) {
+      $result = '';
+    } else {
+        asort($result);
+    }
+    return $result;
+}
+
+
+function tester_plage_utf($texte, $plage) {
+       
+       $total = mb_strlen($texte, "UTF-8");
+       
+       $test = mb_strlen(
+                               preg_replace("/".$plage."/ui", "", $texte),
+                               "UTF-8"
+                       );
+//     echo "<h4>".($test / $total)."<h4> ";
+       return ($test / $total);
+       
+}
+
+function detecter_plages_utf($texte) {
+
+       if (tester_plage_utf($texte, "[\x{0041}-\x{024F}\x{1E00}-\x{1EFF}]") < 0.5) { 
+               // Latin
+               return array("fr", "en", "de", "it", "es", 'af','br','ca','ceb',"da","fi","nl","nr","pt","pt_BR","pt_PT","sk","ha","haw","hr","pl","cs","az","cy","et","ro","eu","hu","id","is","la","lt","lv","nb","nso","sl","so","sq","ss","st","sv","sw","tl","tlh","tn","tr","ts","ve","xh","zu");
+       } else if (tester_plage_utf($texte, "[\x{0400}-\x{0523}]") < 0.5) { 
+               // Cyrillique
+               return array("ru","bg","kk","uk", "ky","mn", "uz","mk","sr");
+       } else  if (tester_plage_utf($texte, "[\x{0370}-\x{03ff}\x{1F00}-\x{1FFE}]") < 0.5) { 
+               // Grec/Copte
+               return "el";
+       } else  if (tester_plage_utf($texte, "[\x{0530}-\x{058A}]") < 0.5) { 
+               // Armenien
+               return "hy";
+       } else  if (tester_plage_utf($texte, "[\x{0590}-\x{05F4}]") < 0.5) { 
+               // Hebreux
+               return "he";
+       } else  if (tester_plage_utf($texte, "[\x{0600}-\x{077F}]") < 0.5) { 
+               // Arabe-farsi-pachtoune-urdu
+               return array("ar","fa", "ps","ur");
+       } else  if (tester_plage_utf($texte, "[\x{3040}-\x{30FF}]") < 0.7) { 
+               // Japonais (hiragana / katakana)
+               return "ja";
+       } else  if (tester_plage_utf($texte, "[\x{4E00}-\x{9FBB}\x{4E00}–\x{9FBF}]") < 0.7) { 
+               // Chinois
+               return "zh";
+       } else  if (tester_plage_utf($texte, "[\x{0E00}-\x{0E5B}]") < 0.5) { 
+               // Thai
+               return "th";
+       } else  if (tester_plage_utf($texte, "[\x{1100}-\x{11F8}\x{3130}-\x{318E}\x{AC00}-\x{D7A3}]") < 0.5) { 
+               // Hangul  - Koreen
+               return "ko";
+       }
+       
+       return false;
+}
+
+
+// Detecter langue
+
+// Premiere passe: detecter dans quel alphabet le texte est écrit
+// ce qui permet de limiter le nombre de réponse 
+// (par exemple: des caractères «arabes» ne peuvent être que de l'arabe, du farsi, du pachtourne ou du urdu)
+// Deuxieme passe: faire un test classique sur les trigrams (uniquement sur les langues possibles de la première passe)
+
+function _detecter_langue($texte) {
+       $texte = strip_tags($texte);
+       $texte = str_replace("’", "'", $texte);
+       $texte = str_replace("\"", " ", $texte);
+       
+       // Si texte trop court, impossible de détecter la langue
+       if (mb_strlen($texte, "utf-8") < 6 ) return false; 
+
+       $possibles = detecter_plages_utf($texte);
+       
+       if (!$possibles) return;
+       else if (!is_array($possibles)) {
+               return $possibles;
+       } else {
+               $ngrams = array();
+               foreach($possibles as $lang) {
+                       $ngrams["$lang"] = $GLOBALS["ngrams"]["$lang"];
+               }
+       }
+       
+    $sub_ng = createNGrams($texte);
+
+    $result_array = compareNGrams($sub_ng, $ngrams, 140000);
+       
+//     print_r($result_array);
+       
+       $resultat = false;
+       if ($result_array) {
+               foreach($result_array as $lang => $val) {
+                       if (!$resultat) $resultat = $lang;
+               }
+       }
+       return $resultat;
+}
+
+
+
+
+?>
\ No newline at end of file
diff --git a/www/plugins/nospam/inc/nospam.php b/www/plugins/nospam/inc/nospam.php
new file mode 100644 (file)
index 0000000..16e508a
--- /dev/null
@@ -0,0 +1,258 @@
+<?php
+/**
+ * Plugin No-SPAM
+ * (c) 2008 Cedric Morin Yterium.net
+ * Licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function nospam_hash_env() {
+       static $res ='';
+       if ($res) return $res;
+       $ip = explode('.',$GLOBALS['ip']);
+       array_pop($ip);
+       $ip = implode('.',$ip).".xxx";
+       $res = md5($ip. $_SERVER['HTTP_USER_AGENT']);
+       #spip_log("jeton $res pour ".$ip. $_SERVER['HTTP_USER_AGENT'],"jetons");
+       return $res;
+}
+
+
+/**
+ * Calcule une cle de jeton pour un formulaire
+ *
+ * @param string $form
+ *   nom du formulaire
+ * @param string $qui
+ *   identifiant du visiteur a qui est attribue le jeton
+ * @return string
+ *   cle calculee
+ */
+function creer_jeton($form, $qui=NULL) {
+       $time = date('Y-m-d-H');
+       if (is_null($qui)){
+               if (isset($GLOBALS['visiteur_session']['id_auteur']) AND intval($GLOBALS['visiteur_session']['id_auteur']))
+                       $qui = ":".$GLOBALS['visiteur_session']['id_auteur'].":".$GLOBALS['visiteur_session']['nom'];
+               elseif (!defined('_IS_BOT') OR !_IS_BOT) { // pas de jeton pour les bots qui n'ont rien d'interessant a poster
+                       $qui = nospam_hash_env();
+               }
+       }
+       include_spip('inc/securiser_action');
+       // le jeton prend en compte l'heure et l'identite de l'internaute
+       return calculer_cle_action("jeton$form$time$qui");
+}
+
+/**
+ * Verifie une cle de jeton pour un formulaire
+ *
+ * @param string $form nom du formulaire
+ * @param string cle recue
+ * @return bool cle correcte ?
+ */
+function verifier_jeton($jeton, $form, $qui=NULL) {
+       $time = time();
+       $time_old = date('Y-m-d-H',$time-3600);
+       $time = date('Y-m-d-H',$time);
+
+       if (is_null($qui)){
+               if (isset($GLOBALS['visiteur_session']['id_auteur']) AND intval($GLOBALS['visiteur_session']['id_auteur']))
+                       $qui = ":".$GLOBALS['visiteur_session']['id_auteur'].":".$GLOBALS['visiteur_session']['nom'];
+               else {
+                       $qui = nospam_hash_env();
+               }
+       }
+       
+       $ok = (verifier_cle_action("jeton$form$time$qui",$jeton)
+                       or verifier_cle_action("jeton$form$time_old$qui",$jeton));
+       #if (!$ok)
+       #       spip_log("Erreur form:$form qui:$qui agent:".$_SERVER['HTTP_USER_AGENT']." ip:".$GLOBALS['ip'],'fauxjeton');
+       return $ok;
+}
+
+
+/**
+ * Compte le nombre de caracteres d'une chaine,
+ * mais en supprimant tous les liens 
+ * (qu'ils soient ou non ecrits en raccourcis SPIP)
+ * ainsi que tous les espaces en trop
+ *
+ * @param string $texte
+ *   texte d'entree
+ * @param bool $propre
+ *   passer le texte dans propre ou non
+ * @return int
+ *   compte du texte nettoye
+ */
+function compter_caracteres_utiles($texte, $propre=true) {
+       include_spip('inc/charsets');
+       if ($propre) $texte = propre($texte);
+       $u = $GLOBALS['meta']['pcre_u'];
+       // regarder si il y a du contenu en dehors des liens !
+       $texte = PtoBR($texte);
+       $texte = preg_replace(",<a.*</a>,{$u}Uims",'',$texte);
+       // \W matche tous les caracteres non ascii apres 0x80
+       // et vide donc les chaines constitues de caracteres unicodes uniquement
+       // on remplace par un match qui elimine uniquement
+       // les non \w  et les non unicodes
+       $texte = trim(preg_replace(",[^\w\x80-\xFF]+,ims",' ',$texte));
+
+       // on utilise spip_strlen pour compter la longueur correcte
+       // pour les chaines unicodes
+       return spip_strlen($texte);
+}
+
+
+/**
+ * Retourne un tableau d'analyse du texte transmis
+ * Cette analyse concerne principalement des statistiques sur les liens
+ *
+ * @param string $texte texte d'entree
+ * @return array rapport d'analyse
+ */
+function analyser_spams($texte) {
+       $infos = array(
+               'caracteres_utiles' => 0, // nombre de caracteres sans les liens
+               'nombre_liens' => 0, // nombre de liens
+               'caracteres_texte_lien_min' => 0, // nombre de caracteres du plus petit titre de lien
+       );
+
+       if (!$texte) return $infos;
+
+       // on travaille d'abord sur le texte 'brut' tel que saisi par
+       // l'utilisateur pour ne pas avoir les class= et style= que spip ajoute
+       // sur les raccourcis.
+       
+       // on ne tient pas compte des blocs <code> et <cadre> ni de leurs contenus
+       include_spip("inc/texte_mini");
+       if (!function_exists('echappe_html')) // SPIP 2.x
+               include_spip("inc/texte");
+       $texte_humain = echappe_html($texte);
+       // on repère dans ce qui reste la présence de style= ou class= qui peuvent
+       // servir à masquer du contenu
+       // les spammeurs utilisent le laxisme des navigateurs pour envoyer aussi style =
+       // soyons donc mefiant
+       // (mais en enlevant le base64 !)
+       $texte_humain = str_replace('class="base64"','',$texte_humain);
+       $hidden = ",\s(?:style|class)\s*=[^>]+>,UimsS";
+       if (preg_match($hidden,$texte_humain)) {
+               // suspicion de spam
+               $infos['contenu_cache'] = true;
+       }
+
+       include_spip('inc/texte');
+       $texte = propre($texte);
+
+       // caracteres_utiles
+       $infos['caracteres_utiles'] = compter_caracteres_utiles($texte, false);
+
+       // nombre de liens
+       $liens = array_filter(extraire_balises($texte,'a'),'pas_lien_ancre');
+       $infos['nombre_liens'] = count($liens);
+       $infos['liens'] = $liens;
+
+       // taille du titre de lien minimum
+       if (count($liens)) {
+               // supprimer_tags() s'applique a tout le tableau,
+               // mais attention a verifier dans le temps que ca continue a fonctionner
+               # $titres_liens = array_map('supprimer_tags', $liens);
+               $titres_liens = supprimer_tags($liens);
+               $titres_liens = array_map('strlen', $titres_liens);
+               $infos['caracteres_texte_lien_min'] = min($titres_liens);
+       }
+       return $infos;
+}
+
+/**
+ * Vérifier si un lien est *n'est pas* une ancre : dans ce cas, ne pas le compte (ici, fonction de filtre de tableau)
+ * Cette analyse concerne principalement des statistiques sur les liens
+ *
+ * @param string $texte lien
+ * @return boolean : true -> 
+ */
+function pas_lien_ancre($texte){
+       return substr(extraire_attribut($texte,'href'),0,1) == '#' ? false : true;
+               
+}
+
+/**
+ * Compare les domaines des liens fournis avec la presence dans la base
+ *
+ * @param array $liens
+ *   liste des liens html
+ * @param int $seuil
+ *   seuil de detection de presence : nombre d'enregistrement qui ont deja un lien avec le meme domaine
+ * @param string $table
+ *   table sql
+ * @param array $champs
+ *   champs a prendre en compte dans la detection
+ * @param null|string $condstatut
+ *   condition sur le statut='spam' pour ne regarder que les enregistrement en statut spam
+ * @return bool
+ */
+function rechercher_presence_liens_spammes($liens,$seuil,$table,$champs,$condstatut=null){
+       include_spip("inc/filtres");
+
+       if (is_null($condstatut))
+               $condstatut = "statut=".sql_quote('spam');
+       if ($condstatut)
+               $condstatut = "$condstatut AND ";
+
+       // limiter la recherche au mois precedent
+       $trouver_table = charger_fonction("trouver_table","base");
+       if ($desc = $trouver_table($table)
+         AND isset($desc['date'])){
+               $depuis = date('Y-m-d H:i:s',strtotime("-1 month"));
+               $condstatut .= $desc['date'].">".sql_quote($depuis)." AND ";
+       }
+
+       // ne pas prendre en compte les liens sur le meme domaine que celui du site
+       $allowed = array();
+       $tests = array($GLOBALS['meta']['adresse_site'],url_de_base());
+       foreach ($tests as $t){
+               if ($parse = parse_url($t)
+                       AND $parse['host']){
+                       $host = explode(".",$parse['host']);
+                       while (count($host)>2) array_shift($host);
+                       $allowed[] = implode(".",$host);
+               }
+       }
+       if (count($allowed)){
+               $allowed = array_map('preg_quote',$allowed);
+               $allowed = implode("|",$allowed);
+               $allowed = "/($allowed)$/";
+               spip_log("domaines whitelist pour les liens spams : $allowed","nospam");
+       }
+       else
+               $allowed = "";
+
+
+       $hosts = array();
+       foreach ($liens as $lien){
+               $url = extraire_attribut($lien,"href");
+               if ($parse = parse_url($url)
+                 AND $parse['host']
+                 AND (!$allowed OR !preg_match($allowed,$parse['host'])))
+                       $hosts[] = $parse['host'];
+       }
+
+       $hosts = array_unique($hosts);
+       $hosts = array_filter($hosts);
+
+       // pour chaque host figurant dans un lien, regarder si on a pas deja eu des spams avec ce meme host
+       // auquel cas on refuse poliment le message
+       foreach($hosts as $h){
+               $like = " LIKE ".sql_quote("%$h%");
+               $where = $condstatut . "(".implode("$like OR ",$champs)."$like)";
+               if (($n=sql_countsel($table,$where))>=$seuil){
+                       // loger les 10 premiers messages concernes pour aider le webmestre
+                       $all = sql_allfetsel(id_table_objet($table),$table,$where,'','','0,10');
+                       $all = array_map('reset',$all);
+                       spip_log("$n liens trouves $like dans table $table (".implode(",",$all).") [champs ".implode(',',$champs)."]","nospam");
+                       return $h;
+               }
+       }
+       return false;
+}
+?>
diff --git a/www/plugins/nospam/inclure/nobot.html b/www/plugins/nospam/inclure/nobot.html
new file mode 100644 (file)
index 0000000..06f4cc9
--- /dev/null
@@ -0,0 +1,5 @@
+[(#REM) Piege a robots spammeurs ]
+<p style="display: none;">
+       <label for="nobot"><:antispam_champ_vide:></label>
+       <input type="text" class="text" name="nobot" id="nobot" value="#ENV{nobot}" size="10" />
+</p>
diff --git a/www/plugins/nospam/lang/nospam.xml b/www/plugins/nospam/lang/nospam.xml
new file mode 100644 (file)
index 0000000..4c3e268
--- /dev/null
@@ -0,0 +1,19 @@
+<traduction module="nospam" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/nospam/lang/" reference="fr">
+       <langue code="ar" url="http://trad.spip.net/tradlang_module/nospam?lang_cible=ar">
+               <traducteur nom="George" lien="http://trad.spip.net/auteur/جورج-قندلفت" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/nospam?lang_cible=en">
+               <traducteur nom="Benitron" lien="http://trad.spip.net/auteur/benitron" />
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/nospam?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/nospam?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/nospam?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/nospam/lang/nospam_ar.php b/www/plugins/nospam/lang/nospam_ar.php
new file mode 100644 (file)
index 0000000..f8d1883
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/nospam?lang_cible=ar
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_attributs_html_interdits' => 'Il n\'est pas permis d\'utiliser les attributs html <tt>class</tt> ou <tt>style</tt>', # NEW
+       'erreur_blacklist' => 'Vous avez été mis sur liste noire, vous ne pouvez plus poster de message.', # NEW
+       'erreur_jeton' => 'غير قادر على مراعاة رسالتك. أشكركم للإعادة !',
+       'erreur_spam' => 'غير قادر على الأخذ في الاعتبار لرسالتك !',
+       'erreur_spam_doublon' => 'وجود رسالة مماثلة !',
+       'erreur_spam_ip' => 'تعليقات كثيرة جدا هي على حساب الجودة !',
+       'erreur_url_deja_spammee' => 'Ce message contient des liens suspects qui ressemblent à du SPAM. Merci de les retirer.', # NEW
+
+       // F
+       'forum_saisie_texte_info' => 'لتنسيق رسالتك، لا تدعم هذه الاستمارة الا اختصارات SPIP مثل <code>[-&gt;url] {{أسود}} {مائل}&lt;quote&gt; &lt;رموز برمجية&gt;</code> &lt;إطار&gt;</cadre> وعلامات HTML كـ<code>&lt;q&gt; &lt;del&gt; &lt;ins&gt;</code>. لإنشاء فقرات، يكفي ترك أسطر فارغة.'
+);
+
+?>
diff --git a/www/plugins/nospam/lang/nospam_en.php b/www/plugins/nospam/lang/nospam_en.php
new file mode 100644 (file)
index 0000000..9e9cd91
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/nospam?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_attributs_html_interdits' => 'It\'s not allowed to use the html attributes <tt>class</tt> or <tt>style</tt>',
+       'erreur_blacklist' => 'You have been blacklisted, you can not post messages anymore.',
+       'erreur_jeton' => 'Unable to take account of your message. Thank you to resubmit!',
+       'erreur_spam' => 'Unable to take account of your message!',
+       'erreur_spam_doublon' => 'An identical message already exists!',
+       'erreur_spam_ip' => 'Too many comments detrimental to the quality!',
+       'erreur_url_deja_spammee' => 'This message contains suspicious links that look like SPAM. Thanks to delete them.',
+
+       // F
+       'forum_saisie_texte_info' => 'For the formatting of your message, this form only accepts SPIP shortcuts <code>[-&gt;url] {{bold}} {italic} &lt;quote&gt; &lt;code&gt;</code> &lt;cadre&gt;</cadre> et le code HTML <code>&lt;q&gt; &lt;del&gt; &lt;ins&gt;</code>. To create paragraphs, simply leave blank lines.'
+);
+
+?>
diff --git a/www/plugins/nospam/lang/nospam_es.php b/www/plugins/nospam/lang/nospam_es.php
new file mode 100644 (file)
index 0000000..c53a9af
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/nospam?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_attributs_html_interdits' => 'No está permitido el uso de atributos html <tt>class</tt> ou <tt>style</tt>',
+       'erreur_blacklist' => 'Usted ha sido metido en lista negra, no puede enviar más mensaje.',
+       'erreur_jeton' => 'Su mensaje no ha sido tomado en cuenta. ¡Gracias por enviarlo de nuevo!',
+       'erreur_spam' => '¡Imposible tomar en cuenta su mensaje!',
+       'erreur_spam_doublon' => '¡Un mensaje idéntico ya existe!',
+       'erreur_spam_ip' => '¡Demasiados comentarios perjudiciales para la calidad!',
+       'erreur_url_deja_spammee' => 'Este mensaje contiene enlaces sospechos de ser SPAM. Gracias por eliminarlos.',
+
+       // F
+       'forum_saisie_texte_info' => 'Para aplicar el formato de su mensaje, este formulario no acepta más que los atajos SPIP <code>[-&gt;url] {{gras}} {italique} &lt;quote&gt; &lt;code&gt;</code> &lt;cadre&gt;</cadre> et le code HTML <code>&lt;q&gt; &lt;del&gt; &lt;ins&gt;</code>. Para crear párrafos, deje simplemente una línea vacía entre los mismos.'
+);
+
+?>
diff --git a/www/plugins/nospam/lang/nospam_fa.php b/www/plugins/nospam/lang/nospam_fa.php
new file mode 100644 (file)
index 0000000..7cfff64
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/nospam?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_attributs_html_interdits' => 'Il n\'est pas permis d\'utiliser les attributs html <tt>class</tt> ou <tt>style</tt>', # NEW
+       'erreur_blacklist' => 'Vous avez été mis sur liste noire, vous ne pouvez plus poster de message.', # NEW
+       'erreur_jeton' => 'روي پيام شما نمي‌توان حساب كرد. ممنون مكرر فرماييد!',
+       'erreur_spam' => 'نمي‌توان روي پيام شما حساب كرد!',
+       'erreur_spam_doublon' => 'يك پيام شناخته شده موجود است!',
+       'erreur_spam_ip' => 'نظرات زيادي به زيان كيفيت!',
+       'erreur_url_deja_spammee' => 'Ce message contient des liens suspects qui ressemblent à du SPAM. Merci de les retirer.', # NEW
+
+       // F
+       'forum_saisie_texte_info' => 'اين فرم ميان‌ برهاي اسپيپ  <code>[-&gt;url] {{gras}} {italique} &lt;quote&gt; &lt;code&gt;</code>و  كد اچ.تي.ام.ال را <code>&lt;q&gt; &lt;del&gt; &lt;ins&gt;</code> مي‌پذيرد . براي ساختن پارگراف فقط يك سطر خالي بگذاريد. '
+);
+
+?>
diff --git a/www/plugins/nospam/lang/nospam_fr.php b/www/plugins/nospam/lang/nospam_fr.php
new file mode 100644 (file)
index 0000000..8e921e1
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/nospam/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_attributs_html_interdits' => 'Il n\'est pas permis d\'utiliser les attributs html <tt>class</tt> ou <tt>style</tt>',
+       'erreur_blacklist' => 'Vous avez été mis sur liste noire, vous ne pouvez plus poster de message.',
+       'erreur_jeton' => 'Impossible de prendre en compte votre message. Merci de le soumettre à nouveau !',
+       'erreur_spam' => 'Impossible de prendre en compte votre message !',
+       'erreur_spam_doublon' => 'Un message identique existe déjà !',
+       'erreur_spam_ip' => 'Trop de commentaires nuit à la qualité !',
+       'erreur_url_deja_spammee' => 'Ce message contient des liens suspects qui ressemblent à du SPAM. Merci de les retirer.',
+
+       // F
+       'forum_saisie_texte_info' => 'Pour la mise en forme de votre message, ce formulaire n\'accepte que les raccourcis SPIP <code>[-&gt;url] {{gras}} {italique} &lt;quote&gt; &lt;code&gt;</code> &lt;cadre&gt;</cadre> et le code HTML <code>&lt;q&gt; &lt;del&gt; &lt;ins&gt;</code>. Pour créer des paragraphes, laissez simplement des lignes vides.'
+);
+
+?>
diff --git a/www/plugins/nospam/lang/nospam_sk.php b/www/plugins/nospam/lang/nospam_sk.php
new file mode 100644 (file)
index 0000000..9f14e60
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/nospam?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_attributs_html_interdits' => 'Nie je povolené používať atribúty html <tt>class</tt> alebo <tt>style</tt>',
+       'erreur_blacklist' => 'Zaradili vás na čiernu listinu, nemôžete posielať správy.',
+       'erreur_jeton' => 'Vaša správa sa nedá posúdiť. Ďakujeme vám, že ju pošlete znova.',
+       'erreur_spam' => 'Vaša správa sa nedá posúdiť.',
+       'erreur_spam_doublon' => 'Rovnaká správa už existuje!',
+       'erreur_spam_ip' => 'Príliš veľa komentárov znižuje kvalitu!',
+       'erreur_url_deja_spammee' => 'V tejto správe sú podozrivé odkazy, ktoré vyzerajú ako spam. Ďakujeme vám za ich odstránenie.',
+
+       // F
+       'forum_saisie_texte_info' => 'Na formátovanie správy tento formulár akceptuje iba skratky SPIPu <code>[-&gt;url] {{tučné}} {kurzíva} &lt;quote&gt; &lt;code&gt;</code> &lt;cadre&gt;</cadre> a kód HTML <code>&lt;q&gt; &lt;del&gt; &lt;ins&gt;</code>. Ak chcete robiť odseky, jednoducho vynechajte niekoľko prázdnych riadkov.'
+);
+
+?>
diff --git a/www/plugins/nospam/lang/paquet-nospam.xml b/www/plugins/nospam/lang/paquet-nospam.xml
new file mode 100644 (file)
index 0000000..b9d200a
--- /dev/null
@@ -0,0 +1,9 @@
+<traduction module="paquet-nospam" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/nospam/lang/" reference="fr">
+       <langue code="ar" />
+       <langue code="de" />
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-nospam?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+</traduction>
diff --git a/www/plugins/nospam/lang/paquet-nospam_ar.php b/www/plugins/nospam/lang/paquet-nospam_ar.php
new file mode 100644 (file)
index 0000000..fceacb9
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-nospam?lang_cible=ar
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'nospam_description' => 'توقف المتطفل! فلتر البريد المزعج في الرسائل ، دون ازعاج لمستخدم صادق.',
+       'nospam_slogan' => 'Limiter le risque de spams dans les forums' # NEW
+);
+
+?>
diff --git a/www/plugins/nospam/lang/paquet-nospam_de.php b/www/plugins/nospam/lang/paquet-nospam_de.php
new file mode 100644 (file)
index 0000000..310a81c
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-nospam?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'nospam_description' => 'SPAM stoppen! Ein Filter ohne Nebenwirkungen für ehrliche Nutzer.',
+       'nospam_slogan' => 'Limiter le risque de spams dans les forums' # NEW
+);
+
+?>
diff --git a/www/plugins/nospam/lang/paquet-nospam_en.php b/www/plugins/nospam/lang/paquet-nospam_en.php
new file mode 100644 (file)
index 0000000..d2740f5
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-nospam?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'nospam_description' => 'Stop spam! Filter spam in messages, without nuisance to honest users.',
+       'nospam_slogan' => 'Reduce the risk of spams in the forums'
+);
+
+?>
diff --git a/www/plugins/nospam/lang/paquet-nospam_es.php b/www/plugins/nospam/lang/paquet-nospam_es.php
new file mode 100644 (file)
index 0000000..38d98f2
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-nospam?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'nospam_description' => 'Detenga el spam! Filtro de spam en los mensajes, sin molestias a los usuarios honestos.',
+       'nospam_slogan' => 'Limitar el riesgo de spams en los foros'
+);
+
+?>
diff --git a/www/plugins/nospam/lang/paquet-nospam_fr.php b/www/plugins/nospam/lang/paquet-nospam_fr.php
new file mode 100644 (file)
index 0000000..8439f6f
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/nospam/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'nospam_description' => 'Halte au spam ! Filtrez les spams dans les messages, sans nuisance pour les utilisateurs honnêtes.',
+       'nospam_slogan' => 'Limiter le risque de spams dans les forums'
+);
+
+?>
diff --git a/www/plugins/nospam/nospam/verifier_formulaire_ecrire_auteur.php b/www/plugins/nospam/nospam/verifier_formulaire_ecrire_auteur.php
new file mode 100644 (file)
index 0000000..d284048
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+
+/**
+ * Plugin No-SPAM
+ * (c) 2008 Cedric Morin Yterium.net
+ * Licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Verification supplementaire antispam sur le formulaire_ecrire_auteur
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_verifier_formulaire_ecrire_auteur_dist($flux){
+       $form = $flux['args']['form'];
+       if (!isset($flux['data']['texte_message_auteur'])){
+               include_spip("inc/nospam");
+               include_spip("inc/texte");
+               // regarder si il y a du contenu en dehors des liens !
+               $texte_message_auteur = _request('texte_message_auteur');
+               $caracteres = compter_caracteres_utiles($texte_message_auteur);
+               if ($caracteres < 10){
+                       $flux['data']['texte_message_auteur'] = _T('forum_attention_dix_caracteres');
+                       unset($flux['data']['previsu']);
+               }
+               // on analyse le sujet
+               $infos_sujet = analyser_spams(_request('sujet_message_auteur'));
+               // si un lien dans le sujet = spam !
+               if ($infos_sujet['nombre_liens'] > 0){
+                       $flux['data']['sujet_message_auteur'] = _T('nospam:erreur_spam');
+                       unset($flux['data']['previsu']);
+               }
+
+               // on analyse le texte
+               $infos_texte = analyser_spams($texte_message_auteur);
+               if ($infos_texte['nombre_liens'] > 0) {
+                       // si un lien a un titre de moins de 3 caracteres = spam !
+                       if ($infos_texte['caracteres_texte_lien_min'] < 3) {
+                               $flux['data']['texte_message_auteur'] = _T('nospam:erreur_spam');
+                       }
+                       // si le texte contient plus de trois liens = spam !
+                       if ($infos_texte['nombre_liens'] >= 3)
+                               $flux['data']['texte_message_auteur'] = _T('nospam:erreur_spam');
+               }
+       }
+
+       return $flux;
+}
\ No newline at end of file
diff --git a/www/plugins/nospam/nospam/verifier_formulaire_forum.php b/www/plugins/nospam/nospam/verifier_formulaire_forum.php
new file mode 100644 (file)
index 0000000..7edc683
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * Plugin No-SPAM
+ * (c) 2008 Cedric Morin Yterium.net
+ * Licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Verification supplementaire antispam sur le formulaire_forum
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_verifier_formulaire_forum_dist($flux){
+       $form = $flux['args']['form'];
+       if (!isset($flux['data']['texte'])
+               AND $GLOBALS['meta']['forums_texte'] == 'oui'){
+
+               $texte = _request('texte');
+               include_spip("inc/nospam");
+               // regarder si il y a du contenu en dehors des liens !
+               $caracteres = compter_caracteres_utiles($texte);
+               $min_length = (defined('_FORUM_LONGUEUR_MINI') ? _FORUM_LONGUEUR_MINI : 10);
+               if ($caracteres < $min_length){
+                       $flux['data']['texte'] = _T('forum_attention_dix_caracteres');
+               }
+
+               // regarder si il y a du contenu cache
+               if (!isset($flux['data']['texte'])){
+                       $infos = analyser_spams($texte);
+                       if (isset($infos['contenu_cache']) AND $infos['contenu_cache']){
+                               $flux['data']['texte'] = _T('nospam:erreur_attributs_html_interdits');
+                       }
+               }
+
+               // regarder si il y a des liens deja references par des spammeurs
+               if (!isset($flux['data']['texte'])
+                 AND isset($infos['liens'])
+                 AND count($infos['liens'])){
+
+
+                       if ($h = rechercher_presence_liens_spammes($infos['liens'],_SPAM_URL_MAX_OCCURENCES,'spip_forum',array('texte'))){
+                               spip_log("Refus message de forum qui contient un lien vers $h","nospam");
+                               $flux['data']['texte'] = _T('nospam:erreur_url_deja_spammee');
+                       }
+               }
+
+               if (isset($flux['data']['texte']))
+                       unset($flux['data']['previsu']);
+       }
+
+       return $flux;
+}
\ No newline at end of file
diff --git a/www/plugins/nospam/nospam/verifier_formulaire_signature.php b/www/plugins/nospam/nospam/verifier_formulaire_signature.php
new file mode 100644 (file)
index 0000000..7695e65
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Plugin No-SPAM
+ * (c) 2008 Cedric Morin Yterium.net
+ * Licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Verification supplementaire antispam sur le formulaire_signature
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_verifier_formulaire_signature_dist($flux){
+       $form = $flux['args']['form'];
+       $id_article = $flux['args']['args'][0];
+       $row = sql_fetsel('*', 'spip_petitions', "id_article=".intval($id_article));
+       if ((!isset($flux['data']['message'])) && ($row['message']  == "oui")){
+               include_spip("inc/nospam");
+               include_spip("inc/texte");
+               // regarder si il y a du contenu en dehors des liens !
+               $message = _request('message');
+               // on analyse le texte
+               $infos_texte = analyser_spams($message);
+               if ($infos_texte['nombre_liens'] > 0) {
+                       // si un lien a un titre de moins de 3 caracteres = spam !
+                       if ($infos_texte['caracteres_texte_lien_min'] < 3) {
+                               $flux['data']['message_erreur'] = _T('nospam:erreur_spam');
+                       }
+                       // si le texte contient plus de trois liens = spam !
+                       if ($infos_texte['nombre_liens'] >= 2)
+                               $flux['data']['message_erreur'] = _T('nospam:erreur_spam');
+               }
+       }
+       // S'il y a un lien dans le champ session_nom => spam
+       if (!isset($flux['data']['session_nom'])){
+               include_spip("inc/nospam");
+               $infos_texte = analyser_spams(_request('session_nom'));
+               if ($infos_texte['nombre_liens'] > 0) {
+                       $flux['data']['message_erreur'] = _T('nospam:erreur_spam');
+                       spip_log("Lien dans le champ session_nom ".$flux['data']['message_erreur'],'nospam');
+               }
+       }
+       return $flux;
+}
\ No newline at end of file
diff --git a/www/plugins/nospam/nospam_pipelines.php b/www/plugins/nospam/nospam_pipelines.php
new file mode 100644 (file)
index 0000000..0a7dec3
--- /dev/null
@@ -0,0 +1,372 @@
+<?php
+/**
+ * Plugin No-SPAM
+ * (c) 2008-2011 Cedric Morin Yterium.net
+ * Licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+if (!defined('_SPAM_URL_MAX_OCCURENCES')) define('_SPAM_URL_MAX_OCCURENCES',3);
+
+/**
+ * Lister les formulaires a prendre en charge contre le SPAM
+ * pour verifier le nobot et le jeton sur un formulaire, l'ajouter a cette liste
+ * par le pipeline nospam_lister_formulaires
+ * @return void
+ */
+function nospam_lister_formulaires() {
+       if (!isset($GLOBALS['formulaires_no_spam']))
+               $GLOBALS['formulaires_no_spam'] = array();
+       $formulaires = array_merge($GLOBALS['formulaires_no_spam'], array('forum', 'ecrire_auteur', 'signature'));
+       return pipeline('nospam_lister_formulaires', $formulaires);
+}
+
+/**
+ * Ajouter le champ de formulaire 'nobot' au besoin
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_recuperer_fond($flux) {
+       // determiner le nom du formulaire
+       $fond = strval($flux['args']['fond']);
+       if (false !== $pos = strpos($fond, 'formulaires/')) {
+               $form = substr($fond, $pos + 12);
+               if (in_array($form, nospam_lister_formulaires())) {
+                       // on ajoute le champ 'nobot' si pas present dans le formulaire
+                       $texte = &$flux['data']['texte'];
+                       if ((false === strpos($texte, 'name="nobot"'))
+                               and (false !== $pos = strpos($texte, '</form>'))
+                       ) {
+                               $nobot = recuperer_fond("inclure/nobot", array('nobot' => ''));
+                               $texte = substr_replace($texte, $nobot, $pos, 0);
+                       }
+               }
+       }
+       return $flux;
+}
+
+/**
+ * Ajouter un jeton temporaire lie a l'heure et a l'IP pour limiter la reutilisation possible du formulaire
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_formulaire_charger($flux) {
+       $form = $flux['args']['form'];
+       if (in_array($form, nospam_lister_formulaires())
+               AND $flux['data']
+                       AND is_array($flux['data'])
+       ) {
+               include_spip("inc/nospam");
+               $jeton = creer_jeton($form);
+               $flux['data']['_hidden'] .= "<input type='hidden' name='_jeton' value='$jeton' />";
+       }
+       return $flux;
+}
+
+/**
+ * Verifier le jeton temporaire lie a l'heure et a l'IP pour limiter la reutilisation possible du formulaire
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_formulaire_verifier($flux) {
+       $form = $flux['args']['form'];
+       if (in_array($form, nospam_lister_formulaires())) {
+               include_spip("inc/nospam");
+               $jeton = _request('_jeton');
+               // le jeton prend en compte l'heure et l'ip de l'internaute
+               if (_request('nobot') // trop facile !
+                       OR (!verifier_jeton($jeton, $form))
+               ) {
+                       #spip_log('pas de jeton pour '.var_export($flux,true),'nospam');
+                       $flux['data']['message_erreur'] .= _T('nospam:erreur_jeton');
+                       if ($form == 'forum')
+                               unset($flux['data']['previsu']);
+               }
+
+               // pas la peine de filtrer les contenus postés par un admin
+               if (!isset($GLOBALS['visiteur_session']['statut']) OR $GLOBALS['visiteur_session']['statut'] != '0minirezo') {
+                       if ($verifier_formulaire = charger_fonction("verifier_formulaire_$form", "nospam", true)) {
+                               $flux = $verifier_formulaire($flux);
+                               // recuperation de la liste des IPs blacklist/greylist
+                               // async si on renvoie la previsu ou si erreur
+                               $async = false;
+                               if (count($flux['data']))
+                                       $async = true;
+                               nospam_update_ip_list($async);
+                       }
+               }
+       }
+       return $flux;
+}
+
+/**
+ * Au moment de decider du statut d'un forum,
+ * quelques verifications et une moderation si necessaire !
+ *
+ * @param array $flux
+ * @return array
+ */
+function nospam_pre_edition($flux) {
+       if ($flux['args']['table'] == 'spip_forum'
+               AND $flux['args']['action'] == 'instituer'
+       ) {
+
+               // ne pas publier automatiquement certains messages suspects ...
+               // sauf si le posteur a de toute facon le pouvoir de moderer et de se publier
+               include_spip('inc/autoriser');
+               if ($flux['data']['statut'] == 'publie'
+                       AND (!isset($GLOBALS['visiteur_session']['statut']) OR !autoriser('modererforum'))
+               ) {
+                       // verifier le status de cette IP
+                       nospam_check_ip_status($GLOBALS['ip']);
+
+                       $email = strlen($flux['data']['email_auteur']) ? " OR email_auteur=" . sql_quote($flux['data']['email_auteur']) : "";
+                       $spammeur_connu = (!isset($GLOBALS['visiteur_session']['statut'])
+                               AND (
+                                       isset($GLOBALS['ip_greylist'][$GLOBALS['ip']])
+                                       OR isset($GLOBALS['ip_blacklist'][$GLOBALS['ip']])
+                                       OR sql_countsel('spip_forum', '(ip=' . sql_quote($GLOBALS['ip']) . "$email) AND statut='spam'") > 0
+                               )
+                       );
+
+                 // activer aussi le flag spammeur connu en cas de flood, meme si aucune detection spam jusqu'ici
+                 // on sera plus severe sur les liens dans ce cas
+                 // cas du spammeur qui envoie que des messages a 3 liens a haute frequence (passe a travers tous les filtres)
+                 // au bout du 5e message en <10min ou 10e en <30min on va moderer tout message avec un lien
+                 if (!$spammeur_connu){
+                         if (($nb=sql_countsel('spip_forum','(ip='.sql_quote($GLOBALS['ip']).$email.') AND '.sql_date_proche('date_heure','-30','minute')))>=7){
+                         spip_log("[Flood] $nb message pour (ip=".$GLOBALS['ip']."$email) dans les 30 dernieres minutes",'nospam');
+                         $spammeur_connu = true;
+                         }
+                 }
+                 if (!$spammeur_connu){
+                         if (($nb=sql_countsel('spip_forum','(ip='.sql_quote($GLOBALS['ip']).$email.') AND '.sql_date_proche('date_heure','-10','minute')))>=3){
+                         spip_log("[Flood] $nb message pour (ip=".$GLOBALS['ip']."$email) dans les 10 dernieres minutes",'nospam');
+                         $spammeur_connu = true;
+                         }
+                 }
+
+                       $lang_suspecte = false;
+                       // si c'est un spammeur connu,
+                       // verifier que cette ip n'en est pas a son N-ieme spam en peu de temps
+                       // a partir d'un moment on refuse carrement le spam massif, le posteur devra attendre pour reposter
+                       if ($spammeur_connu) {
+                               // plus de 30 spams dans les dernieres 2h, faut se calmer ...
+                               // ou plus de 10 spams dans la dernieres 1h, faut se calmer ...
+                               // ou IP blacklistee et plus de 5 messages prop/spam dans les dernieres 24h, faut se calmer ...
+                               if (
+                                       (isset($GLOBALS['ip_blacklist'][$GLOBALS['ip']])
+                                  AND ($nb = sql_countsel('spip_forum', sql_in('statut',array('spam')).' AND (ip=' . sql_quote($GLOBALS['ip']).') AND ' . sql_date_proche('date_heure','-24','hour'))) >= 5
+                                        AND $h=24
+                                       )
+                                       OR
+                                       (($nb = sql_countsel('spip_forum', 'statut=\'spam\' AND (ip=' . sql_quote($GLOBALS['ip']) . $email . ') AND ' . sql_date_proche('date_heure','-120','minute'))) >= 30
+                                               AND $h=2)
+                                       OR
+                                       (($nb = sql_countsel('spip_forum', 'statut=\'spam\' AND (ip=' . sql_quote($GLOBALS['ip']) . $email .') AND ' . sql_date_proche('date_heure','-60','minute'))) >= 10
+                                               AND $h=1)
+                                       ){
+                                       $flux['data']['statut'] = ''; // on n'en veut pas !
+                                       spip_log("[Refuse] $nb spam pour (ip=" . $GLOBALS['ip'] . "$email) dans les $h dernieres heures", 'nospam');
+                                       return $flux;
+                               }
+                       }
+                       // sinon regarder si l'objet a une langue, et si le post est dans la meme langue ou non
+                       // en cas de langue differente, on se mefie
+                       elseif ($flux['data']['objet']){
+                               $table = table_objet_sql($flux['data']['objet']);
+                               $trouver_table = charger_fonction("trouver_table","base");
+                               if ($desc = $trouver_table($table)
+                                 AND isset($desc['field']['lang'])){
+                                       $primary = id_table_objet($flux['data']['objet']);
+                                       $lang_objet = sql_getfetsel("lang",$table,"$primary=".intval($flux['data']['id_objet']));
+                                       include_spip("inc/detecter_langue");
+                                       $lang_post = _detecter_langue($flux['data']['texte']);
+                                       if ($lang_post!==$lang_objet)
+                                               $lang_suspecte = true;
+                               }
+                       }
+
+                       // si c'est un message bourre de liens, on le modere
+                       // le seuil varie selon le champ et le fait que le spammeur est deja connu ou non
+                       $seuils = array(
+                               // seuils par defaut
+                               0 => array(
+                                       0 => array(1 => 'prop', 3 => 'spam'), // seuils par defaut
+                                       'url_site' => array(2 => 'spam'), // 2 liens dans le champ url, c'est vraiment louche
+                                       'texte' => array(4 => 'prop', 20 => 'spam') // pour le champ texte
+                               ),
+                               // seuils severises pour les suspects : modere en prop des qu'il y a un lien, spam si plus de 5
+                               'suspect' => array(
+                                       0 => array(1 => 'spam'),
+                                       'url_site' => array(2 => 'spam'), // 2 liens dans le champ url, c'est vraiment louche
+                                       'texte' => array(1 => 'prop', 5 => 'spam')
+                               ),
+                               // seuils pour les blacklist : si pas de lien on passe en prop par precaution, sinon en spam
+                               'blacklist' => array(
+                                       0 => array(1 => 'spam'),
+                                       'url_site' => array(2 => 'spam'), // 2 liens dans le champ url, c'est vraiment louche
+                                       'texte' => array(0 => 'prop', 1 => 'spam')
+                               )
+                       );
+
+                       $seuils = isset($GLOBALS['ip_blacklist'][$GLOBALS['ip']])? $seuils['blacklist'] : (($spammeur_connu OR $lang_suspecte) ? $seuils['suspect'] : $seuils[0]);
+                       include_spip("inc/nospam"); // pour analyser_spams()
+                       foreach ($flux['data'] as $champ => $valeur) {
+                               $infos = analyser_spams($valeur);
+                               if ($infos['contenu_cache']) {
+                                       // s'il y a du contenu caché avec des styles => spam direct
+                                       $flux['data']['statut'] = 'spam';
+                                       spip_log("\t" . $flux['data']['auteur'] . "\t" . $GLOBALS['ip'] . "\t" . "requalifié en spam car contenu cache", 'nospam');
+                               }
+                               elseif ($infos['nombre_liens'] > 0) {
+                                       // si un lien a un titre de moins de 3 caracteres, c'est louche...
+                                       if ($infos['caracteres_texte_lien_min'] < 3) {
+                                               $flux['data']['statut'] = 'prop'; // en dur en attendant une idee plus generique
+                                               spip_log("\t" . $flux['data']['auteur'] . "\t" . $GLOBALS['ip'] . "\t" . "requalifié en prop car moins de 3car hors liens", 'nospam');
+                                       }
+
+                                       if (isset($seuils[$champ]))
+                                               $seuil = $seuils[$champ];
+                                       else
+                                               $seuil = $seuils[0];
+
+                                       foreach ($seuil as $s => $stat)
+                                               if ($infos['nombre_liens'] >= $s) {
+                                                       $flux['data']['statut'] = $stat;
+                                                       spip_log("\t" . $flux['data']['auteur'] . "\t" . $GLOBALS['ip'] . "\t" . "requalifié en " . $stat . " car nombre_liens >= " . $s, 'nospam');
+                                               }
+
+                                       if ($flux['data']['statut'] != 'spam') {
+                                               $champs = array_unique(array('texte', $champ));
+                                               if ($h = rechercher_presence_liens_spammes($infos['liens'], _SPAM_URL_MAX_OCCURENCES, 'spip_forum', $champs)) {
+                                                       $flux['data']['statut'] = 'spam';
+                                                       spip_log("\t" . $flux['data']['auteur'] . "\t" . $GLOBALS['ip'] . "\t" . "requalifié en spam car lien $h deja dans un spam", 'nospam');
+                                               }
+                                       }
+                               }
+                       }
+
+
+                       // verifier qu'un message identique n'a pas ete publie il y a peu
+                       if ($flux['data']['statut'] != 'spam') {
+                               if (sql_countsel('spip_forum', 'texte=' . sql_quote($flux['data']['texte']) . " AND statut IN ('publie','off','spam')") > 0){
+                                       $flux['data']['statut'] = 'spam';
+                                       spip_log("\t" . $flux['data']['auteur'] . "\t" . $GLOBALS['ip'] . "\t" . "requalifié en spam car message identique deja existant", 'nospam');
+                               }
+                       }
+                       // verifier que cette ip n'en est pas a son N-ieme post en peu de temps
+                       // plus de 5 messages en 5 minutes c'est suspect ...
+                       if ($flux['data']['statut'] != 'spam') {
+                               if (($nb = sql_countsel('spip_forum', 'ip=' . sql_quote($GLOBALS['ip']) . ' AND ' . sql_date_proche('date_heure','-5','minute'))) >= 5){
+                                       $flux['data']['statut'] = 'spam';
+                                       spip_log("[Flood2] $nb message pour (ip=".$GLOBALS['ip']."$email) dans les 5 dernieres minutes : requalif en spam",'nospam');
+                               }
+                       }
+               }
+       }
+       return $flux;
+}
+
+
+
+/**
+ * Fermer la connexion pour que le visiteur n'attende pas apres le curl sur nospam.spip.net
+ * @param $content
+ * @return mixed
+ */
+function nospam_flush_close($content){
+       header("Content-Length: ".($l=ob_get_length()));
+       header("Connection: close");
+       return $content;
+}
+
+/**
+ * Flusher et lancer l'update de la liste des ip
+ */
+function nospam_flush_and_update(){
+       chdir(_ROOT_CWD); // securite en cas de register_shutdown_function
+       // forcer le flush des tampons pas envoyes (declenche le content-length/conection:close envoye dans cache_cool_flush)
+       $flush_level = ob_get_level();
+       while ($flush_level--) ob_end_flush();
+       flush();
+       if (function_exists('fastcgi_finish_request'))
+               fastcgi_finish_request();
+       nospam_update_ip_list();
+}
+
+if (!defined('_NOSPAM_IP_LIST_CACHE')) define('_NOSPAM_IP_LIST_CACHE',10800);
+/**
+ * Recuperer la liste des IP black ou grey sur nospam.spip.net
+ * si on a pas une liste a jour
+ * et la stocker dans un fichier
+ * @param bool $async
+ */
+function nospam_update_ip_list($async=false){
+       $file = _DIR_TMP."nospam_ip_list.txt";
+       if (file_exists($file) AND filemtime($file)>time()-_NOSPAM_IP_LIST_CACHE)
+               return;
+       spip_log("nospam_update_ip_list:$async","nospam");
+
+       if ($async){
+               // indiquer de fermer la connexion dans la foulee
+               // pour faire le hit de recuperation async hors temps d'attente
+               ob_start("nospam_flush_close");
+               register_shutdown_function("nospam_flush_and_update");
+               return;
+       }
+
+       // on fait d'abord un touch car si le recuperer_page echoue (hebergeurs qui interdisent)
+       // on ne veut pas recommencer plein de fois de suite
+       @touch($file);
+       $url_api = "http://nospam.spip.net/spamsignal.api/list";
+       include_spip("inc/distant");
+       include_spip("inc/json");
+       $res = recuperer_page($url_api);
+       if ($res
+         AND function_exists("json_decode")
+         AND $liste = json_decode($res,true)){
+               ecrire_fichier($file,serialize($liste));
+       }
+}
+
+/**
+ * Verifier le status d'une IP et la noter dans la globale ip_blacklist ou ip_greylist si c'est une IP louche
+ * @param $ip
+ * @return string
+ *   ok|grey|black
+ */
+function nospam_check_ip_status($ip){
+       $file = _DIR_TMP."nospam_ip_list.txt";
+       if (!file_exists($file) OR filemtime($file)<time()-_NOSPAM_IP_LIST_CACHE)
+               return;
+
+       lire_fichier($file,$liste);
+       spip_log("nospam_check_ip_status:$ip","nospam");
+       if ($liste = unserialize($liste)){
+               #spip_log($liste,"nospam");
+               $now = date('Y-m-d H:i:s');
+               $ip_family = preg_replace(",([.:])[^.:]+$,","$1*",$ip);
+               spip_log("ip $ip famille $ip_family","nospam");
+               foreach(array("blacklist","greylist") AS $l){
+                       if (isset($liste[$l][$ip])
+                               AND $liste[$l][$ip]>$now){
+                               $GLOBALS['ip_'.$l][$ip] = true;
+                               spip_log("$ip ajoute a ip_$l","nospam");
+                               return ($l=="blacklist"?"black":"grey");
+                       }
+                       if (isset($liste[$l][$ip_family])
+                               AND $liste[$l][$ip_family]>$now){
+                               $GLOBALS['ip_'.$l][$ip] = true;
+                               spip_log("$ip ajoute a ip_$l (famille $ip_family)","nospam");
+                               return ($l=="blacklist"?"black":"grey");
+                       }
+               }
+       }
+       return "ok";
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/nospam/paquet.xml b/www/plugins/nospam/paquet.xml
new file mode 100644 (file)
index 0000000..f5a81a3
--- /dev/null
@@ -0,0 +1,25 @@
+<paquet
+       prefix="nospam"
+       categorie="performance"
+       version="1.3.0"
+       etat="stable"
+       compatibilite="[2.0.0;3.0.99]"
+       logo="images/nospam-32.png"
+       documentation="http://www.spip-contrib.net/?rubrique1165"
+>      
+
+       <nom>NoSPAM</nom>
+       <!-- Limiter le risque de spams dans les forums -->
+
+       <auteur lien="www.yterium.net">Yterium</auteur>
+
+       <copyright>2008</copyright>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>
+
+       <pipeline nom="pre_edition" inclure="nospam_pipelines.php" />
+       <pipeline nom="recuperer_fond" inclure="nospam_pipelines.php" />
+       <pipeline nom="formulaire_charger" inclure="nospam_pipelines.php" />
+       <pipeline nom="formulaire_verifier" inclure="nospam_pipelines.php" />
+       <pipeline nom="nospam_lister_formulaires" action="" />
+</paquet>
diff --git a/www/plugins/nospam/plugin.xml b/www/plugins/nospam/plugin.xml
new file mode 100644 (file)
index 0000000..e6d1c33
--- /dev/null
@@ -0,0 +1,45 @@
+<plugin>
+       <nom>NoSPAM</nom>
+       <slogan>
+               <multi>
+               [fr]Limiter le risque de spams dans les forums
+               [en]Reduce the risk of spams in the forums
+               </multi>
+       </slogan>
+       <auteur>Cedric Morin pour [Yterium->www.yterium.net], Superyms (Traduction)</auteur>
+       <icon>images/nospam-32.png</icon>
+       <licence>(c) 2008 GPL</licence>
+       <version>1.3.0</version>
+       <etat>stable</etat>
+       <description><multi>
+       [fr]Halte au spam ! Filtrez les spams dans les messages, sans nuisance pour les utilisateurs honn&#234;tes.
+       [en]Stop spam! Filter spam in messages, without nuisance to honest users.
+       [es]Detenga el spam! Filtro de spam en los mensajes, sin molestias a los usuarios honestos.
+       [ar]&#1578;&#1608;&#1602;&#1601; &#1575;&#1604;&#1605;&#1578;&#1591;&#1601;&#1604;&#33; &#1601;&#1604;&#1578;&#1585; &#1575;&#1604;&#1576;&#1585;&#1610;&#1583; &#1575;&#1604;&#1605;&#1586;&#1593;&#1580; &#1601;&#1610; &#1575;&#1604;&#1585;&#1587;&#1575;&#1574;&#1604; &#1548; &#1583;&#1608;&#1606; &#1575;&#1586;&#1593;&#1575;&#1580; &#1604;&#1605;&#1587;&#1578;&#1582;&#1583;&#1605; &#1589;&#1575;&#1583;&#1602;.
+       [de]SPAM stoppen&#33; Ein Filter ohne Nebenwirkungen f&#252;r ehrliche Nutzer.
+       </multi></description>
+       <lien>http://www.spip-contrib.net/?rubrique1165</lien>
+       <prefix>nospam</prefix>
+       <pipeline>
+               <nom>pre_edition</nom>
+               <inclure>nospam_pipelines.php</inclure>
+       </pipeline>
+       <pipeline>
+               <nom>recuperer_fond</nom>
+               <inclure>nospam_pipelines.php</inclure>
+       </pipeline>
+       <pipeline>
+               <nom>formulaire_charger</nom>
+               <inclure>nospam_pipelines.php</inclure>
+       </pipeline>
+       <pipeline>
+               <nom>formulaire_verifier</nom>
+               <inclure>nospam_pipelines.php</inclure>
+       </pipeline>
+       <pipeline>
+               <nom>nospam_lister_formulaires</nom>
+               <action></action>
+       </pipeline>
+       <categorie>performance</categorie>
+       <necessite id="SPIP" version="[2.0.0;3.0.99]" />
+</plugin>
diff --git a/www/plugins/nospam/svn.revision b/www/plugins/nospam/svn.revision
new file mode 100644 (file)
index 0000000..c565939
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/nospam
+Revision: 73844
+Dernier commit: 2013-06-25 06:00:36 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/nospam</origine>
+<revision>73844</revision>
+<commit>2013-06-25 06:00:36 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/notifications2/action/instituer_forum_paremail.php b/www/plugins/notifications2/action/instituer_forum_paremail.php
new file mode 100644 (file)
index 0000000..78c67aa
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// http://doc.spip.org/@action_instituer_forum_dist
+function action_instituer_forum_paremail_dist() {
+
+       // verification manuelle de la signature : cas particulier de cette action signee par email
+       $arg = _request('arg');
+       $hash = _request('hash');
+
+       include_spip("inc/securiser_action");
+       $action = 'instituer_forum_paremail';
+       $pass = secret_du_site();
+
+       $verif = _action_auteur("$action-$arg", '', $pass, 'alea_ephemere');
+
+       $ae = explode("-",$arg);
+       $id_forum = array_shift($ae);
+       $statut = array_shift($ae);
+       $statut_init = array_shift($ae);
+       // l'email est ce qui reste
+       $email = implode("-",$ae);
+       $message = null;
+       $erreur_auteur = _T('notifications:info_moderation_interdite');
+
+       include_spip("inc/filtres");
+       $lien_moderation = lien_ou_expose(url_absolue(generer_url_entite($id_forum,'forum',"","forum$id_forum",false)),_T('notifications:info_moderation_lien_titre'));
+       $erreur = _T('notifications:info_moderation_url_perimee')."<br />$lien_moderation";
+
+       if ($hash==_action_auteur("$action-$arg", '', $pass, 'alea_ephemere')
+         OR $hash==_action_auteur("$action-$arg", '', $pass, 'alea_ephemere_ancien'))
+               $erreur = "";
+       else {
+               // le hash est invalide, mais peut-etre est-on loge avec cet email ?
+               // auquel cas on peut utiliser les liens, meme perimes (confort)
+               if (isset($GLOBALS['visiteur_session'])
+                 AND $GLOBALS['visiteur_session']['id_auteur']
+                       AND $GLOBALS['visiteur_session']['email']==$email){
+                       $message = sql_fetsel("id_objet,objet,statut","spip_forum","id_forum=".intval($id_forum));
+                       if (autoriser("modererforum",$message['objet'],$message['id_objet'])){
+                               $erreur_auteur = "";
+                               $erreur = "";
+                       }
+               }
+               else
+                       spip_log("Signature incorrecte pour $arg","moderationparemail"._LOG_INFO_IMPORTANTE);
+       }
+
+       // si hash est ok, verifier si l'email correspond a un auteur qui a le droit de faire cette action
+       if (!$erreur){
+               // reconstituer l'arg pour l'action standard
+               $arg = "$id_forum-$statut";
+
+               if (!$message)
+                       $message = sql_fetsel("id_objet,objet,statut","spip_forum","id_forum=".intval($id_forum));
+
+               // on recherche le message en verifiant qu'il a bien le statut
+               if ($message){
+                       if ($message['statut']!=$statut_init){
+                               $erreur = _T("notifications:info_moderation_deja_faite",array('id_forum'=>$id_forum,'statut'=>$message['statut']))
+                                       ."<br />$lien_moderation";
+                       }
+                       else {
+                               // trouver le(s) auteur(s) et verifier leur autorisation si besoin
+                               if ($erreur_auteur){
+                                       $res = sql_select("*","spip_auteurs","email=".sql_quote($email,'','text'));
+                                       while ($auteur = sql_fetch($res)){
+                                               if (autoriser("modererforum",$message['objet'],$message['id_objet'],$auteur)){
+                                                       $erreur_auteur = "";
+                                                       // on ajoute l'exception car on est pas identifie avec cet id_auteur
+                                                       autoriser_exception("modererforum",$message['objet'],$message['id_objet']);
+                                                       break;
+                                               }
+                                       }
+                               }
+                               if ($erreur_auteur){
+                                       $erreur = $erreur_auteur 
+                                         . "<br /><small>"
+                                         . _L("(aucun auteur avec l'email $email n'a de droit suffisant)")
+                                         . "</small>";
+                                       spip_log("Aucun auteur pour $email autorise a moderer $id_forum","moderationparemail"._LOG_INFO_IMPORTANTE);
+                               }
+                       }
+               }
+               else {
+                       spip_log("Message forum $id_forum introuvable","moderationparemail"._LOG_INFO_IMPORTANTE);
+                       $erreur = "Message forum $id_forum introuvable"; // improbable ?
+               }
+       }
+
+       if (!$erreur){
+               spip_log("Moderation message $id_forum $statut par $email","moderationparemail"._LOG_INFO_IMPORTANTE);
+               $instituer_forum = charger_fonction("instituer_forum","action");
+               $instituer_forum($arg);
+       }
+
+       // Dans tous les cas on finit sur un minipres qui dit si ok ou echec
+       $titre = (!$erreur ? _T("notifications:info_moderation_confirmee_$statut",array('id_forum'=>$id_forum)) : $erreur);
+       include_spip('inc/minipres');
+       echo minipres($titre,"","",true);
+
+}
diff --git a/www/plugins/notifications2/content/inc-suivi_forums_date.html b/www/plugins/notifications2/content/inc-suivi_forums_date.html
new file mode 100644 (file)
index 0000000..f3708e2
--- /dev/null
@@ -0,0 +1,20 @@
+
+        [(#REM) Timeline des forums ]
+        <B_forumstimeline>
+        <div class="menu timeline">
+        <h2><:notifications:suivis_public_vos_forums_date:></h2>
+        <ul>
+         <BOUCLE_forumstimeline(FORUMS)
+         {id_auteur=(#SESSION{id_auteur}|sinon{-1})}
+            {!par date_heure}
+            {statut?}
+            {plat}>[#GET{fermeul}
+            <li>(#DATE|annee|unique)<ul>[(#SET{fermeul,</ul></li>})]]
+            [<li><a href="[(#SELF|parametre_url{
+               debut_forums,[(#COMPTEUR_BOUCLE|moins{1})]}
+               )#pagination_forums]">(#DATE|affdate_court|unique)</a></li>
+       ]</BOUCLE_forumstimeline>
+       #GET{fermeul}
+       </ul>
+       </div>
+       </B_forumstimeline>
diff --git a/www/plugins/notifications2/content/notifications.html b/www/plugins/notifications2/content/notifications.html
new file mode 100644 (file)
index 0000000..06bfa30
--- /dev/null
@@ -0,0 +1,5 @@
+<h1><:notifications:notifications:></h1>
+
+<div class="ajax">
+#FORMULAIRE_ABONNER_NOTIFICATIONS{#ENV{email}, #ENV{key}, #SESSION{id_auteur}}
+</div>
\ No newline at end of file
diff --git a/www/plugins/notifications2/formulaires/abonner_notifications.html b/www/plugins/notifications2/formulaires/abonner_notifications.html
new file mode 100644 (file)
index 0000000..b49f75b
--- /dev/null
@@ -0,0 +1,60 @@
+<div class="ajax formulaire_spip formulaire_#FORM formulaire_#FORM-#ENV{id,nouveau}">
+       <h3 class="titrem"><:abonnernotifications:titre_abonnements:><span class='image_loading'>&nbsp;</span></h3>
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV**{message_erreur})</p>]
+
+       <form method='post' action='#ENV{action}'><div>
+               [(#REM) déclarer les hidden qui déclencheront le service du formulaire
+               paramêtre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               #SET{fl,abonnernotifications}
+               <fieldset>
+                       <legend><:abonnernotifications:abonnement_forum_threads:></legend>
+                       <p class="explication"><:abonnernotifications:explication_abonnements{email=#ENV{_email}}:></p>
+                       <ul>
+                               <!--EX10-->
+                               #SET{name,id_threads}#SET{obli,''}#SET{defaut,''}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
+                               <li class="editer pleine_largeur editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
+                                       <label>[(#GET{fl}|concat{':label_',#GET{name}}|_T)]</label>[
+                                       <span class='erreur_message'>(#GET{erreurs})</span>
+                                       ]
+                                       <input type="hidden" name="#GET{name}#EVAL{chr(91)}#EVAL{chr(93)}" value="" />
+                                       <BOUCLE_threads(FORUMS){id_forum IN #ENV{_all_threads}}{par titre}>
+                                       #SET{val,#ID_THREAD}
+                                       <div class="choix">
+                                               <input type="checkbox" name="#GET{name}#EVAL{chr(91)}#EVAL{chr(93)}" class="checkbox" id="#GET{name}_#GET{val}" value="#GET{val}"[(#GET{val}|in_any{#ENV{#GET{name},#GET{defaut}}}|oui)checked="checked"] />
+                                               <label for="#GET{name}_#GET{val}">#TITRE (<a href="[(#URL_FORUM)]">Voir la discussion</a>)</label>
+                                       </div>
+                                       </BOUCLE_threads>
+                                       <p>
+                                       <a href="#" onclick="jQuery(this).closest('li').find('input.checkbox').prop('checked','checked');return false;">Tout cocher</a> |
+                                       <a href="#" onclick="jQuery(this).closest('li').find('input.checkbox').prop('checked',false);return false;">Tout décocher</a>
+                                       </p>
+                               </li>
+                       </ul>
+               </fieldset>
+               [(#REM) ajouter les saisies supplémentaires : extra et autre, à cet endroit ]
+         <!--extra-->
+         <p class='boutons'>
+               <input type='submit' class='submit' name='modifabo' value='<:abonnernotifications:bouton_modifier_abonnements|attribut_html:>' /></p>
+
+               <fieldset>
+                       <legend><:abonnernotifications:abonnement_modif_email:></legend>
+                       <ul>
+                               #SET{name,notification_email}#SET{obli,''}#SET{defaut,''}#SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}
+                               <li class="editer editer_[(#GET{name})][ (#GET{obli})][ (#GET{erreurs}|oui)erreur]">
+                                       <label for="#GET{name}">[(#GET{fl}|concat{':label_',#GET{name}}|_T)]</label>[
+                                       <span class='erreur_message'>(#GET{erreurs})</span>
+                                       ]<input type="text" name="#GET{name}" class="text" value="#ENV*{#GET{name},#GET{defaut}}" id="#GET{name}" [(#HTML5|et{#GET{obli}})required='required']/>
+                                       <p class="explication"><:abonnernotifications:explication_changer_email{email=#ENV{_email}}:></p>
+                               </li>
+                       </ul>
+               </fieldset>
+               [(#REM) ajouter les saisies supplémentaires : extra et autre, à cet endroit ]
+         <!--extra-->
+         <p class='boutons'>
+               <input type='submit' class='submit' name='modifemail' value='<:abonnernotifications:bouton_changer_email|attribut_html:>' /></p>
+
+       </div></form>
+
+</div>
\ No newline at end of file
diff --git a/www/plugins/notifications2/formulaires/abonner_notifications.php b/www/plugins/notifications2/formulaires/abonner_notifications.php
new file mode 100644 (file)
index 0000000..ae648a3
--- /dev/null
@@ -0,0 +1,182 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Charger()
+ *
+ * @param string $email
+ *   email dont on veut gerer les abonnements
+ * @param string $key
+ *   cle de signature de l'email
+ * @param null $id_auteur
+ *   id_auteur dont on veut gerer les abonnements (si pas d'email fourni)
+ * @return array|string
+ */
+function formulaires_abonner_notifications_charger_dist($email, $key, $id_auteur=null){
+
+       list($email, $id_auteur) = notifications_email_auteur($email, $key, $id_auteur);
+
+       if (!$email AND !$id_auteur)
+               return "<p><strong>"._T('abonnernotifications:message_acces_interdit')."</strong><br />"._T('abonnernotifications:message_acces_interdit_explication')."</p>";
+
+       $valeurs = array(
+               "id_threads" => array(),
+               "_all_threads" => array(),
+               "_email" => $email,
+               "notification_email" => '',
+       );
+
+       // trouver tous les threads
+       $rows = sql_allfetsel("id_thread,notification","spip_forum",notifications_where_abo($email, $id_auteur));
+
+       if (!$rows)
+               return "<p>"._T('abonnernotifications:message_aucun_abonnement_a_modifier')."</p>";
+
+       $valeurs['_all_threads'] = array_map('reset',$rows);
+       $valeurs['_all_threads'] = array_unique($valeurs['_all_threads']);
+
+       foreach ($rows as $row){
+               if ($row['notification'])
+                       $valeurs['id_threads'][] = $row['id_thread'];
+       }
+
+       return $valeurs;
+}
+
+/**
+ * Verifier()
+ *
+ * @param string $email
+ *   email dont on veut gerer les abonnements
+ * @param string $key
+ *   cle de signature de l'email
+ * @param null $id_auteur
+ *   id_auteur dont on veut gerer les abonnements (si pas d'email fourni)
+ * @return array|string
+ */
+function formulaires_abonner_notifications_verifier_dist($email, $key, $id_auteur=null){
+
+       $erreurs = array();
+
+       if (_request('modifemail')){
+               include_spip("inc/filtres");
+               if (!$email = _request('notification_email'))
+                       $erreurs['notification_email'] = _T('info_obligatoire');
+               elseif (!email_valide($email))
+                       $erreurs['notification_email'] = _T('form_prop_indiquer_email');
+       }
+
+       return $erreurs;
+}
+
+
+/**
+ * Traiter()
+ *
+ * @param string $email
+ *   email dont on veut gerer les abonnements
+ * @param string $key
+ *   cle de signature de l'email
+ * @param null $id_auteur
+ *   id_auteur dont on veut gerer les abonnements (si pas d'email fourni)
+ * @return array|string
+ */
+function formulaires_abonner_notifications_traiter_dist($email, $key, $id_auteur=null){
+
+       $res = array();
+       list($email, $id_auteur) = notifications_email_auteur($email, $key, $id_auteur);
+
+       if (_request('modifabo')){
+
+
+               $id_threads = _request('id_threads');
+               if (!is_array($id_threads))
+                       $id_threads = array();
+               $id_threads = array_map('intval',$id_threads);
+               $where_abo = notifications_where_abo($email, $id_auteur);
+               // desabonner ceux qui ne sont pas coches
+               sql_updateq("spip_forum",array('notification'=>0),"notification=1 AND $where_abo AND ".sql_in('id_thread',$id_threads,"NOT"));
+               // abonner ceux qui sont coches
+               sql_updateq("spip_forum",array('notification'=>1),"notification=0 AND $where_abo AND ".sql_in('id_thread',$id_threads));
+               $res = array("message_ok"=>_T('abonnernotifications:message_abonnements_modifies'));
+               // vider la saisie pour provoquer l'affichage de ce qui est en base
+               set_request('id_threads');
+       }
+       elseif (_request('modifemail')){
+
+       }
+
+       // ne devrait jamais...
+       if (!$res)
+               $res = array('message_erreur' => 'Erreur');
+
+       return $res;
+}
+
+
+
+/**
+ * Verifier la signature de l'email
+ * et retrouver l'id_auteur correspondant si possible (ou retrouver l'email de l'id_auteur si possible)
+ *
+ * @param string $email
+ *   email dont on veut gerer les abonnements
+ * @param string $key
+ *   cle de signature de l'email
+ * @param null $id_auteur
+ *   id_auteur dont on veut gerer les abonnements (si pas d'email fourni)
+ * @return array|string
+ */
+function notifications_email_auteur($email, $key, $id_auteur=null){
+       // si un email fourni, il doit etre signe par une cle valide
+       if ($email){
+               include_spip("inc/securiser_action");
+               if (!$key
+                       OR !verifier_cle_action("abonner_notifications $email",$key))
+                       return array('','');
+       }
+
+       // retrouver l'id_auteur correspondant a ce mail
+       if ($email AND !$id_auteur){
+               $id_auteur = sql_allfetsel("id_auteur","spip_auteurs","email=".sql_quote($email));
+               if ($id_auteur)
+                       $id_auteur = array_map('reset',$id_auteur);
+               if (count($id_auteur)==1)
+                       $id_auteur = reset($id_auteur);
+       }
+       // si pas d'email mais un id_auteur, prendre l'email de l'auteur
+       if (!$email AND $id_auteur){
+               $email = sql_getfetsel("email","spip_auteurs","id_auteur=".intval($id_auteur));
+       }
+
+       return array($email,$id_auteur);
+}
+
+/**
+ * Condition where pour retrouver tous les abonnements de l'email/id_auteur
+ * @param string $email
+ * @param int|null $id_auteur
+ * @return string
+ */
+function notifications_where_abo($email, $id_auteur=null){
+
+       if (!$email AND !$id_auteur){
+               return "(0=1)"; // rien a chercher
+       }
+
+       $where = array();
+       if ($email)
+               $where[] = "(notification_email=".sql_quote($email)
+                                         ." OR (notification_email=".sql_quote('')." AND email_auteur=".sql_quote($email)."))";
+       if ($id_auteur)
+               $where[] = "(notification_email=".sql_quote('')." AND email_auteur=".sql_quote('')." AND id_auteur=".intval($id_auteur).")";
+
+       return implode(" OR ",$where);
+}
\ No newline at end of file
diff --git a/www/plugins/notifications2/formulaires/configurer_notifications.html b/www/plugins/notifications2/formulaires/configurer_notifications.html
new file mode 100644 (file)
index 0000000..42b72d6
--- /dev/null
@@ -0,0 +1,149 @@
+<div class="formulaire_spip formulaire_cfg forulaire_#FORM">
+       [<p class='reponse_formulaire reponse_formulaire_erreur'>(#ENV*{message_erreur})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       <p class="explication"><:notifications:evenement_notification:></p>
+       <form method="post" action="#ENV{action}"><div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       [(#REM) ------------------------ ARTICLES PRIVES ------------------------ ]
+                       <li class="fieldset fieldset_article_prive">
+                               <fieldset>
+                                       <h3 class="legend"><:notifications:article_prive:></h3>
+                                       <ul>
+                                               <li class="editer editer_prevenir_auteurs_articles">
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="prevenir_auteurs_articles"[(#ENV{prevenir_auteurs_articles}|=={on}|oui)checked="checked"] id="prevenir_auteurs_articles" class="checkbox" />
+                                                               <label for="prevenir_auteurs_articles"><:notifications:article_prive_auteurs:></label>
+                                                       </div>
+                                               </li>
+                                               <li class="editer editer_prevenir_admins_restreints">
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="prevenir_admins_restreints"[(#ENV{prevenir_admins_restreints}|=={on}|oui)checked="checked"] id="prevenir_admins_restreints" class="checkbox" />
+                                                               <label for="prevenir_admins_restreints"><:notifications:article_prive_admins_restreints:></label>
+                                                       </div>
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+
+                       [(#REM) ------------------------ FORUMS PUBLICS ------------------------ ]
+                       <li class="fieldset fieldset_forums_public">
+                               <fieldset>
+                                       <h3 class="legend"><:notifications:forums_public:></h3>
+                                       <ul>
+                                               <li class="editer editer_prevenir_auteurs">
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="prevenir_auteurs"[(#ENV{prevenir_auteurs}|=={on}|oui)checked="checked"] id="prevenir_auteurs" class="checkbox" />
+                                                               <label for="prevenir_auteurs"><:notifications:forums_public_auteurs:></label>
+                                                       </div>
+                                               </li>
+                                               <li class="editer editer_thread_forum">
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="thread_forum"[(#ENV{thread_forum}|=={on}|oui)checked="checked"] id="thread_forum" class="checkbox" />
+                                                               <label for="thread_forum"><:notifications:forums_public_thread:></label>
+                                                       </div>
+                                               </li>
+                                               <li class="editer editer_moderateurs_forum">
+                                                       <label for="moderateurs_forum"><:notifications:moderateur:></label>
+                                                       <p class="explication"><:notifications:forums_public_moderateur:></p>
+                                                       <input type="text" name="moderateurs_forum" value="[(#ENV{moderateurs_forum}|entites_html)]" id="moderateurs_forum" class="text" />
+                                                       <p class="explication"><:notifications:forums_public_a_noter:></p>
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+
+                       [(#REM) ------------------------ FORUMS PRIVES ------------------------ ]
+                       <li class="fieldset fieldset_forums_prives">
+                               <fieldset>
+                                       <h3 class="legend"><:notifications:forums_prives:></h3>
+                                       <ul>
+                                               <li class="editer editer_prevenir_auteurs_prive">
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="prevenir_auteurs_prive"[(#ENV{prevenir_auteurs_prive}|=={on}|oui)checked="checked"] id="prevenir_auteurs_prive" class="checkbox" />
+                                                               <label for="prevenir_auteurs_prive"><:notifications:forum_prives_auteur:></label>
+                                                       </div>
+                                               </li>
+                                               <li class="editer editer_thread_forum_prive">
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="thread_forum_prive"[(#ENV{thread_forum_prive}|=={on}|oui)checked="checked"] id="thread_forum_prive" class="checkbox" />
+                                                               <label for="thread_forum_prive"><:notifications:forum_prives_thread:></label>
+                                                       </div>
+                                               </li>
+                                               <li class="editer editer_moderateurs_forum_prive">
+                                                       <label for="moderateurs_forum_prive"><:notifications:moderateur:></label>
+                                                       <p class="explication"><:notifications:forum_prives_moderateur:></p>
+                                                       <input type="text" name="moderateurs_forum_prive" value="[(#ENV{moderateurs_forum_prive}|entites_html)]" id="moderateurs_forum_prive" class="text" />
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+
+                       [(#REM) ------------------------ Messagerie ------------------------ ]
+                       <li class="fieldset fieldset_messagerie_interne">
+                               <fieldset>
+                                       <h3 class="legend"><:notifications:messagerie_interne:></h3>
+                                       <ul>
+                                               <li class="editer editer_messagerie">
+                                                       <div class="choix">
+                                                               <input type="checkbox" name="messagerie"[(#ENV{messagerie}|=={on}|oui)checked="checked"] id="messagerie" class="checkbox" />
+                                                               <label for="messagerie"><:notifications:messagerie_interne_signaler:></label>
+                                                       </div>
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+
+                       [(#REM) ------------------------ SIGNATURES ------------------------ ]
+                       <li class="fieldset fieldset_signature_petition">
+                               <fieldset>
+                                       <h3 class="legend"><:notifications:signature_petition:></h3>
+                                       <ul>
+                                               <li class="editer editer_moderateurs_signatures">
+                                                       <label for="moderateurs_signatures"><:notifications:moderateur:></label>
+                                                       <p class="explication"><:notifications:signature_petition_moderateur:></p>
+                                                       <input type="text" name="moderateurs_signatures" value="[(#ENV{moderateurs_signatures}|entites_html)]" id="moderateurs_signatures" class="text" />
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+                       
+                       [(#REM) ------------------------ INSCRIPTIONS ------------------------ ]
+                       <li class="fieldset fieldset_inscription">
+                               <fieldset>
+                                       <h3 class="legend"><:notifications:inscription:></h3>
+                                       <ul>
+                                               <li class="editer editer_inscription">
+                                                       <label for="inscription"><:notifications:inscription_label:></label>
+                                                       <p class="explication"><:notifications:inscription_explication:></p>
+                                                       <select name="inscription" id="inscription">
+                                                               <option value=""><:notifications:inscription_statut_aucun:></option>
+                                                               <option value="webmestres"[ selected="(#ENV{inscription}|=={webmestres}|?{selected})"]><:notifications:inscription_statut_webmestres:></option>
+                                                               <option value="admins"[ selected="(#ENV{inscription}|=={admins}|?{selected})"]><:notifications:inscription_admins:></option>
+                                                       </select>
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+                       [(#REM) --------------- SUIVI PERSONNALISE ----------- ]
+                       <li class="fieldset fieldset_suivis_perso">
+                               <fieldset>
+                                       <h3 class="legend"><:notifications:suivis_perso:></h3>
+                                       <ul>
+                                               <li class="editer editer_suivi">
+                                                       <p class="explication"><:notifications:suivis_perso_url_suivis:></p>
+                                                       <select name="suivi" id="suivi">
+                                                               <option value=""><:notifications:suivis_perso_non:></option>
+                                                               <option value="1"[ selected="(#ENV{suivi}|?{selected})"]><:notifications:suivis_perso_oui:></option>
+                                                       </select>
+                                               </li>
+                                       </ul>
+                               </fieldset>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+       </form>
+</div>
\ No newline at end of file
diff --git a/www/plugins/notifications2/genie/notifications.php b/www/plugins/notifications2/genie/notifications.php
new file mode 100644 (file)
index 0000000..4a788a8
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// 20 minutes de repit avant notification (+0 a 10 minutes de cron)
+define('_DELAI_NOTIFICATION_MESSAGERIE', 60 * 20);
+
+// Les notifications de la messagerie privee et de son forum se font par cron
+// base sur le champ 'vu' de spip_auteurs_liens
+// L'idee est
+// 1) de ne pas spammer les gens qui sont en ligne
+// 2) de ne pas notifier un auteur qu'on vient d'ajouter a une discussion,
+//    alors qu'on va peut-etre le supprimer (erreur de choix de destinataire)
+function genie_notifications_dist($time) {
+       if (!is_array($GLOBALS['notifications'] = @unserialize($GLOBALS['meta']['notifications'])))
+               $GLOBALS['notifications'] = array();
+
+       if (!$GLOBALS['notifications']['messagerie'])
+               return;
+       include_spip('base/abstract_sql');
+       $envoyer_mail = charger_fonction('envoyer_mail','inc');
+
+    $s = sql_select("lien.id_auteur,lien.id_objet,lien.objet,message.titre,message.texte, message.date_heure as date, auteur.nom,auteur.email,auteur.en_ligne",
+"spip_auteurs_liens AS lien, spip_messages AS message,spip_auteurs AS auteur",
+"lien.objet='message' AND lien.id_objet = message.id_message AND lien.id_auteur = auteur.id_auteur AND lien.vu='non'");
+       while ($t = sql_fetch($s)) {
+               // si le message est tout nouveau (ou n'a pas de date), on l'ignore
+               if (!$d = strtotime($t['date'])
+               OR $d > time() - _DELAI_NOTIFICATION_MESSAGERIE)
+                       continue;
+
+               // Si l'auteur est en ligne (ou ne l'a jamais ete), on l'ignore aussi
+               if (!$d = strtotime($t['en_ligne'])
+               OR $d > time() - _DELAI_NOTIFICATION_MESSAGERIE)
+                       continue;
+
+               // Si l'auteur n'a pas de mail ou est a la poubelle, on l'ignore
+               if (!$t['email'] OR $t['statut'] == '5poubelle')
+                       continue;
+
+               // OK on peut lui envoyer le mail
+               include_spip('inc/notifications');
+               include_spip('inc/texte');
+
+               // Chercher les forums les plus recents de ce message, pour afficher
+               // des extraits
+               $body =  _T('form_forum_message_auto')."\n\n";
+               $body .= "* " . textebrut(propre(couper(
+                               $t['titre']."<p>".$t['texte'], 700)))."\n\n";
+
+               $f = sql_select("titre,texte","spip_forum","id_message = " .intval($t['id_objet'])
+                       ." AND UNIX_TIMESTAMP(date_heure) > "._q($time));
+               while ($ff = sql_fetch($f)) {
+                       $body .= "----\n"
+                               .textebrut(propre(couper(
+                                       "** ".$ff['titre']."<p>".$ff['texte'], 700)))."\n\n";
+               }
+
+               $u = generer_url_ecrire('message', 'id_message='.$t['id_objet'],'&');
+               $body .= "$u\n";
+
+               $subject = "[" .
+         entites_html(textebrut(typo($GLOBALS['meta']["nom_site"]))) .
+         "] ["._T('onglet_messagerie')."] ".typo($t['titre']);
+
+               // Ne pas recommencer la prochaine, meme en cas de plantage du mail :)
+               sql_updateq("spip_auteurs_liens",array('vu'=>'oui'),"id_auteur=".intval($t['id_auteur'])." AND objet=".sql_quote($t['objet'])." AND id_objet=".intval($t['id_objet']));
+               $envoyer_mail($t['email'], $subject, $body);
+       }
+
+       if ($t)
+               return 1;
+}
+
+?>
diff --git a/www/plugins/notifications2/lang/abonnernotifications_fr.php b/www/plugins/notifications2/lang/abonnernotifications_fr.php
new file mode 100644 (file)
index 0000000..7224142
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/notifications/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       'titre_abonnements' => 'Gestion des abonnements',
+       'abonnement_forum_threads' => 'Abonnements aux discussions',
+       'explication_abonnements' => 'L\'adresse <strong>@email@</strong> aux discussions cochées dans la liste ci-dessous.',
+       'label_id_threads' => 'Modifiez vos abonnements :<br /><small>(décochez la case pour vous désabonner d\'une discussion)</small>',
+       'bouton_modifier_abonnements' => 'Modifier les abonnements',
+       'abonnement_modif_email' => 'Modification de votre courriel',
+       'label_notification_email' => 'Nouvelle adresse de courriel',
+       'bouton_changer_email' => 'Changer le courriel',
+       'explication_changer_email' => 'Un email de confirmation sera envoyé à <em>@email@</em> pour confirmation de la modification.',
+       'message_abonnements_modifies' => 'Vos abonnements ont bien été modifiés',
+       'message_acces_interdit' => 'Vous n\'avez pas le droit d\'accéder à cette fonction.',
+       'message_acces_interdit_explication' => 'Pour modifier vos abonnements aux discussions, utilisez le lien qui figure en bas des mails de notification.',
+       'message_aucun_abonnement_a_modifier' => 'Vous n\'avez pas d\'abonnement à modifier sur ce site',
+
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/notifications.xml b/www/plugins/notifications2/lang/notifications.xml
new file mode 100644 (file)
index 0000000..918f1ff
--- /dev/null
@@ -0,0 +1,16 @@
+<traduction module="notifications" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/notifications/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/notifications?lang_cible=en">
+               <traducteur nom="Benitron" lien="http://trad.spip.net/auteur/benitron" />
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/notifications?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/notifications?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/notifications?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/notifications2/lang/notifications_en.php b/www/plugins/notifications2/lang/notifications_en.php
new file mode 100644 (file)
index 0000000..7bf98cc
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/notifications?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'alt_logo_conf' => 'Notifications plugin logo',
+       'article_prive' => 'Articles publishing',
+       'article_prive_admins_restreints' => '<strong>Administrators</strong>: Administrators get notified when article(s) is(are) proposed in their section',
+       'article_prive_auteurs' => '<strong>Authors</strong>: Authors get notified when their article(s) is(are) proposed, published or deleted.',
+       'article_propose_detail' => 'The article "@titre@" is submitted for publication.',
+       'article_propose_sujet' => '[@nom_site_spip@] Submitted: @titre@',
+       'article_propose_titre' => 'Article submitted
+       ---------------',
+       'article_propose_url' => 'You are invited to review it and to give your opinion
+       in the forum linked to it. It is available at the address :',
+       'article_publie_detail' => 'The article "@titre@" was validated by @connect_nom@.',
+       'article_publie_sujet' => '[@nom_site_spip@] PUBLISHED: @titre@',
+       'article_publie_titre' => 'Article published
+       --------------',
+       'article_valide_date' => 'Without change, this article will be published',
+       'article_valide_detail' => 'The article "@titre@" is validated by @connect_nom@.',
+       'article_valide_sujet' => '[@nom_site_spip@] VALIDATED: @titre@',
+       'article_valide_titre' => 'Article validated
+       --------------',
+       'article_valide_url' => 'Meanwhile, it is visible at this temporary address :',
+
+       // B
+       'bouton_changer_pass' => 'Change my password',
+       'bouton_finir_inscription' => 'Validate my registration',
+       'breve_propose_detail' => 'The news item "@titre@" is proposed for publication since',
+       'breve_propose_sujet' => '[@nom_site_spip@] Proposed: @titre@',
+       'breve_propose_titre' => 'Proposed news item
+       ---------------',
+       'breve_propose_url' => 'You are invited to view it and give your opinion
+       in the forum attached to it. It is available at:',
+       'breve_publie_detail' => 'The news item "@titre@" has just been published by @connect_nom@.',
+       'breve_publie_sujet' => '[@nom_site_spip@] PUBLISHED: @titre@',
+       'breve_publie_titre' => 'News item published
+       --------------',
+
+       // E
+       'evenement_notification' => 'Following events may generate email notifications.',
+
+       // F
+       'form_forum_confirmer_email' => 'To confirm your email address, click the button below:',
+       'forum_prives_auteur' => '<strong>Authors</strong>: Authors get notified when comments are posted to their article(s) or comment(s) on the private area.',
+       'forum_prives_moderateur' => 'Please write here moderators\' email adress for private forums, coma separated.',
+       'forum_prives_thread' => '<strong>Forum thread</strong>: Posters to the same thread get notified when a new comment is posted to the (private) thread.',
+       'forums_prives' => 'Forums in private area',
+       'forums_public' => 'Public forums',
+       'forums_public_a_noter' => 'Note: if forums are awaiting validation from moderators before publication, only authors with rights to validate forums get notified when the comment is posted ; other recipients get notified only when moderators validate the comment.',
+       'forums_public_auteurs' => '<strong>Authors</strong>: Authors get notified when new comments are posted to their article(s) on the public area.',
+       'forums_public_moderateur' => 'Please write here moderators\' email adress for public forums, coma separated.',
+       'forums_public_thread' => '<strong>Forum thread</strong>: Posters to the same thread get notified when a new comment is posted to the (public) thread.',
+
+       // I
+       'info_lien_publier_commentaire' => 'Publish this comment online',
+       'info_lien_signaler_spam_commentaire' => 'Report as SPAM',
+       'info_lien_supprimer_commentaire' => 'Delete this comment',
+       'info_moderation_confirmee_off' => 'Message #@id_forum@ has been deleted',
+       'info_moderation_confirmee_publie' => 'Message #@id_forum@ has been published online',
+       'info_moderation_confirmee_spam' => 'Message #@id_forum@ has been reported as SPAM',
+       'info_moderation_deja_faite' => 'Message #@id_forum@ has already been moderated as "@statut@".',
+       'info_moderation_interdite' => 'You are not allowed to moderate this message',
+       'info_moderation_lien_titre' => 'Moderate this message from the private area',
+       'info_moderation_url_perimee' => 'This moderation link is not valid anymore.',
+       'info_nouveau_commentaire' => 'New comment',
+       'inscription' => 'Editors registration',
+       'inscription_admins' => 'Administrators',
+       'inscription_explication' => 'Which authors receive notifications when registering new editors?',
+       'inscription_label' => 'Status',
+       'inscription_statut_aucun' => 'None',
+       'inscription_statut_webmestres' => 'Webmaster',
+
+       // L
+       'lien_documentation' => '<a href="http://www.spip-contrib.net/Notifications" class="spip_out">View documentation</a>',
+
+       // M
+       'message_a_valider' => 'Message to confirm:',
+       'message_spam_a_confirmer' => 'SPAM to confirm:',
+       'message_voir_configuration' => 'Look at the notification setup',
+       'messagerie_interne' => 'Private messages',
+       'messagerie_interne_signaler' => '<strong>Notify new private messages</strong>: activate this to get redactors notified when they haven\'t seen a Private Message had been sent to them. Redactors get notified 20 minutes after the Private Message is sent, in order to avoid spam, when the redactor is connected to the private area.',
+       'moderateur' => '<strong>Moderator</strong>',
+
+       // N
+       'notifications' => 'Notifications',
+
+       // P
+       'pass_mail_passcookie_1' => 'To regain access to the site @nom_site_spip@, click the button:',
+       'pass_mail_passcookie_2' => 'You can then enter a new password and reconnect to the site.',
+
+       // S
+       'signature_petition' => 'Petition signatures',
+       'signature_petition_moderateur' => 'Please write here moderator\'s email address for petitions, coma separated.',
+       'suivi_texte_acces_page' => 'Change my subscriptions to discussions',
+       'suivis_perso' => 'Personnal notifications follow-up',
+       'suivis_perso_activer_option' => 'If you activate this option, each visitor clicking this follow-up URL will be registered in the <code>spip_auteurs</code> DB table, with status <code>6visiteur</code>. He\'ll be then able to view all the messages he posted on the website, configure his own notification options, ...',
+       'suivis_perso_non' => 'No follow-up',
+       'suivis_perso_oui' => 'Follow-up activated',
+       'suivis_perso_url_suivis' => '<strong>Add an URL for notifications follow-up</strong> in each notification email. CLicking on this URL will let the user configure his own notification preferences.',
+       'suivis_public_article_thread' => 'TODO: Tickbox on each article/thread',
+       'suivis_public_changer_email' => 'TODO: Change your email',
+       'suivis_public_description' => 'You will be able (when this will be operationnal...) find here all your comments on this website, get a RSS stream for their answers, choose your notification mode, ...',
+       'suivis_public_notif_desactiver' => 'TODO: Tickbox to stop notifications',
+       'suivis_public_vos_forums' => 'Your forums',
+       'suivis_public_vos_forums_date' => 'Your forums, by date',
+       'suivis_public_votre_page' => 'This is your personnal Notifications follow-up for the website',
+
+       // T
+       'titre_moderation' => 'Moderation'
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/notifications_es.php b/www/plugins/notifications2/lang/notifications_es.php
new file mode 100644 (file)
index 0000000..49fed06
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/notifications?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'alt_logo_conf' => 'Logo del plugin Notificaciones',
+       'article_prive' => 'Publicación de artículos',
+       'article_prive_admins_restreints' => '<strong>Administradores</strong>: Los administradores -limitados- reciben notificaciones cuando llegan propuestas de artículos a su sección',
+       'article_prive_auteurs' => '<strong>Autores</strong>: los autores reciben notificaciones cuando su(s) artículo(s) son propuestos, publicados o eliminados',
+       'article_propose_detail' => 'El artículo "@titre@" ha sido propuesto para publicación
+       desde',
+       'article_propose_sujet' => '[@nom_site_spip@] Propone: @titre@',
+       'article_propose_titre' => 'Artículo propuesto
+       ---------------',
+       'article_propose_url' => 'Le invitamos a consultarlo y a dar su opinión en el foro asociado. El mismo está disponible en la dirección:',
+       'article_publie_detail' => 'El artículo "@titre@" ha sido publicado por @connect_nom@.',
+       'article_publie_sujet' => '[@nom_site_spip@] PUBLICADO: @titre@',
+       'article_publie_titre' => 'Artículo publicado
+       --------------',
+       'article_valide_date' => 'Sujeto a modificación, este artículo será publicado',
+       'article_valide_detail' => 'El artículo "@titre@" ha sido aprobado por @connect_nom@.',
+       'article_valide_sujet' => '[@nom_site_spip@] APROBADO: @titre@',
+       'article_valide_titre' => 'Artículo aprobado
+       --------------',
+       'article_valide_url' => 'Mientras tanto, se halla disponible en esta dirección temporal:',
+
+       // B
+       'bouton_changer_pass' => 'Cambiar mi contraseña',
+       'bouton_finir_inscription' => 'Terminar mi registro',
+       'breve_propose_detail' => 'El breve "@titre@" ha sido propuesto para publicación
+       desde',
+       'breve_propose_sujet' => '[@nom_site_spip@] Propone: @titre@',
+       'breve_propose_titre' => 'Breve propuesto
+       ---------------',
+       'breve_propose_url' => 'Le invitamos a consultarlo y a dar su opinión en el foro asociado. El mismo está disponible en la dirección:',
+       'breve_publie_detail' => 'El breve "@titre@" ha sido publicado por @connect_nom@.',
+       'breve_publie_sujet' => '[@nom_site_spip@] PUBLICADO: @titre@',
+       'breve_publie_titre' => 'Breve publicado
+       --------------',
+
+       // E
+       'evenement_notification' => 'Los siguientes eventos pueden conllevar notificación por correo electrónico.',
+
+       // F
+       'form_forum_confirmer_email' => 'Para confirmar su dirección de correo electrónico, haga click en el siguiente botón: ',
+       'forum_prives_auteur' => '<strong>Autores</strong>: los autores reciben notificaciones de los foros derivados de sus artículos o de sus mensajes en el sitio privado. ',
+       'forum_prives_moderateur' => 'Indique a continuación el correo electrónico del moderador de los foros privados (si son varios, separe con comas).',
+       'forum_prives_thread' => '<strong>Hilo de discusión</strong>: los participantes de un mismo hilo de discusión reciben notificaciones de los foros (privados).',
+       'forums_prives' => 'Foros privados',
+       'forums_public' => 'Foros públicos',
+       'forums_public_a_noter' => 'Nota: en el caso de los foros moderados a priori, sólo aquellos autores que tienen derecho de aprobar los foros son notificados cuando se crea un foro; los otros destinatarios son notificados cuando el mensaje ha sido aprobado por el moderador.',
+       'forums_public_auteurs' => '<strong>Autores</strong>: los autores reciben notificaciones de aquellos foros derivados de sus artículos en en el sitio públicos.',
+       'forums_public_moderateur' => 'Indique a continuación el correo electrónico del moderador de los foros públicos (si son varios, separe con comas).',
+       'forums_public_thread' => '<strong>Hilo de discusión</strong>: los participantes de un mismo hilo de discusión reciben notificaciones de los foros (públicos).',
+
+       // I
+       'info_lien_publier_commentaire' => 'Publicar este comentario',
+       'info_lien_signaler_spam_commentaire' => 'Marcar como SPAM',
+       'info_lien_supprimer_commentaire' => 'Eliminar este comentario',
+       'info_moderation_confirmee_off' => 'El mensaje #@id_forum@ se ha eliminado correctamente',
+       'info_moderation_confirmee_publie' => 'El mensaje #@id_forum@ se ha publicado correctamente',
+       'info_moderation_confirmee_spam' => 'El mensaje #@id_forum@ se ha marcado como SPAM correctamente',
+       'info_moderation_deja_faite' => 'El mensaje #@id_forum@ ya se ha moderado en "@statut@".',
+       'info_moderation_interdite' => 'Usted no dispone de derecho de moderación de este mensaje',
+       'info_moderation_lien_titre' => 'Moderar este mensaje desde el espacio privado',
+       'info_moderation_url_perimee' => 'Este enlace de moderación ya no es válido.',
+       'info_nouveau_commentaire' => 'Nuevo comentario',
+       'inscription' => 'Registro de los redactores',
+       'inscription_admins' => 'Administradores',
+       'inscription_explication' => '¿Qué autores reciben notificación con el registro de nuevos redactores?',
+       'inscription_label' => 'Estatus',
+       'inscription_statut_aucun' => 'Ninguno',
+       'inscription_statut_webmestres' => 'Webmasters',
+
+       // L
+       'lien_documentation' => '<a href="http://www.spip-contrib.net/Notifications" class="spip_out">Cf. documentation</a>',
+
+       // M
+       'message_a_valider' => 'Mensaje para aprobar:',
+       'message_spam_a_confirmer' => 'Confirmar SPAM: ',
+       'message_voir_configuration' => 'Ver la configuración de las notificaciones',
+       'messagerie_interne' => 'Mensajería interna',
+       'messagerie_interne_signaler' => '<strong>Marcar nuevos mensajes privados</strong>: activar esta opción para que el sitio envíe una notificación cuando un redactor no haya advertido un nuevo mensaje en su mensajería. El sistema espera 20 minutos antes de notificarle al redactor, por lo que no se envía SPAM a un redactor ya en línea en el espacio privado.',
+       'moderateur' => '<strong>Moderador</strong>',
+
+       // N
+       'notifications' => 'Notificaciones',
+
+       // P
+       'pass_mail_passcookie_1' => 'Para recuperar el acceso al sitio @nom_site_spip@, haga click sobre el botón: ',
+       'pass_mail_passcookie_2' => 'A continuación puede introducir una nueva contraseña y volver a conectar con el sitio.',
+
+       // S
+       'signature_petition' => 'Firmas de petición',
+       'signature_petition_moderateur' => 'Indique a continuación el correo electrónico del moderador de las peticiones (si son varios, separe con comas).',
+       'suivi_texte_acces_page' => 'Modificar mis suscripciones a las discusiones ',
+       'suivis_perso' => 'Seguimiento personalizado',
+       'suivis_perso_activer_option' => 'Si habilita esta opción, cada usuario que visite esta URL de seguimiento quedará registrado en la tabla <code>spip_auteurs</code>, con el estatus <code>6visiteur</code>. El visitante podrá así ver el conjunto de mensajes firmados en el foro, regular sus opciones de notificación, etc.',
+       'suivis_perso_non' => 'Sin seguimiento',
+       'suivis_perso_oui' => 'Seguimiento activado',
+       'suivis_perso_url_suivis' => '<strong>Añadir una URL de seguimiento personalizado</strong> en cada uno de los correos electrónicos de notificación. A partir de esta URL, el usuario podrá configurar sus preferencias individuales de notificación.',
+       'suivis_public_article_thread' => 'TODO: casilla a marcar en cada artículo/thread',
+       'suivis_public_changer_email' => 'TODO: cambiar el correo electrónico',
+       'suivis_public_description' => 'Usted podrá acceder (cuando sea funcional) a todos sus mensajes del foro, obtener un hilo RSS de las respuestas aportadas, elegir su modo de notificación, etc.',
+       'suivis_public_notif_desactiver' => 'TODO: casilla a marcar para no recibir más notificaciones',
+       'suivis_public_vos_forums' => 'Sus foros',
+       'suivis_public_vos_forums_date' => 'Sus foros, por fecha',
+       'suivis_public_votre_page' => 'Ésta es su página personalizada de seguimiento del sitio',
+
+       // T
+       'titre_moderation' => 'Moderación'
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/notifications_fa.php b/www/plugins/notifications2/lang/notifications_fa.php
new file mode 100644 (file)
index 0000000..e3ff147
--- /dev/null
@@ -0,0 +1,120 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/notifications?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'alt_logo_conf' => 'لوگوي پلاگين اطلاعيه‌ها',
+       'article_prive' => 'نشر مقاله‌ها',
+       'article_prive_admins_restreints' => '<strong>ادمين‌ها </strong> : ادمين‌ها وقتي مقاله‌ها داخل بخش‌ آن‌ها پيشنهاد شود با خبر خواهند شد',
+       'article_prive_auteurs' => '<strong>نويسندگان</strong> :نويسندگان هنگام نشر مقاله‌ (ها) با خبر مي‌شوند', # MODIF
+       'article_propose_detail' => 'مقاله "@titre@" براي نشر پيشنهاد شده',
+       'article_propose_sujet' => '[@nom_site_spip@] پيشنهاد شده: @titre@',
+       'article_propose_titre' => 'مقاله پيشنهادي
+       ---------------',
+       'article_propose_url' => 'دعوت مي‌شويد كه در فرم پيوست مشورت و نظر خود را اعلام كنيد. اين فرم در اين شناني در دسترس است: ',
+       'article_publie_detail' => 'مقاله‌ي "@titre@" به وسيله‌ي @connect_nom@ منتشر شده.',
+       'article_publie_sujet' => '[@nom_site_spip@] منتشر شده: @titre@',
+       'article_publie_titre' => 'مقاله‌ي منتشر شده
+       --------------',
+       'article_valide_date' => 'بدون تغيير اين مقاله نشر خواهد شد',
+       'article_valide_detail' => 'مقاله‌ي "@titre@" از سوي  @connect_nom@ معتبر شده.',
+       'article_valide_sujet' => '[@nom_site_spip@] معتبر : @titre@',
+       'article_valide_titre' => 'مقاله‌ي تأييدي 
+       --------------',
+       'article_valide_url' => 'در ضمن، در اين نشاني موقت ديدني است:',
+
+       // B
+       'bouton_changer_pass' => 'Changer mon mot de passe', # NEW
+       'bouton_finir_inscription' => 'Finir mon inscription', # NEW
+       'breve_propose_detail' => 'خبر "@titre@" براي نشر پيشنهاد شده',
+       'breve_propose_sujet' => '[@nom_site_spip@]  پيشنهاد شده: @titre@',
+       'breve_propose_titre' => 'خبر پيشنهادي
+       ---------------',
+       'breve_propose_url' => 'دعوت مي‌شويد مشورت و نظر خود را در فرم پيوست ارايه دهيد. در اين نشاني در دسترس اشت:',
+       'breve_publie_detail' => 'خبر "@titre@" به وسيله‌ي  @connect_nom@ منتشر شده.',
+       'breve_publie_sujet' => '[@nom_site_spip@] منتشر شده: @titre@',
+       'breve_publie_titre' => 'خبر منتشر شده
+       --------------',
+
+       // E
+       'evenement_notification' => 'رويدادهاي آتي ممكن است سبب اطلاعيه‌هاي ايميلي شوند.',
+
+       // F
+       'form_forum_confirmer_email' => 'Pour confirmer votre adresse email, cliquez sur le bouton ci-dessous : ', # NEW
+       'forum_prives_auteur' => '<strong>نويسندگان: </strong>: نويسنده‌ها اطلاعيه‌هايي از سخنگاه‌هاي پست شده روي مقالاتشان يا پيام‌هايشان در قسمت شخصي سايت دريافت مي‌كنند. ',
+       'forum_prives_moderateur' => 'در زير نشاني ايميل گرداننده‌ي سخنگاه‌هاي قسمت شخصي را قيد كنيد (اگرچندتاست، با ويرگول جدا كنيد).',
+       'forum_prives_thread' => '<strong>خط گفتگو</strong> : شركت كنندگان در همان خط گفتگو اطلايه‌هاي سخنگاه‌ها را دريافت خواهند كرد (خصوصي)',
+       'forums_prives' => 'سخنگاه‌هاي خصوصي',
+       'forums_public' => 'سخنگاه‌هاي همگاني',
+       'forums_public_a_noter' => 'توجه: اگر سخنگاه‌ها در انتظار تأييد گرداننده‌ها پيش از نشر باشند، فقط نويسندگان با حق تأييد سخنگاه‌ها هنگامي كه نظري پست شود اطلاعيه‌ دريافت مي‌كنند، ساير دريافت كنندگان فقط هنگامي اطلاعيه را دريافت خواهدند كرد كه گردانند‌گان اظهار نظر را تأييد كنند.
+',
+       'forums_public_auteurs' => '<strong>نويسندگان</strong>: نويسندگان اطلاعيه‌هايي در سخنگاه‌هاي پست شده روي مقاله‌هايشان در سايت همگاني دريافت مي‌كنند.',
+       'forums_public_moderateur' => 'در زير نشاني ايميل گرداننده‌ (يا گردانندگان - جدا شده با ويرگول) سخنگاههاي عمومي  را قيد كنند.',
+       'forums_public_thread' => '<strong>خط گفتگو</strong>: شركت‌كنندگان در همان خط گفتگو اطلاعيه‌هايي از سخنگاه‌ها (همگاني) دريافت مي‌كنند.',
+
+       // I
+       'info_lien_publier_commentaire' => 'Publier ce commentaire', # NEW
+       'info_lien_signaler_spam_commentaire' => 'Signaler comme SPAM', # NEW
+       'info_lien_supprimer_commentaire' => 'Supprimer ce commentaire', # NEW
+       'info_moderation_confirmee_off' => 'Le message #@id_forum@ a bien été supprimé', # NEW
+       'info_moderation_confirmee_publie' => 'Le message #@id_forum@ a bien été publié', # NEW
+       'info_moderation_confirmee_spam' => 'Le message #@id_forum@ a bien été signalé en SPAM', # NEW
+       'info_moderation_deja_faite' => 'Le message #@id_forum@ a déjà été modéré en "@statut@".<br />Connectez-vous dans l\'espace privé pour le modifier.', # NEW
+       'info_moderation_interdite' => 'Vous n\'avez pas le droit de moderer ce message', # NEW
+       'info_moderation_lien_titre' => 'Moderer ce message depuis l\'espace privé', # NEW
+       'info_moderation_url_perimee' => 'Ce lien de moderation n\'est plus valide.', # NEW
+       'info_nouveau_commentaire' => 'Nouveau commentaire', # NEW
+       'inscription' => 'ثبت سردبيران',
+       'inscription_admins' => 'مديران',
+       'inscription_explication' => 'كدام نويسندگان اطلاعيه ثبت سردبيران جديد را دريافت مي‌كنند؟',
+       'inscription_label' => 'وضعيت ',
+       'inscription_statut_aucun' => 'هيچ',
+       'inscription_statut_webmestres' => 'وب‌مسترها',
+
+       // L
+       'lien_documentation' => '<a href="http://www.spip-contrib.net/Notifications" class="spip_out">به اسناد بنگريد</a>',
+
+       // M
+       'message_a_valider' => 'Message à valider : ', # NEW
+       'message_spam_a_confirmer' => 'SPAM à confirmer : ', # NEW
+       'message_voir_configuration' => 'به پيكربندي اطلاعيه‌ها بنگريد',
+       'messagerie_interne' => 'پيك داخلي',
+       'messagerie_interne_signaler' => '<strong>خبر يك پيام خصوصي</strong>: اين گزينه‌ را فعال كنيد تا هنگامي كه  نويسندگان يك پيام خصوصي را كه برايشان ارسال شده نديده باشند سايت يك اطلاعيه ارسال كند. سامانه پيش از خبر كردن نويسنده 20 دقيقه صبر خواهد كرد،  براي آنكه نويسنده‌اي كه الان در قسمت شخصي روي خط است اسپم نباشد.
+',
+       'moderateur' => '<strong>گرداننده</strong>',
+
+       // N
+       'notifications' => 'اطلاعيه‌ها',
+
+       // P
+       'pass_mail_passcookie_1' => 'Pour retrouver votre accès au site @nom_site_spip@, cliquez sur le bouton : ', # NEW
+       'pass_mail_passcookie_2' => 'Vous pourrez alors entrer un nouveau mot de passe et vous reconnecter au site.', # NEW
+
+       // S
+       'signature_petition' => 'امضا كنندگان طومار ',
+       'signature_petition_moderateur' => ' نشاني ايميل گرداننده (يا گردانندگان، با ويرگول جدا شود) طومارها را در زير قيد كنيد.',
+       'suivi_texte_acces_page' => 'Modifier mes abonnements aux discussions', # NEW
+       'suivis_perso' => 'پيگيري اطلاهيه‌هاي خصوصي',
+       'suivis_perso_activer_option' => 'اگر اين گزينه را فعال كنيد، هر بازديد‌كننده‌اي كه به اين يو.آر.ال وصل شود، در جدول نويسندگان اسپيپ <code>spip_auteurs</code>با وضعيت <code>6visiteur</code>فلان ثبت مي‌شود. بعد او مي‌تواند تمام پيام‌هايي را كه روي وب سايت پست كرده ببيند، گزينه‌هاي اطلاعيه‌ي خودش را پيكربندي كند و از اين قبيل. . . 
+',
+       'suivis_perso_non' => 'بدون پيگيري',
+       'suivis_perso_oui' => 'پيگيري فعال',
+       'suivis_perso_url_suivis' => 'افزودن يك يو.آر.ال پيگيري اطلاعيه‌هاي خصوصي در هر يك از ايميل‌هاي اطلاع‌رساني. بازديدكننده مي‌تواند از اين يو.آر.ال ترجيح‌هاي شخصي خود از اطلاع رساني را پيكربندي كند. ',
+       'suivis_public_article_thread' => 'TODO:جاي علامت روي هر مقاله/خط بحث',
+       'suivis_public_changer_email' => 'TODO: تغيير ايميل',
+       'suivis_public_description' => '(هرگاه اين كاركرد فعال باشد. . . )خواهيد توانست اينجا تمام پيام‌هاي خود در سخنگاه را بيابيد، يك خط آر.اس.اس براي پاسخ‌هاي آن‌ها به دست آوريد،حالت اطلاع‌رساني خود را انتخاب كنيد و از اين قبيل. . . ',
+       'suivis_public_notif_desactiver' => 'TODO: جاي علامت زدن براي آنكه ديگر اطلاعيه دريافت نشود',
+       'suivis_public_vos_forums' => 'سخنگاه‌هاي شما ',
+       'suivis_public_vos_forums_date' => 'سخنگاه‌هاي شما، به ترتيب تاريخ',
+       'suivis_public_votre_page' => 'اين صفحه‌ي شخصي شما براي پيگيري سايت است',
+
+       // T
+       'titre_moderation' => 'Modération' # NEW
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/notifications_fr.php b/www/plugins/notifications2/lang/notifications_fr.php
new file mode 100644 (file)
index 0000000..5dd68af
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/notifications/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'alt_logo_conf' => 'Logo du plugin Notifications',
+       'article_prive' => 'Publication d\'articles',
+       'article_prive_admins_restreints' => '<strong>Administrateurs</strong> : Les administrateurs restreints reçoivent les notifications lors de proposition d\'articles dans leur rubrique',
+       'article_prive_auteurs' => '<strong>Auteurs</strong> : les auteurs reçoivent les notifications lors de la proposition,publication ou suppression de leur(s) article(s)',
+       'article_propose_detail' => 'L\'article "@titre@" est proposé à la publication
+       depuis',
+       'article_propose_sujet' => '[@nom_site_spip@] Propose : @titre@',
+       'article_propose_titre' => 'Article proposé
+       ---------------',
+       'article_propose_url' => 'Vous êtes invité à venir le consulter et à donner votre opinion
+       dans le forum qui lui est attaché. Il est disponible à l\'adresse :',
+       'article_publie_detail' => 'L\'article "@titre@" vient d\'être publié par @connect_nom@.',
+       'article_publie_sujet' => '[@nom_site_spip@] PUBLIE : @titre@',
+       'article_publie_titre' => 'Article publié
+       --------------',
+       'article_valide_date' => 'Sous réserve de changement, cet article sera publié',
+       'article_valide_detail' => 'L\'article "@titre@" a été validé par @connect_nom@.',
+       'article_valide_sujet' => '[@nom_site_spip@] VALIDE : @titre@',
+       'article_valide_titre' => 'Article validé
+       --------------',
+       'article_valide_url' => 'En attendant, il est visible à cette adresse temporaire :',
+
+       // B
+       'bouton_changer_pass' => 'Changer mon mot de passe',
+       'bouton_finir_inscription' => 'Finir mon inscription',
+       'breve_propose_detail' => 'La brève "@titre@" est proposée à la publication
+       depuis',
+       'breve_propose_sujet' => '[@nom_site_spip@] Propose : @titre@',
+       'breve_propose_titre' => 'Brève proposée
+       ---------------',
+       'breve_propose_url' => 'Vous êtes invité à venir la consulter et à donner votre opinion
+       dans le forum qui lui est attaché. Elle est disponible à l\'adresse :',
+       'breve_publie_detail' => 'La brève "@titre@" vient d\'être publiée par @connect_nom@.',
+       'breve_publie_sujet' => '[@nom_site_spip@] PUBLIE : @titre@',
+       'breve_publie_titre' => 'Brève publiée
+       --------------',
+
+       // E
+       'evenement_notification' => 'Les événements suivants peuvent déclencher une notification par email.',
+
+       // F
+       'form_forum_confirmer_email' => 'Pour confirmer votre adresse email, cliquez sur le bouton ci-dessous : ',
+       'forum_prives_auteur' => '<strong>Auteurs</strong> : les auteurs reçoivent les notifications des forums postés sous leurs articles ou leurs messages dans le site privé.',
+       'forum_prives_moderateur' => 'Indiquez ci-dessous l\'adresse email du modérateur des forums privés (ou plusieurs, séparés par des virgules).',
+       'forum_prives_thread' => '<strong>Fil de discussion</strong> : les participants au même fil de discussion reçoivent les notifications des forums (privés).',
+       'forums_prives' => 'Forums privés',
+       'forums_public' => 'Forums publics',
+       'forums_public_a_noter' => 'À noter : dans le cas des forums modérés à priori, seuls les auteurs ayant le droit de valider les forums sont notifiés lors de l\'envoi du forum ; les autres destinataires sont notifiés lors de la validation du message par le modérateur.',
+       'forums_public_auteurs' => '<strong>Auteurs</strong> : les auteurs reçoivent les notifications des forums postés sous leurs articles dans le site public.',
+       'forums_public_moderateur' => 'Indiquez ci-dessous l\'adresse email du modérateur des forums publics (ou plusieurs, séparés par des virgules).',
+       'forums_public_thread' => '<strong>Fil de discussion</strong> : les participants au même fil de discussion reçoivent les notifications des forums (publics).',
+
+       // I
+       'info_lien_publier_commentaire' => 'Publier ce commentaire',
+       'info_lien_signaler_spam_commentaire' => 'Signaler comme SPAM',
+       'info_lien_supprimer_commentaire' => 'Supprimer ce commentaire',
+       'info_moderation_confirmee_off' => 'Le message #@id_forum@ a bien été supprimé',
+       'info_moderation_confirmee_publie' => 'Le message #@id_forum@ a bien été publié',
+       'info_moderation_confirmee_spam' => 'Le message #@id_forum@ a bien été signalé en SPAM',
+       'info_moderation_deja_faite' => 'Le message #@id_forum@ a déjà été modéré en "@statut@".',
+       'info_moderation_interdite' => 'Vous n\'avez pas le droit de modérer ce message',
+       'info_moderation_lien_titre' => 'Modérer ce message depuis l\'espace privé',
+       'info_moderation_url_perimee' => 'Ce lien de modération n\'est plus valide.',
+       'info_nouveau_commentaire' => 'Nouveau commentaire',
+       'inscription' => 'Inscription des rédacteurs',
+       'inscription_admins' => 'Administrateurs',
+       'inscription_explication' => 'Quels auteurs reçoivent les notifications lors de l\'inscription de nouveaux rédacteurs ?',
+       'inscription_label' => 'Statut',
+       'inscription_statut_aucun' => 'Aucun',
+       'inscription_statut_webmestres' => 'Webmestres',
+
+       // L
+       'lien_documentation' => '<a href="http://www.spip-contrib.net/Notifications" class="spip_out">Cf. documentation</a>',
+
+       // M
+       'message_a_valider' => 'Message à valider : ',
+       'message_spam_a_confirmer' => 'SPAM à confirmer : ',
+       'message_voir_configuration' => 'Voir la configuration des notifications',
+       'messagerie_interne' => 'Messagerie interne',
+       'messagerie_interne_signaler' => '<strong>Signaler les nouveaux messages privés</strong> : activer cette option pour que le site envoie une notification lorsqu\'un rédacteur n\'a pas vu un nouveau message dans sa messagerie. Le système attend 20 minutes avant de notifier le rédacteur, de manière à ne pas spammer un rédacteur déjà en ligne dans l\'espace privé.',
+       'moderateur' => '<strong>Modérateur</strong>',
+
+       // N
+       'notifications' => 'Notifications',
+
+       // P
+       'pass_mail_passcookie_1' => 'Pour retrouver votre accès au site @nom_site_spip@, cliquez sur le bouton : ',
+       'pass_mail_passcookie_2' => 'Vous pourrez alors entrer un nouveau mot de passe et vous reconnecter au site.',
+
+       // S
+       'signature_petition' => 'Signatures de pétition',
+       'signature_petition_moderateur' => 'Indiquez ci-dessous l\'adresse email du modérateur des pétitions (ou plusieurs, séparés par des virgules).',
+       'suivi_texte_acces_page' => 'Modifier mes abonnements aux discussions',
+       'suivis_perso' => 'Suivi personnalisé',
+       'suivis_perso_activer_option' => 'Si vous activez cette option, chaque visiteur qui se connecte sur cet URL de suivi sera enregistré dans la table <code>spip_auteurs</code>, avec le statut <code>6visiteur</code>. Il pourra alors voir l\'ensemble des messages qu\'il a signés sur le forum, régler ses options de notification, etc.',
+       'suivis_perso_non' => 'Pas de suivi',
+       'suivis_perso_oui' => 'Suivi activé',
+       'suivis_perso_url_suivis' => '<strong>Ajouter une URL de suivi personnalisé</strong> dans chacun des emails de notification. À partir de cette URL, l\'utilisateur pourra configurer ses préférences individuelles de notification.',
+       'suivis_public_article_thread' => 'TODO: case à cocher sur chaque article/thread',
+       'suivis_public_changer_email' => 'TODO: changer d\'email',
+       'suivis_public_description' => 'Vous pourrez (quand ce sera fonctionnel...) y retrouver tous vos messages de forum, obtenir un fil RSS des réponses qui y seront apportées, choisir votre mode de notification, etc.',
+       'suivis_public_notif_desactiver' => 'TODO: case à cocher pour ne plus recevoir de notifications',
+       'suivis_public_vos_forums' => 'Vos forums',
+       'suivis_public_vos_forums_date' => 'Vos forums, par date',
+       'suivis_public_votre_page' => 'Ceci est votre page personnalisée de suivi du site',
+
+       // T
+       'titre_moderation' => 'Modération'
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/notifications_sk.php b/www/plugins/notifications2/lang/notifications_sk.php
new file mode 100644 (file)
index 0000000..c830442
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/notifications?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'alt_logo_conf' => 'Logo zásuvného modulu Oznamy',
+       'article_prive' => 'Publikovanie článkov',
+       'article_prive_admins_restreints' => '<strong>Administrátori:</strong> administrátori s obmedzeniami dostávajú oznamy pri odoslaní článkov do ich rubriky',
+       'article_prive_auteurs' => '<strong>Autori:</strong> autori dostávajú oznamy pri odoslaní svojich článkov na schválenie, pri ich publikovaní alebo odstránení',
+       'article_propose_detail' => 'Článok "@titre@" bol odoslaný na publikovanie
+       z(o)',
+       'article_propose_sujet' => '[@nom_site_spip@] Odoslaný: @titre@',
+       'article_propose_titre' => 'Článok bol odoslaný
+       ---------------',
+       'article_propose_url' => 'Pozvali vás, aby ste si prečítali tento článok a svoj názor naň napísali do diskusného fóra, ktoré je k nemu pripojené. Článok nájdete na adrese:',
+       'article_publie_detail' => 'Článok "@titre@" práve publikoval(a) @connect_nom@.',
+       'article_publie_sujet' => '[@nom_site_spip@] PUBLIKOVANÝ: @titre@',
+       'article_publie_titre' => 'Publikovaný článok
+       --------------',
+       'article_valide_date' => 'Môže sa zmeniť, tento článok bude publikovaný',
+       'article_valide_detail' => 'Článok "@titre@" schválil(a) @connect_nom@.',
+       'article_valide_sujet' => '[@nom_site_spip@] POTVRDENÝ: @titre@',
+       'article_valide_titre' => 'Článok bol schválený
+       --------------',
+       'article_valide_url' => 'Zatiaľ je zobrazený na tejto dočasnej adrese:',
+
+       // B
+       'bouton_changer_pass' => 'Zmeniť si heslo',
+       'bouton_finir_inscription' => 'Dokončiť registráciu',
+       'breve_propose_detail' => 'Novinka "@titre@" sa posiela na publikovanie
+       z(o)',
+       'breve_propose_sujet' => '[@nom_site_spip@] Odoslaný: @titre@',
+       'breve_propose_titre' => 'Novinka bola odoslaná
+       ---------------',
+       'breve_propose_url' => 'Pozvali vás, aby ste si pozreli túto novinku a svoj názor na ňu napísali  do diskusného fóra, ktoré je k nej pripojené. Novinku nájdete na adrese:',
+       'breve_publie_detail' => 'Novinku "@titre@" práve publikoval(a) @connect_nom@.',
+       'breve_publie_sujet' => '[@nom_site_spip@] PUBLIKOVANÝ: @titre@',
+       'breve_publie_titre' => 'Novinka bola publikovaná
+       --------------',
+
+       // E
+       'evenement_notification' => 'Ďalšie udalosti môžu vyvolať odoslanie oznamu e-mailom.',
+
+       // F
+       'form_forum_confirmer_email' => 'Ak chcete potvrdiť svoju e-mailovú adresu, kliknite na toto tlačidlo: ',
+       'forum_prives_auteur' => '<strong>Autori:</strong> autori dostávajú oznamy odoslané z diskusných fór pod ich článkami alebo správami v súkromnej zóne.',
+       'forum_prives_moderateur' => 'Zadajte e-mailovú adresu moderátora súkromných diskusných fór (alebo viac, oddelených čiarkami).',
+       'forum_prives_thread' => '<strong>Téma:</strong> diskutujúci v rovnakom vlánke dostávajú oznami z (verejných) diskusných fór.',
+       'forums_prives' => 'Súkromné diskusné fóra',
+       'forums_public' => 'Verejné diskusné fóra',
+       'forums_public_a_noter' => 'Poznámka: v prípade, že sa príspevky do diskusných fór kontrolujú pred ich zverejnením, o odoslaní príspevkov sú informovaní iba autori, ktorí majú právo schvaľovať príspevky; ostatní sú informovaní, až keď príspevky schvália títo moderátori.',
+       'forums_public_auteurs' => '<strong>Autori:</strong> autori dostávajú oznamy odoslané z diskusných fór pod ich článkami na verejne prístupnej stránke.',
+       'forums_public_moderateur' => 'Zadajte e-mailovú adresu moderátora verejných diskusných fór (alebo viac, oddelených čiarkami).',
+       'forums_public_thread' => '<strong>Téma:</strong> diskutujúci v rovnakom vlákne dostávajú oznamy z (verejných) diskusných fór.',
+
+       // I
+       'info_lien_publier_commentaire' => 'Publikovať tento komentár',
+       'info_lien_signaler_spam_commentaire' => 'Nahlásiť ako SPAM',
+       'info_lien_supprimer_commentaire' => 'Odstrániť tento komentár',
+       'info_moderation_confirmee_off' => 'Príspevok #@id_forum@ bol vymazaný',
+       'info_moderation_confirmee_publie' => 'Príspevok #@id_forum@ bol publikovaný',
+       'info_moderation_confirmee_spam' => 'Príspevok #@id_forum@ bol nahlásený ako SPAM',
+       'info_moderation_deja_faite' => 'Príspevok #@id_forum@ už bol skontrolovaný v "@statut@".',
+       'info_moderation_interdite' => 'Na kontrolu tohto príspevku nemáte dostatočné práva',
+       'info_moderation_lien_titre' => 'Skontrolovať tento príspevok zo súkromnej zóny',
+       'info_moderation_url_perimee' => 'Tento odkaz na kontrolu už nie je platný.',
+       'info_nouveau_commentaire' => 'Nový komentár',
+       'inscription' => 'Prihlásenie redaktorov',
+       'inscription_admins' => 'Administrátori',
+       'inscription_explication' => 'Ktorí autori dostanú oznamy pri zaregistrovaní nových redaktorov?',
+       'inscription_label' => 'Stav',
+       'inscription_statut_aucun' => 'Žiaden',
+       'inscription_statut_webmestres' => 'Webmasteri',
+
+       // L
+       'lien_documentation' => '<a href="http://www.spip-contrib.net/Notifications" class="spip_out">Porov. s dokumentáciou</a>',
+
+       // M
+       'message_a_valider' => 'Príspevok na potvrdenie: ',
+       'message_spam_a_confirmer' => 'SPAM na potvrdenie: ',
+       'message_voir_configuration' => 'Zobraziť nastavenia oznamov',
+       'messagerie_interne' => 'Súkromný odkazovač',
+       'messagerie_interne_signaler' => '<strong>Označiť nové súkromné správy:</strong> aktivujte túto možnosť, ak chcete, aby stránka poslala oznam redaktorovi, v prípade, že si neprečítal novú správu vo svojej schránke. Systém počká 20 minút, predtým ako upozorní redaktora, a tak nespamuje redaktora, ktorý je už online v súkromnej zóne.',
+       'moderateur' => '<strong>Moderátor</strong>',
+
+       // N
+       'notifications' => 'Oznamy',
+
+       // P
+       'pass_mail_passcookie_1' => 'Ak chcete znovu získať prístup na stránku @nom_site_spip@, kliknite na tlačidlo: ',
+       'pass_mail_passcookie_2' => 'Potom môžete zadať nové heslo a znova sa prihlásiť na stránku.',
+
+       // S
+       'signature_petition' => 'Podpisy pod petíciu',
+       'signature_petition_moderateur' => 'Zadajte e-mailovú adresu moderátora petícií (alebo viac, oddelených čiarkami).',
+       'suivi_texte_acces_page' => 'Upraviť odoberanie príspevkov z diskusií',
+       'suivis_perso' => 'Prispôsobené sledovanie',
+       'suivis_perso_activer_option' => 'Ak aktivujete túto možnosť, každý návštevník, ktorý sa prihlási na túto sledovaciu adresu, bude zapísaný do tabuľky <code>spip_auteurs</code> so stavom <code>6visiteur.</code> Potom si bude môcť prezrieť všetky príspevky, pod ktoré sa podpísal na diskusnom fóre, upraviť si nastavenia oznamov, atď.',
+       'suivis_perso_non' => 'Bez sledovania',
+       'suivis_perso_oui' => 'Sledovať aktivitu',
+       'suivis_perso_url_suivis' => '<strong>Pridať vlastnú URL na sledovanie</strong> do každého oznamu e-mailom. Pomocou tejto adresy si môžu používatelia sami nastaviť vlastné predvoľby pre oznamy.',
+       'suivis_public_article_thread' => 'TREBA: zaškrtávacie políčko pri každom článku/vlákne',
+       'suivis_public_changer_email' => 'TREBA: zmeniť e-mail',
+       'suivis_public_description' => 'Môžete (ak to funguje) duplikovať a preniesť ich na inú stránku všetky svoje príspevky v diskusnom fóre, vytvoriť si kanál RSS s reakciami na ne, vybrať si spôsob oznámenia o reakcii, atď.',
+       'suivis_public_notif_desactiver' => 'TREBA: zaškrtávacie políčko na zastavenie prijímania oznamov',
+       'suivis_public_vos_forums' => 'Vaše diskusné fóra',
+       'suivis_public_vos_forums_date' => 'Vaše diskusné fóra podľa dátumu',
+       'suivis_public_votre_page' => 'Toto je vaša vlastná stránka na sledovanie webu.',
+
+       // T
+       'titre_moderation' => 'Kontrola'
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/paquet-notifications.xml b/www/plugins/notifications2/lang/paquet-notifications.xml
new file mode 100644 (file)
index 0000000..b367f2b
--- /dev/null
@@ -0,0 +1,15 @@
+<traduction module="paquet-notifications" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/notifications/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/notifications2/lang/paquet-notifications_en.php b/www/plugins/notifications2/lang/paquet-notifications_en.php
new file mode 100644 (file)
index 0000000..1123b68
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'notifications_description' => 'Sends mail notifications for certain actions : forums posts and answers notified to users, private messages notified to redactors or articles publication notified to their authors.',
+       'notifications_slogan' => 'Report changes by mail '
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/paquet-notifications_es.php b/www/plugins/notifications2/lang/paquet-notifications_es.php
new file mode 100644 (file)
index 0000000..be7e54e
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'notifications_description' => 'Activa las notificaciones por correo electrónico de ciertas acciones, incluyendo las referidas a foros y mensajería del espacio privado. Permite igualmente el envío de un correo electrónico a los autores cuando sus artículos son publicados.',
+       'notifications_slogan' => 'Advertir por correo electrónico de las modificaciones'
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/paquet-notifications_fa.php b/www/plugins/notifications2/lang/paquet-notifications_fa.php
new file mode 100644 (file)
index 0000000..fa79a73
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'notifications_description' => 'فعال سازي اطلاعيه‌ها به وسيله‌ي ايميل بعضي كارها، به ويژه سخنگاه‌ها و پيك قسمت شخصي، اجازه‌ي ارسال يك ايميل به تمام نويسنده هنگام نشر مقاله‌هاي آنان را مي‌دهد.
+',
+       'notifications_slogan' => 'خبردهي از اصلاحات با ايميل'
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/paquet-notifications_fr.php b/www/plugins/notifications2/lang/paquet-notifications_fr.php
new file mode 100644 (file)
index 0000000..998f070
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/notifications/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'notifications_description' => 'Active les notifications par email de certaines actions, notamment des forums et de la messagerie de l\'espace privé, permet également l\'envoi d\'un mail aux auteurs lors de la publication de leurs articles.',
+       'notifications_slogan' => 'Signaler par mail des modifications'
+);
+
+?>
diff --git a/www/plugins/notifications2/lang/paquet-notifications_sk.php b/www/plugins/notifications2/lang/paquet-notifications_sk.php
new file mode 100644 (file)
index 0000000..d4b7d46
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-notifications?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // N
+       'notifications_description' => 'Aktivuje oznamy e-mailom pri určitých akciách, vrátane diskusných fór a odkazovača v súkromnej zóne, ako aj odoslania e-mailov autorom pri publikovaní ich článkov.',
+       'notifications_slogan' => 'Oznámiť zmeny e-mailom'
+);
+
+?>
diff --git a/www/plugins/notifications2/modeles/mail_inscription.html b/www/plugins/notifications2/modeles/mail_inscription.html
new file mode 100644 (file)
index 0000000..5b4110c
--- /dev/null
@@ -0,0 +1,38 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<title>[\[(#NOM_SITE_SPIP|concat{'\] : ',<:form_forum_identifiants:>}|nettoyer_titre_email)]</title>
+
+<body>
+[(#SET{nom,[<strong>(#ENV{nom})</strong>]})]
+<p><:form_forum_bonjour{nom=#GET{nom}}:></p>
+
+
+
+<p><:notifications:form_forum_confirmer_email:></p>
+<div>
+[<br><center>(#INCLURE{fond=emails/inc-button,url=[(#ENV{url_confirm}|url_absolue)],label=<:notifications:bouton_finir_inscription:>,width=250px})</center><br>]
+</div>
+
+#SET{url_site,#URL_SITE_SPIP/}
+[(#SET{nom_site,[<a href="#GET{url_site}">(#NOM_SITE_SPIP)</a>]})]
+[(#ENV{mode}|=={6forum}|oui)
+[(#SET{url_login,[<a href="#GET{url_site}">(#URL_PAGE{login})</a>]})]
+<p><:form_forum_voici1{nom_site_spip=#GET{nom_site},adresse_site=#REM,adresse_login=#GET{url_login}}|replace{'\\(\\)',''}:></p>
+]
+[(#ENV{mode}|=={6forum}|non)
+[(#SET{url_login,[<a href="#GET{url_site}">(#URL_SITE_SPIP|concat{'/',#EVAL{_DIR_RESTREINT_ABS}})</a>]})]
+<p><:form_forum_voici2{nom_site_spip=#NOM_SITE_SPIP,adresse_site=#REM,adresse_login=#GET{url_login}}|replace{'\\(\\)',''}:></p>
+]
+
+<ul class="spip">
+<li><:form_forum_login:>[ (#ENV{email,email})]</li>
+<li><:form_forum_pass:>[ (#ENV{pass,pass})]</li>
+</ul>
+</body>
+
+#FILTRE{facteur_email_wrap_to_html}
\ No newline at end of file
diff --git a/www/plugins/notifications2/modeles/mail_oubli.html b/www/plugins/notifications2/modeles/mail_oubli.html
new file mode 100644 (file)
index 0000000..a690e60
--- /dev/null
@@ -0,0 +1,21 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<title>[\[(#NOM_SITE_SPIP|concat{'\] ',<:pass_oubli_mot:>}|nettoyer_titre_email)]</title>
+<body>
+
+#SET{url_site,#URL_SITE_SPIP/}
+[(#SET{nom_site,[<a href="#GET{url_site}">(#NOM_SITE_SPIP)</a>]})]
+<p><:notifications:pass_mail_passcookie_1{nom_site_spip=#GET{nom_site}}:></p>
+<div>
+[<br><center>(#INCLURE{fond=emails/inc-button,url=[(#ENV{url_reset}|url_absolue)],label=<:notifications:bouton_changer_pass:>,width=250px})</center><br>]
+</div>
+
+<p><:notifications:pass_mail_passcookie_2:></p>
+</body>
+
+#FILTRE{facteur_email_wrap_to_html}
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications-24.png b/www/plugins/notifications2/notifications-24.png
new file mode 100644 (file)
index 0000000..32deae8
Binary files /dev/null and b/www/plugins/notifications2/notifications-24.png differ
diff --git a/www/plugins/notifications2/notifications-32.png b/www/plugins/notifications2/notifications-32.png
new file mode 100644 (file)
index 0000000..bf434e0
Binary files /dev/null and b/www/plugins/notifications2/notifications-32.png differ
diff --git a/www/plugins/notifications2/notifications.png b/www/plugins/notifications2/notifications.png
new file mode 100644 (file)
index 0000000..72c7943
Binary files /dev/null and b/www/plugins/notifications2/notifications.png differ
diff --git a/www/plugins/notifications2/notifications/article_propose.html b/www/plugins/notifications2/notifications/article_propose.html
new file mode 100644 (file)
index 0000000..9583470
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<BOUCLE_art(ARTICLES){id_article}{statut?}{tout}>
+#SET{auteurs,#LESAUTEURS}
+<title>[(#VAL{notifications:article_propose_sujet}|_T{#ARRAY{nom_site_spip,#NOM_SITE_SPIP,titre,#TITRE}}|nettoyer_titre_email)]</title>
+
+<body>
+<div class="header">
+<h1><:notifications:article_propose_titre|trim|trim{-}:></h1>
+<p>
+[(#SET{titre,[<a href="[(#ID_ARTICLE|generer_url_entite{article,'','',0})]"><strong>(#TITRE)</strong></a>]})]
+[(#VAL{notifications:article_propose_detail}|_T{#ARRAY{titre,#GET{titre}}})][ (#VAL{date_fmt_nomjour_date}|_T{[(#ARRAY{'nomjour',[(#DATE|nom_jour)],'date',[(#DATE|affdate)]})]}).]
+</p>
+<hr />
+</div>
+
+<INCLURE{fond=notifications/inc-article,id_article} />
+</body>
+</BOUCLE_art>
+#FILTRE{facteur_email_wrap_to_html}
diff --git a/www/plugins/notifications2/notifications/article_publie.html b/www/plugins/notifications2/notifications/article_publie.html
new file mode 100644 (file)
index 0000000..be52400
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<BOUCLE_art(ARTICLES){id_article}{statut?}{tout}>
+#SET{auteurs,#LESAUTEURS}
+<title>[(#VAL{notifications:article_publie_sujet}|_T{#ARRAY{nom_site_spip,#NOM_SITE_SPIP,titre,#TITRE}}|nettoyer_titre_email)]</title>
+
+<body>
+<div class="header">
+<h1><:notifications:article_valide_titre|trim|trim{-}:></h1>
+<p>
+[(#SET{titre,[<a href="[(#URL_ARTICLE|url_absolue)]"><strong>(#TITRE)</strong></a>]})]
+[(#VAL{notifications:article_publie_detail}|_T{#ARRAY{titre,#GET{titre},connect_nom,#SESSION{nom}}})]
+</p>
+<hr />
+</div>
+
+<INCLURE{fond=notifications/inc-article,id_article} />
+</body>
+</BOUCLE_art>
+#FILTRE{facteur_email_wrap_to_html}
diff --git a/www/plugins/notifications2/notifications/article_valide.html b/www/plugins/notifications2/notifications/article_valide.html
new file mode 100644 (file)
index 0000000..e329561
--- /dev/null
@@ -0,0 +1,26 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<BOUCLE_art(ARTICLES){id_article}{statut?}{tout}>
+#SET{auteurs,#LESAUTEURS}
+<title>[(#VAL{notifications:article_valide_sujet}|_T{#ARRAY{nom_site_spip,#NOM_SITE_SPIP,titre,#TITRE}}|nettoyer_titre_email)]</title>
+
+<body>
+<div class="header">
+<h1><:notifications:article_valide_titre|trim|trim{-}:></h1>
+<p>
+[(#SET{titre,[<a href="(#URL_ARTICLE|url_absolue|parametre_url{var_mode,'preview'})"><strong>(#TITRE)</strong></a>]})]
+[(#VAL{notifications:article_valide_detail}|_T{#ARRAY{titre,#GET{titre},connect_nom,#SESSION{nom}}})]
+[<:notifications:article_valide_date:> (#VAL{date_fmt_nomjour_date}|_T{[(#ARRAY{'nomjour',[(#DATE|nom_jour)],'date',[(#DATE|affdate)]})]}).]
+</p>
+<hr />
+</div>
+
+<INCLURE{fond=notifications/inc-article,id_article} />
+</body>
+</BOUCLE_art>
+#FILTRE{facteur_email_wrap_to_html}
diff --git a/www/plugins/notifications2/notifications/breve_propose.html b/www/plugins/notifications2/notifications/breve_propose.html
new file mode 100644 (file)
index 0000000..7c5d9df
--- /dev/null
@@ -0,0 +1,24 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<BOUCLE_bre(BREVES){id_breve}{statut?}{tout}>
+<title>[(#VAL{notifications:breve_propose_sujet}|_T{#ARRAY{nom_site_spip,#NOM_SITE_SPIP,titre,#TITRE}}|nettoyer_titre_email)]</title>
+
+<body>
+<div class="header">
+<h1><:notifications:breve_propose_titre|trim|trim{-}:></h1>
+<p>
+[(#SET{titre,[<a href="[(#ID_BREVE|generer_url_entite{breve,'','',0})]"><strong>(#TITRE)</strong></a>]})]
+[(#VAL{notifications:breve_propose_detail}|_T{#ARRAY{titre,#GET{titre}}})][ (#VAL{date_fmt_nomjour_date}|_T{[(#ARRAY{'nomjour',[(#DATE|nom_jour)],'date',[(#DATE|affdate)]})]}).]
+</p>
+<hr />
+</div>
+
+<INCLURE{fond=notifications/inc-breve,id_breve} />
+</body>
+</BOUCLE_bre>
+#FILTRE{facteur_email_wrap_to_html}
diff --git a/www/plugins/notifications2/notifications/breve_publie.html b/www/plugins/notifications2/notifications/breve_publie.html
new file mode 100644 (file)
index 0000000..15796c2
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<BOUCLE_bre(BREVES){id_breve}{statut?}{tout}>
+<title>[(#VAL{notifications:breve_publie_sujet}|_T{#ARRAY{nom_site_spip,#NOM_SITE_SPIP,titre,#TITRE}}|nettoyer_titre_email)]</title>
+
+<body>
+<div class="header">
+<h1><:notifications:breve_publie_titre|trim|trim{-}:></h1>
+<p>
+[(#SET{titre,[<a href="[(#URL_BREVE|url_absolue)]"><strong>(#TITRE)</strong></a>]})]
+[(#VAL{notifications:breve_publie_detail}|_T{#ARRAY{titre,#GET{titre},connect_nom,#SESSION{nom}}})]
+[ (#VAL{date_fmt_nomjour_date}|_T{[(#ARRAY{'nomjour',[(#DATE|nom_jour)],'date',[(#DATE|affdate)]})]}).]
+</p>
+<hr />
+</div>
+
+<INCLURE{fond=notifications/inc-breve,id_breve} />
+</body>
+</BOUCLE_bre>
+#FILTRE{facteur_email_wrap_to_html}
diff --git a/www/plugins/notifications2/notifications/forum_poste.html b/www/plugins/notifications2/notifications/forum_poste.html
new file mode 100644 (file)
index 0000000..40af3e5
--- /dev/null
@@ -0,0 +1,70 @@
+[(#REM)
+
+Mail HTML simplifie mis en forme complete par le filtre |facteur_email_wrap_to_html
+
+
+]
+<title>[[(#NOM_SITE_SPIP|textebrut)]] [<:forum:forum_forum:>][ (#TITRE|nettoyer_titre_email)]</title>
+
+<intro>[*SPAM*(#STATUT|=={spam}|oui)][(#TEXTE|safehtml|couper{100})] | </intro>
+
+<body>
+       <div class="header">
+               [<p><strong><:forum:titre_cadre_forum_interne:></strong></p>(#STATUT|=={privrac}|oui)]
+               [<p><strong><:forum:titre_cadre_forum_administrateur:></strong></p>(#STATUT|=={priadm}|oui)]
+               [
+               (#ENV{par_auteur})
+               <br />]
+               [<a href="(#ENV{url_site})">[(#NOM_SITE|sinon{#ENV{url_site}})]</a>]
+               <hr/>
+       </div>
+       <h2>[<b>(SPAM)</b>(#STATUT|=={spam}|oui)]#TITRE</h2>
+       [
+       (#TEXTE|safehtml)
+       ]
+       <B_doc>
+               <h4>[(#TOTAL_BOUCLE|singulier_ou_pluriel{medias:un_document,medias:des_documents})]</h4>
+               <ul>
+               <BOUCLE_doc(DOCUMENTS){id_forum}>
+                       <li>
+                               <a href="[(#URL_DOCUMENT|url_absolue)]">#URL_DOCUMENT</a>
+                               <br /><small>([<abbr title="<:info_document:> #TYPE_DOCUMENT" class="ext">(#EXTENSION|strtoupper)</abbr> - ][<span>(#TAILLE|taille_en_octets)</span>])</small>
+                       </li>
+               </BOUCLE_doc>
+               </ul>
+       </B_doc>
+
+       <div class="footer">
+               <hr/>
+               <h3><:notifications:titre_moderation:></h3>
+               <p>
+               [
+               (#STATUT|=={publie}|oui)<:forum:forum_ne_repondez_pas:>][
+               (#STATUT|=={prop}|oui)<:notifications:message_a_valider:>][
+               (#STATUT|=={spam}|oui)<:notifications:message_spam_a_confirmer:>][
+               <a href="(#ENV{url}|url_absolue)">[(#ENV{url}|url_absolue)]</a>]
+               <br />
+               <br />
+               </p>
+
+               [(#ENV{url_moderer_publie}|ou{#ENV{url_moderer_off}}|ou{#ENV{url_moderer_spam}})
+               <div style="text-align:center;"><center>
+               [(#ENV{url_moderer_publie}|oui)<span style="display: inline-block;margin-bottom: 1em">[(#INCLURE{fond=emails/inc-button,url=#ENV{url_moderer_publie},label=<:notifications:info_lien_publier_commentaire:>,bgcolor=#96A05B})]</span>]
+               [(#ENV{url_moderer_off}|oui)<span style="display: inline-block;margin-bottom: 1em">[(#INCLURE{fond=emails/inc-button,url=#ENV{url_moderer_off},label=<:notifications:info_lien_supprimer_commentaire:>,bgcolor=#BE4848})]</span>]
+               [(#ENV{url_moderer_spam}|oui)<span style="display: inline-block;margin-bottom: 1em">[(#INCLURE{fond=emails/inc-button,url=#ENV{url_moderer_spam},label=<:notifications:info_lien_signaler_spam_commentaire:>,bgcolor=#666666})]</span>]
+               </center></div>
+               ]
+
+               [<p><strong><:forum:info_liens_texte:>&nbsp;:</strong><br />(#LIENS)</p>]
+
+
+               [
+               <br />
+               (#CONFIG{notifications/suivi}|oui)
+               [<p><a href="(#ENV{notification_email}|notifications_url_suivi)"><:notifications:suivi_texte_acces_page:></a></p>]
+               ]
+       </div>
+
+</body>
+
+#FILTRE{facteur_email_wrap_to_html}
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/forumposte.php b/www/plugins/notifications2/notifications/forumposte.php
new file mode 100644 (file)
index 0000000..2520452
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * cette notification s'execute quand un message est poste,
+ *
+ * @param string $quoi
+ * @param int $id_forum
+ */
+function notifications_forumposte_dist($quoi, $id_forum, $options) {
+       $t = sql_fetsel("*", "spip_forum", "id_forum=".intval($id_forum));
+       if (!$t)
+               return;
+
+       // plugin notification si present
+       $prevenir_auteurs = isset($GLOBALS['notifications']['prevenir_auteurs']) AND $GLOBALS['notifications']['prevenir_auteurs'];
+       // sinon voie normale
+       if ($t['objet']=='article' AND $t['id_objet'] AND !$prevenir_auteurs){
+               $s = sql_getfetsel('accepter_forum','spip_articles',"id_article=" . $t['id_objet']);
+               if (!$s)  $s = substr($GLOBALS['meta']["forums_publics"],0,3);
+
+               $prevenir_auteurs = (strpos(@$GLOBALS['meta']['prevenir_auteurs'],",$s,")!==false
+                       OR @$GLOBALS['meta']['prevenir_auteurs'] === 'oui'); // compat
+       }
+
+       include_spip('inc/texte');
+       include_spip('inc/filtres');
+       include_spip('inc/autoriser');
+
+       // Qui va-t-on prevenir ?
+       $tous = array();
+
+       // 1. Les auteurs de l'objet lie au forum
+       // seulement s'ils ont le droit de le moderer (les autres seront
+       // avertis par la notifications_forumvalide).
+       if ($prevenir_auteurs) {
+               $result = sql_select("auteurs.*","spip_auteurs AS auteurs JOIN spip_auteurs_liens AS lien","lien.objet=".sql_quote($t['objet'])." AND lien.id_objet=".intval($t['id_objet'])." AND auteurs.id_auteur=lien.id_auteur");
+
+               while ($qui = sql_fetch($result)) {
+                       if ($qui['email'] AND autoriser('modererforum', $t['objet'], $t['id_objet'], $qui['id_auteur']))
+                               $tous[] = $qui['email'];
+               }
+       }
+
+       $options['forum'] = $t;
+       $destinataires = pipeline('notifications_destinataires',
+               array(
+                       'args'=>array('quoi'=>$quoi,'id'=>$id_forum,'options'=>$options)
+               ,
+                       'data'=>$tous)
+       );
+
+       // Nettoyer le tableau
+       // Ne pas ecrire au posteur du message !
+       notifications_nettoyer_emails($destinataires,array($t['email_auteur']));
+
+       //
+       // Envoyer les emails
+       //
+
+       // preparer le calcul des liens de moderation
+       $moderations = array();
+       foreach(array('publie','spam','off') as $statut){
+               if ($statut!==$t['statut']){
+                       $moderations["url_moderer_$statut"] = "$id_forum-$statut-".$t['statut'];
+               }
+       }
+       include_spip("inc/securiser_action");
+       $action = 'instituer_forum_paremail';
+       $pass = secret_du_site();
+
+
+       $email_notification_forum = charger_fonction('email_notification_forum','inc');
+       foreach ($destinataires as $email) {
+               // ajouter les liens de moderation par statut
+               $contexte = array('notification_email'=>$email);
+               foreach($moderations as $k=>$arg){
+                       $arg = "$arg-$email";
+                       $hash = _action_auteur("$action-$arg", '', $pass, 'alea_ephemere');
+                       $contexte[$k] = generer_url_action($action, "arg=$arg&hash=$hash", true, true);
+               }
+
+               $texte = $email_notification_forum($t, $email, $contexte);
+               notifications_envoyer_mails_texte_ou_html($email, $texte);
+       }
+
+       // Notifier les autres si le forum est valide
+       // est-ce que cet appel devrait bien etre la ?
+       if ($t['statut'] == 'publie') {
+               $notifications = charger_fonction('notifications', 'inc');
+               $notifications('forumvalide', $id_forum);
+       }
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/forumprive.php b/www/plugins/notifications2/notifications/forumprive.php
new file mode 100644 (file)
index 0000000..23e0157
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * notification appelee quand on poste un forum prive
+ *
+ * @param string $quoi
+ * @param int $id_forum
+ * @param array $options
+ * @return <type>
+ */
+function notifications_forumprive_dist($quoi, $id_forum, $options) {
+       include_spip('base/abstract_sql');
+
+       $t = sql_fetsel("*", "spip_forum", "id_forum=".intval($id_forum));
+       if (!$t)
+               return;
+
+       include_spip('inc/texte');
+       include_spip('inc/filtres');
+       include_spip('inc/autoriser');
+
+       // Qui va-t-on prevenir ?
+       $tous = array();
+
+       // 1. Prevenir les auteurs
+       if ($GLOBALS['notifications']['prevenir_auteurs_prive']) {
+
+               // 1.1. Les auteurs du message (si c'est un message)
+               if ($t['objet']=='message' AND $t['id_objet']) {
+                       $result = sql_select("auteurs.email","spip_auteurs AS auteurs JOIN spip_auteurs_liens AS lien ON auteurs.id_auteur=lien.id_auteur","lien.objet='message' AND lien.id_objet=".intval($t['id_objet']));
+
+                       while ($qui = sql_fetch($result))
+                               $tous[] = $qui['email'];
+
+                       $url = url_absolue(generer_url_entite($t['id_objet'], 'message'));
+                       $t['texte'] .= "\n\n"._T('forum_ne_repondez_pas')."\n<html>$url</html>";
+               }
+
+               // 1.2. Les auteurs de l'article (si c'est un article)
+               elseif ($t['objet']=='article' AND $t['id_objet']) {
+                       $result = sql_select("auteurs.email","spip_auteurs AS auteurs JOIN spip_auteurs_liens AS lien ON auteurs.id_auteur=lien.id_auteur","lien.objet='article' AND lien.id_objet=".intval($t['id_objet']));
+
+                       while ($qui = sql_fetch($result))
+                               $tous[] = $qui['email'];
+               }
+       }
+
+// 2. Les moderateurs
+       if ($GLOBALS['notifications']['moderateurs_forum_prive']){
+               foreach (explode(',', $GLOBALS['notifications']['moderateurs_forum_prive']) as $m) {
+                       $tous[] = $m;
+               }
+       }
+
+       $options['forum'] = $t;
+       $destinataires = pipeline('notifications_destinataires',
+               array(
+                       'args'=>array('quoi'=>$quoi,'id'=>$id_forum,'options'=>$options)
+               ,
+                       'data'=>$tous)
+       );
+
+       // Nettoyer le tableau
+       // Ne pas ecrire au posteur du message !
+       notifications_nettoyer_emails($destinataires,array($t['email_auteur']));
+
+       //
+       // Envoyer les emails
+       //
+       $email_notification_forum = charger_fonction('email_notification_forum','inc');
+       foreach ($destinataires as $email) {
+               $texte = $email_notification_forum($t, $email);
+               notifications_envoyer_mails_texte_ou_html($email, $texte);
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/forumvalide.php b/www/plugins/notifications2/notifications/forumvalide.php
new file mode 100644 (file)
index 0000000..c7a1a47
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * cette notification s'execute quand on valide un message 'prop'ose,
+ * dans ecrire/inc/forum_insert.php ; ici on va notifier ceux qui ne l'ont
+ * pas ete a la notification forumposte (sachant que les deux peuvent se
+ * suivre si le forum est valide directement ('pos' ou 'abo')
+ * http://doc.spip.org/@notifications_forumvalide_dist
+ *
+ * @param string $quoi
+ * @param int $id_forum
+ */
+function notifications_forumvalide_dist($quoi, $id_forum, $options) {
+
+       $t = sql_fetsel("*", "spip_forum", "id_forum=".intval($id_forum));
+       if (!$t
+               // forum sur un message prive : pas de notification ici (cron)
+               OR @$t['statut'] == 'perso')
+               return;
+
+       // plugin notification si present
+       $prevenir_auteurs = isset($GLOBALS['notifications']['prevenir_auteurs']) AND $GLOBALS['notifications']['prevenir_auteurs'];
+       // sinon voie normale
+       if ($t['objet']=='article' AND $t['id_objet'] AND !$prevenir_auteurs){
+               $s = sql_getfetsel('accepter_forum','spip_articles',"id_article=" . $t['id_objet']);
+               if (!$s)  $s = substr($GLOBALS['meta']["forums_publics"],0,3);
+
+               $prevenir_auteurs = (strpos(@$GLOBALS['meta']['prevenir_auteurs'],",$s,")!==false
+                       OR @$GLOBALS['meta']['prevenir_auteurs'] === 'oui'); // compat
+       }
+
+       include_spip('inc/texte');
+       include_spip('inc/filtres');
+       include_spip('inc/autoriser');
+
+       // Qui va-t-on prevenir ?
+       $tous = array();
+       // Ne pas ecrire au posteur du message, ni au moderateur qui valide le forum,
+       $pasmoi = array($t['email_auteur'],$GLOBALS['visiteur_session']['email']);
+
+       // 1. Les auteurs de l'objet lie au forum
+       // seulement ceux qui n'ont
+       // pas le droit de le moderer (les autres l'ont recu plus tot)
+       if ($prevenir_auteurs) {
+               $result = sql_select("auteurs.*","spip_auteurs AS auteurs, spip_auteurs_liens AS lien","lien.objet=".sql_quote($t['objet'])." AND lien.id_objet=".intval($t['id_objet'])." AND auteurs.id_auteur=lien.id_auteur");
+
+               while ($qui = sql_fetch($result)) {
+                       if ($qui['email']) {
+                               if (!autoriser('modererforum', $t['objet'], $t['id_objet'], $qui['id_auteur']))
+                                       $tous[] = $qui['email'];
+                               else
+                                       // Ne pas ecrire aux auteurs deja notifies precedemment
+                                       $pasmoi[] = $qui['email'];
+                       }
+               }
+       }
+
+       $options['forum'] = $t;
+       $destinataires = pipeline('notifications_destinataires',
+               array(
+                       'args'=>array('quoi'=>$quoi,'id'=>$id_forum,'options'=>$options)
+               ,
+                       'data'=>$tous)
+       );
+
+       // Nettoyer le tableau
+       // en enlevant les exclus
+       notifications_nettoyer_emails($destinataires,$pasmoi);
+
+       //
+       // Envoyer les emails
+       //
+       $email_notification_forum = charger_fonction('email_notification_forum','inc');
+       foreach ($destinataires as $email) {
+               $contexte = array('notification_email'=>$email);
+               $texte = $email_notification_forum($t, $email, $contexte);
+               notifications_envoyer_mails_texte_ou_html($email, $texte);
+       }
+
+}
+
+?>
diff --git a/www/plugins/notifications2/notifications/inc-article.html b/www/plugins/notifications2/notifications/inc-article.html
new file mode 100644 (file)
index 0000000..b8c4563
--- /dev/null
@@ -0,0 +1,26 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<BOUCLE_art(ARTICLES){id_article}{statut?}{tout}>
+<div class="cartouche">
+       [<p class="surtitre">(#SURTITRE)</p>]
+       <h2 class="surlignable">[(#LOGO_ARTICLE_RUBRIQUE|image_reduire{40,*}) ]#TITRE</h2>
+       [<p class="soustitre">(#SOUSTITRE)</p>]
+       <p class="info-publi"><abbr class="published" title="[(#DATE|date_iso)]">[(#DATE|nom_jour) ][(#DATE|affdate)]</abbr>[<span class="sep">, </span><span class="auteurs"><:par_auteur:> (#LESAUTEURS)</span>]</p>
+</div>
+
+[<div class="chapo" style="font-weight: bold;">(#CHAPO|image_reduire{500,*})</div>]
+[<div class="texte">(#TEXTE|image_reduire{500,*})</div>]
+
+[<p class="hyperlien" style="font-style: italic"><:voir_en_ligne:> : <a href="(#URL_SITE)">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+[<div class="ps"><strong><:info_ps:></strong>(#PS|image_reduire{500,*})</div>]
+
+[(#REM) Gestion du portfolio et des documents ]
+[(#INCLURE{fond=inclure/documents,id_article, env})]
+
+[<div class="notes" style="border-top:1px solid #eee;font-size: 0.9em">(#NOTES)</div>]
+</BOUCLE_art>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/inc-breve.html b/www/plugins/notifications2/notifications/inc-breve.html
new file mode 100644 (file)
index 0000000..bba7116
--- /dev/null
@@ -0,0 +1,19 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+]
+<BOUCLE_bre(BREVES){id_breve}{statut?}{tout}>
+<div class="cartouche">
+       <h2 class="titre">[(#LOGO_BREVE_RUBRIQUE|image_reduire{40,*}) ]#TITRE</h2>
+       <p class="info-publi"><abbr class="published" title="[(#DATE|date_iso)]">[(#DATE|nom_jour) ][(#DATE|affdate)]</abbr></p>
+</div>
+
+[<div class="texte">(#TEXTE|image_reduire{500,*})</div>]
+
+[<p class="hyperlien" style="font-style: italic"><:voir_en_ligne:> : <a href="(#URL_SITE)">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+
+[<div class="notes" style="border-top:1px solid #eee;font-size: 0.9em">(#NOTES)</div>]
+</BOUCLE_bre>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/inscription.html b/www/plugins/notifications2/notifications/inscription.html
new file mode 100644 (file)
index 0000000..484e348
--- /dev/null
@@ -0,0 +1,18 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+][(#HTTP_HEADER{Content-type: text/plain[; charset=(#CHARSET)]})]
+<BOUCLE_auteur(AUTEURS){id_auteur}{tout}>
+Inscription sur le site [(#NOM_SITE_SPIP|nettoyer_titre_email)]
+
+
+Nom : #NOM
+email : #EMAIL
+
+** [(#URL_AUTEUR|url_absolue)]
+
+</BOUCLE_auteur>
+#FILTRE{supprimer_tags|filtrer_entites|trim}
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/inscription.php b/www/plugins/notifications2/notifications/inscription.php
new file mode 100644 (file)
index 0000000..a37f4bb
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * inscription d'un nouvel auteur => mail aux admins
+ *
+ * @param string $quoi
+ * @param int $id_auteur
+ * @options array $options
+ */
+function notifications_inscription_dist($quoi, $id_auteur, $options) {
+       if (!isset($GLOBALS['notifications']['inscription'])
+         OR !$GLOBALS['notifications']['inscription'])
+               return;
+       
+       $modele = "notifications/inscription";
+
+       $destinataires = array();
+       
+       $query = sql_select("email","spip_auteurs","statut = '0minirezo'");
+
+       // notifier uniquement les webmestres ?
+       if ($GLOBALS['notifications']['inscription'] == 'webmestres') {
+               $query = sql_select("email","spip_auteurs","statut = '0minirezo' AND webmestre = 'oui'");
+       }
+
+       while ($row = sql_fetch($query)) {
+               $destinataires[] = $row["email"];
+       }
+
+       $destinataires = pipeline('notifications_destinataires',
+               array(
+                       'args'=>array('quoi'=>$quoi,'id'=>$id_auteur,'options'=>$options)
+               ,
+                       'data'=>$destinataires)
+       );
+
+       $envoyer_mail = charger_fonction('envoyer_mail','inc'); // pour nettoyer_titre_email
+       $texte = recuperer_fond($modele,array('id_auteur'=>$id_auteur));
+       
+       notifications_envoyer_mails($destinataires, $texte);
+
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/instituerarticle.php b/www/plugins/notifications2/notifications/instituerarticle.php
new file mode 100644 (file)
index 0000000..bd4b7c3
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// Fonction appelee par divers pipelines
+// http://doc.spip.org/@notifications_instituerarticle_dist
+function notifications_instituerarticle_dist($quoi, $id_article, $options) {
+
+       // ne devrait jamais se produire
+       if ($options['statut'] == $options['statut_ancien']) {
+               spip_log("statut inchange",'notifications');
+               return;
+       }
+
+       include_spip('inc/texte');
+
+       $modele = "";
+       if ($options['statut'] == 'publie') {
+               if ($GLOBALS['meta']["post_dates"]=='non'
+                       AND strtotime($options['date'])>time())
+                       $modele = "notifications/article_valide";
+               else
+                       $modele = "notifications/article_publie";
+       }
+
+       if ($options['statut'] == 'prop' AND $options['statut_ancien'] != 'publie')
+               $modele = "notifications/article_propose";
+
+       if ($modele){
+               $destinataires = array();
+               if ($GLOBALS['meta']["suivi_edito"] == "oui")
+                       $destinataires = explode(',',$GLOBALS['meta']["adresse_suivi"]);
+
+
+               $destinataires = pipeline('notifications_destinataires',
+                       array(
+                               'args'=>array('quoi'=>$quoi,'id'=>$id_article,'options'=>$options)
+                       ,
+                               'data'=>$destinataires)
+               );
+
+               $texte = email_notification_objet($id_article, "article", $modele);
+               notifications_envoyer_mails($destinataires, $texte);
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/instituerbreve.php b/www/plugins/notifications2/notifications/instituerbreve.php
new file mode 100644 (file)
index 0000000..9ecae30
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// Fonction appelee par divers pipelines
+// http://doc.spip.org/@notifications_instituerbreve_dist
+function notifications_instituerbreve_dist($quoi, $id_breve, $options) {
+
+       // ne devrait jamais se produire
+       if ($options['statut'] == $options['statut_ancien']) {
+               spip_log("statut inchange",'notifications');
+               return;
+       }
+
+       include_spip('inc/texte');
+
+       $modele = "";
+       if ($options['statut'] == 'publie') {
+               $modele = "notifications/breve_publie";
+       }
+
+       if ($options['statut'] == 'prop' AND $options['statut_ancien'] != 'publie')
+               $modele = "notifications/breve_propose";
+
+       if ($modele){
+               $destinataires = array();
+               if ($GLOBALS['meta']["suivi_edito"] == "oui")
+                       $destinataires = explode(',',$GLOBALS['meta']["adresse_suivi"]);
+
+
+               $destinataires = pipeline('notifications_destinataires',
+                       array(
+                               'args'=>array('quoi'=>$quoi,'id'=>$id_breve,'options'=>$options)
+                       ,
+                               'data'=>$destinataires)
+               );
+
+               $texte = email_notification_objet($id_breve, "breve", $modele);
+               notifications_envoyer_mails($destinataires, $texte);
+       }
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/petition_signee.html b/www/plugins/notifications2/notifications/petition_signee.html
new file mode 100644 (file)
index 0000000..a815fa1
--- /dev/null
@@ -0,0 +1,26 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 SPIP
+  Distribue sous licence GPL
+
+][(#HTTP_HEADER{Content-type: text/plain[; charset=(#CHARSET)]})]
+<BOUCLE_sign(SIGNATURES){id_signature}{tout}>
+<BOUCLE_art(ARTICLES){id_petition}{statut==.*}{tout}>
+Nouvelle signature pour la petition [ (#TITRE|nettoyer_titre_email)]
+
+** [(#URL_ARTICLE|url_absolue)]
+
+Nom: #NOM_EMAIL
+email: #AD_EMAIL
+message: #MESSAGE
+nom_site: #_sign:NOM_SITE
+url_site: #_sign:URL_SITE
+
+Cette signature n'a pas encore ete validee
+si vous souhaitez la supprimer directement :
+[(#URL_ARTICLE|parametre_url{var_confirm,#ID_SIGNATURE}|parametre_url{refus,#ENV{cle},'&'}|ancre_url{sp#ID_ARTICLE}|url_absolue)]
+
+</BOUCLE_art>
+</BOUCLE_sign>
+#FILTRE{supprimer_tags|filtrer_entites|trim}
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications/petitionsignee.php b/www/plugins/notifications2/notifications/petitionsignee.php
new file mode 100644 (file)
index 0000000..0b9af75
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * insertion d'une nouvelle signature => mail aux moderateurs
+ *
+ * @param string $quoi
+ * @param int $id_forum
+ */
+function notifications_petitionsignee_dist($quoi, $id_signature, $options) {
+       if (!isset($GLOBALS['notifications']['moderateurs_signatures'])
+         OR !$GLOBALS['notifications']['moderateurs_signatures'])
+               return;
+
+       // creer la cle de suppression de la signature
+       // old style ...
+       // il faudrait passer par une action et une redirection
+       // ce qui necessite de pouvoir generer une action pour un autre auteur que celui connecte
+       // grml
+       include_spip('inc/securiser_action');
+       $cle = _action_auteur("supprimer signature $id_signature", '', '', 'alea_ephemere');
+
+       $envoyer_mail = charger_fonction('envoyer_mail','inc'); // pour nettoyer_titre_email
+       $texte = recuperer_fond("notifications/petition_signee",array('id_signature'=>$id_signature,'cle'=>$cle));
+       
+       notifications_envoyer_mails($GLOBALS['notifications']['moderateurs_signatures'],$texte);
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/notifications2/notifications_administrations.php b/www/plugins/notifications2/notifications_administrations.php
new file mode 100644 (file)
index 0000000..11062d4
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+/**
+ * Declarer le champ notification_email sur la table forum
+ *
+ * @param array $tables
+ * @return array
+ */
+function notifications_declarer_tables_objets_sql($tables){
+
+       // champ notification (editable via le form de forum) :
+       // 0/1 (non abonne/abonne) defaut 1
+       $tables['spip_forum']['field']['notification'] = "tinyint NOT NULL default 1";
+       $tables['spip_forum']['champs_editables'][] = 'notification';
+
+       // champ notification_email :
+       // vide -> notification par le champ id_auteur ou email_auteur
+       // email -> notification sur cet email (permet de maj l'email de notif sans modifier l'email de signature)
+       $tables['spip_forum']['field']['notification_email'] = "text DEFAULT '' NOT NULL";
+
+       return $tables;
+}
+
+
+/**
+ * maj de table forum
+ *
+ * @param string $nom_meta_base_version
+ * @param string $version_cible
+ */
+function notifications_upgrade($nom_meta_base_version,$version_cible){
+
+       $maj = array();
+       $maj['create'] = array(
+               array('maj_tables',array('spip_forum')),
+       );
+
+       $maj['0.1.3'] = array(
+               array('sql_alter',"TABLE spip_forum CHANGE notification notification_email text DEFAULT '' NOT NULL"),
+               array('maj_tables',array('spip_forum')),
+       );
+
+       include_spip('base/upgrade');
+       maj_plugin($nom_meta_base_version, $version_cible, $maj);
+}
+
+function notifications_vider_tables($nom_meta_base_version) {
+       #on ne drop pas pour ne pas perdre les reglages.. a voir
+       #sql_alter("TABLE spip_forum DROP COLUMN notification");
+       effacer_meta($nom_meta_base_version);
+}
diff --git a/www/plugins/notifications2/notifications_pipelines.php b/www/plugins/notifications2/notifications_pipelines.php
new file mode 100644 (file)
index 0000000..7954879
--- /dev/null
@@ -0,0 +1,330 @@
+<?php
+/*
+ * Plugin Notifications
+ * (c) 2009-2012 SPIP
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ *
+ * Declarer la tache cron de notification lente (messagerie de l'espace prive)
+ * @param array $taches_generales
+ * @return array
+ */
+function notifications_taches_generales_cron($taches_generales){
+       $taches_generales['notifications'] = 60*10; // toutes les 10 minutes
+       return $taches_generales;
+}
+
+$GLOBALS['notifications_post_edition']['spip_signatures'] = "petitionsignee";
+
+// Initialise les reglages sous forme de tableau
+function notifications_go($x){
+       if (!is_array($GLOBALS['notifications'] = @unserialize($GLOBALS['meta']['notifications'])))
+               $GLOBALS['notifications'] = array();
+       return $x;
+}
+
+
+/**
+ * Pipeline post-edition
+ * pour permettre de se pluger sur une modification en base non notifiee par defaut
+ *
+ * @param array $x
+ * @return array
+ */
+function notifications_post_edition($x){
+       #spip_log($x,'notifications');
+       if (isset($x['args']['table'])
+               AND $quoi = $GLOBALS['notifications_post_edition'][$x['args']['table']]
+       ){
+               // repasser par l'entree principale
+               $notifications = charger_fonction('notifications', 'inc');
+               $notifications($quoi, $x['args']['id_objet'], array());
+       }
+
+       return $x;
+}
+
+/**
+ * Ajouter des destinataires dans une notification en lot
+ *
+ * @param array $flux
+ * @return array
+ */
+function notifications_notifications_destinataires($flux){
+       static $sent = array();
+       $quoi = $flux['args']['quoi'];
+       $options = $flux['args']['options'];
+
+       // proposition d'article prevenir les admins restreints
+       if ($quoi=='instituerarticle' AND $GLOBALS['notifications']['prevenir_admins_restreints']
+               AND $options['statut']=='prop' AND $options['statut_ancien']!='publie' // ligne a commenter si vous voulez prevenir de la publication
+       ){
+
+               $id_article = $flux['args']['id'];
+               include_spip('base/abstract_sql');
+               $t = sql_fetsel("id_rubrique", "spip_articles", "id_article=" . intval($id_article));
+               $id_rubrique = $t['id_rubrique'];
+
+               while ($id_rubrique){
+                       $hierarchie[] = $id_rubrique;
+                       $res = sql_fetsel("id_parent", "spip_rubriques", "id_rubrique=" . intval($id_rubrique));
+                       if (!$res){ // rubrique inexistante
+                               $id_rubrique = 0;
+                               break;
+                       }
+                       $id_parent = $res['id_parent'];
+                       $id_rubrique = $id_parent;
+               }
+               spip_log("Prop article > admin restreint de " . join(',', $hierarchie), 'notifications');
+
+               //les admins de la rub et de ses parents 
+               $result_email = sql_select(
+                       "auteurs.email,auteurs.id_auteur,lien.id_objet as id_rubrique",
+                       "spip_auteurs AS auteurs JOIN spip_auteurs_liens AS lien ON auteurs.id_auteur=lien.id_auteur ",
+                       "lien.objet='rubrique' AND ".sql_in('lien.id_objet',sql_quote($hierarchie))." AND auteurs.statut='0minirezo'");
+
+               while ($qui = sql_fetch($result_email)){
+                       spip_log($options['statut'] . " article > admin restreint " . $qui['id_auteur'] . " de la rubrique" . $qui['id_rubrique'] . " prevenu", 'notifications');
+                       $flux['data'][] = $qui['email'];
+               }
+
+       }
+
+       // publication d'article : prevenir les auteurs
+       if ($quoi=='instituerarticle'
+               AND $GLOBALS['notifications']['prevenir_auteurs_articles']
+       ){
+               $id_article = $flux['args']['id'];
+
+
+               include_spip('base/abstract_sql');
+
+               // Qui va-t-on prevenir en plus ?
+               $result_email = sql_select(
+                       "auteurs.email",
+                       "spip_auteurs AS auteurs JOIN spip_auteurs_liens AS lien ON auteurs.id_auteur=lien.id_auteur",
+                       "lien.id_objet=".intval($id_article)." AND lien.objet='article'");
+
+               while ($qui = sql_fetch($result_email)){
+                       $flux['data'][] = $qui['email'];
+                       spip_log($options['statut'] . " article > auteur " . $qui['id_auteur'] . " prevenu", 'notifications');
+               }
+
+       }
+
+       // forum valide ou prive : prevenir les autres contributeurs du thread
+       if (($quoi=='forumprive' AND $GLOBALS['notifications']['thread_forum_prive'])
+               OR ($quoi=='forumvalide' AND $GLOBALS['notifications']['thread_forum'])
+       ){
+
+               $id_forum = $flux['args']['id'];
+
+               if ($t = $options['forum']
+                       OR $t = sql_fetsel("*", "spip_forum", "id_forum=" . intval($id_forum))
+               ){
+
+                       // Tous les participants a ce *thread*, abonnes
+                       // on prend les emails parmi notification_email (prioritaire si rempli) email_auteur ou email de l'auteur qd id_auteur connu
+                       $s = sql_select("F.email_auteur, F.notification_email, A.email",
+                               "spip_forum AS F LEFT JOIN spip_auteurs AS A ON F.id_auteur=A.id_auteur",
+                               "notification=1 AND id_thread=" . intval($t['id_thread']) . " AND (email_auteur != '' OR notification_email != '' OR A.email IS NOT NULL )");
+                       while ($r = sql_fetch($s)){
+                               if ($r['notification_email'])
+                                       $flux['data'][] = $r['notification_email'];
+                               elseif($r['email_auteur'])
+                                       $flux['data'][] = $r['email_auteur'];
+                               elseif($r['email'])
+                                       $flux['data'][] = $r['email'];
+                       }
+
+                       /*
+                       // 3. Tous les auteurs des messages qui precedent (desactive egalement)
+                       // (possibilite exclusive de la possibilite precedente)
+                       // TODO: est-ce utile, par rapport au thread ?
+                       else if (defined('_SUIVI_FORUMS_REPONSES')
+                       AND _SUIVI_FORUMS_REPONSES) {
+                               $id_parent = $id_forum;
+                               while ($r = spip_fetch_array(spip_query("SELECT email_auteur, id_parent FROM spip_forum WHERE id_forum=$id_parent AND statut='publie'"))) {
+                                       $tous[] = $r['email_auteur'];
+                                       $id_parent = $r['id_parent'];
+                               }
+                       }
+                       */
+               }
+       }
+
+       // Les moderateurs de forums public
+       if ($quoi=='forumposte' AND $GLOBALS['notifications']['moderateurs_forum']){
+               foreach (explode(',', $GLOBALS['notifications']['moderateurs_forum']) as $m){
+                       $flux['data'][] = $m;
+               }
+       }
+
+       // noter les envois de ce forum pour ne pas doublonner
+       if (in_array($quoi, array('forumposte', 'forumvalide', 'forumprive'))
+               AND $id = $flux['args']['id']
+       ){
+               if (isset($sent[$id])){
+                       $flux['data'] = array_diff($flux['data'], $sent[$id]);
+               } else {
+                       $sent[$id] = array();
+               }
+               $sent[$id] = array_merge($sent[$id], $flux['data']);
+       }
+
+       return $flux;
+}
+
+
+/**
+ * Pipeline notifications_envoyer_mails
+ * appele a chaque envoi de mails
+ * permet de gerer les contributeurs :
+ *  - inscription auto si activee
+ *  - url de suivi des forums
+ *
+ * @param array $flux
+ * @return array
+ */
+/*
+function notifications_notifications_envoyer_mails($flux){
+       if ($GLOBALS['notifications']['suivi']){
+
+               // ajouter un acces a la page de suivi
+               $url = url_absolue(generer_url_public('suivi', 'email=' . $flux['email']));
+               $flux['texte'] .= "\n\n" . _L('Gerer mes abonnements : ') . $url;
+
+               // ajouter les auteurs en base ?
+               // ici ou dans la page de suivi lorsqu'ils essayent vraiment de gerer
+               // leurs abonnements ?
+               // $a = notifications_creer_auteur($email);
+       }
+
+       return $flux;
+}
+*/
+
+function notifications_url_suivi($email){
+       if (!$email) return "";
+       include_spip("inc/securiser_action");
+       $key = calculer_cle_action("abonner_notifications $email");
+       $url = url_absolue(generer_url_public('notifications', "email=$email&key=$key"));
+       return $url;
+}
+
+/**
+ * Regarder si l'auteur est dans la base de donnees, sinon l'ajouter
+ * comme s'il avait demande a s'inscrire comme visiteur
+ * Pour l'historique il faut retrouver le nom de la personne,
+ * pour ca on va regarder dans les forums existants
+ * Si c'est la personne connectee, c'est plus facile
+ *
+ * @param string $email
+ * @return array|bool
+ */
+function notifications_creer_auteur($email){
+
+       include_spip('base/abstract_sql');
+       if (!$a = sql_fetsel('*', 'spip_auteurs', 'email=' . sql_quote($email))){
+               if ($GLOBALS['visiteur_session']['session_email']===$email
+                       AND isset($GLOBALS['visiteur_session']['session_nom'])
+               ){
+                       $nom = $GLOBALS['visiteur_session']['session_nom'];
+               } else {
+                       if ($b = sql_fetsel('auteur', 'spip_forum',
+                               'email_auteur=' . sql_quote($email) . ' AND auteur!=""',
+                               /* groupby */
+                               '', /* orderby */
+                               array('date_heure DESC'),
+                               /* limit */
+                               '1')
+                       ){
+                               $nom = $b['auteur'];
+                       } else {
+                               $nom = $email;
+                       }
+               }
+               // charger message_inscription()
+               if ($traiter = charger_fonction('traiter', 'formulaires/inscription', true)){
+                       // "pirater" les globals
+                       $_GET['nom_inscription'] = $nom;
+                       $_GET['email_inscription'] = $email;
+                       $a = $traiter('6forum', null);
+               }
+               if (!is_array($a)){
+                       spip_log("erreur sur la creation d'auteur: $a", 'notifications');
+                       next;
+               }
+       }
+
+       // lui donner un cookie_oubli s'il n'en a pas deja un
+       if (!isset($a['cookie_oubli'])){
+               include_spip('inc/acces'); # pour creer_uniqid
+               $a['cookie_oubli'] = creer_uniqid();
+               sql_updateq('spip_auteurs',
+                       array('cookie_oubli' => $a['cookie_oubli']),
+                       'id_auteur=' . $a['id_auteur']
+               );
+       }
+
+       return $a;
+}
+
+/**
+ * Pretraiter le mail/sujet quand il est au format html
+ * pour la fonction notifications_envoyer_mails qui ne sait traiter que les mails html
+ *
+ * @param string $email
+ * @param $texte_ou_html
+ */
+function notifications_envoyer_mails_texte_ou_html($email, $texte_ou_html){
+       $texte_ou_html = trim($texte_ou_html);
+
+       // tester si le mail est deja en html
+       if (substr($texte_ou_html,0,1)=="<"
+         AND substr($texte_ou_html,-1,1)==">"
+         AND stripos($texte_ou_html,"</html>")!==false){
+
+               // dans ce cas on ruse un peu : extraire le sujet du title
+               $sujet = "";
+               if (preg_match(",<title>(.*)</title>,Uims",$texte_ou_html,$m))
+                       $sujet = $m[1];
+
+               // et envoyer un content-type pour envoyer_mail
+               return notifications_envoyer_mails($email, $texte_ou_html, $sujet, "","Content-Type: text/html\n");
+       }
+       else
+               // texte brut, on passe
+               return notifications_envoyer_mails($email, $texte_ou_html);
+}
+
+/* TODO
+       // Envoyer un message de bienvenue/connexion au posteur du forum,
+       // dans le cas ou il ne s'est pas authentifie
+       // Souci : ne pas notifier comme ca si on est deja present dans le thread
+       // (eviter d'avoir deux notificaitons pour ce message qu'on a, dans 99,99%
+       // des cas, poste nous-memes !)
+       if (strlen(trim($t['email_auteur']))
+       AND email_valide($t['email_auteur'])
+       AND !$GLOBALS['visiteur_session']['id_auteur']) {
+               $msg = Notifications_jeuneposteur($t, $email);
+               if ($t['email_auteur'] == 'fil@rezo.net')
+                       notifications_envoyer_mails($t['email_auteur'], $msg['body'],$msg['subject'])
+       }
+*/
+
+
+/*
+// Creer un mail pour les forums envoyes par quelqu'un qui n'est pas authentifie
+// en lui souhaitant la bienvenue et avec un lien suivi&p= de connexion au site
+function Notifications_jeuneposteur($t, $email) {
+       return array('test', 'coucou');
+}
+*/
+
+?>
diff --git a/www/plugins/notifications2/nouveautes.html b/www/plugins/notifications2/nouveautes.html
new file mode 100644 (file)
index 0000000..5bd9232
--- /dev/null
@@ -0,0 +1,32 @@
+<B_test_contenu><title>[[(#NOM_SITE_SPIP|textebrut)]] <:nouveautes:></title>
+
+
+<body>
+<div class="header">
+<p><:bonjour:></p>
+<p><:texte_lettre_information:> "[(#NOM_SITE_SPIP|textebrut)]" (#URL_SITE_SPIP).</p>
+<p><:texte_lettre_information_2:> [(#ENV{jours_neuf})] <:jours:>.</p>
+</div>
+
+<BOUCLE_test_contenu(AUTEURS){0,1}{tous}><B_nv1>
+
+<h1><:nouveaux_articles:></h1>
+<hr />
+<BOUCLE_nv1(ARTICLES){age_relatif<=0}{par date}{inverse}{0,30}>
+<div style="padding-bottom:2em">
+<INCLURE{fond=notifications/inc-article,id_article} />
+<p><a href="[(#URL_ARTICLE|url_absolue)]">[(#URL_ARTICLE|url_absolue)]</a></p>
+</div>
+</BOUCLE_nv1><B_nv2>
+
+<h1><:nouvelles_breves:></h1>
+<hr />
+<BOUCLE_nv2(BREVES){age_relatif<=0}{par date}{inverse}{0,30}>
+<div style="padding-bottom:2em">
+<INCLURE{fond=notifications/inc-breve,id_breve} />
+<p><a href="[(#URL_BREVE|url_absolue)]">[(#URL_BREVE|url_absolue)]</a></p>
+</div>
+</BOUCLE_nv2></BOUCLE_test_contenu>
+</body>
+</B_test_contenu>
+#FILTRE{facteur_email_wrap_to_html}
\ No newline at end of file
diff --git a/www/plugins/notifications2/paquet.xml b/www/plugins/notifications2/paquet.xml
new file mode 100644 (file)
index 0000000..52a40b7
--- /dev/null
@@ -0,0 +1,29 @@
+<paquet
+       prefix="notifications"
+       categorie="communication"
+       version="3.0.10"
+       etat="stable"
+       compatibilite="[3.0.0;3.0.*]"
+       logo="notifications-32.png"
+       documentation="http://www.spip-contrib.net/Notifications,2360"
+       schema="0.1.3"
+>
+       <nom>Notifications</nom>
+
+       <auteur>fil@rezo.net</auteur>
+
+       <licence>GNU/GPL</licence>
+
+       <traduire gestionnaire="salvatore" module="crayons" reference="fr" />
+
+       <pipeline nom="declarer_tables_objets_sql" inclure="notifications_administrations.php"/>
+       <pipeline nom="taches_generales_cron" inclure="notifications_pipelines.php" />
+       <pipeline nom="post_edition" inclure="notifications_pipelines.php"/>
+       <pipeline nom="notifications_destinataires" inclure="notifications_pipelines.php"/>
+
+       <pipeline nom="notifications" inclure="notifications_pipelines.php" action="go" />
+
+       <utilise nom="forum" />
+       <necessite nom="facteur" compatibilite="[2.4.2;]"/>
+
+</paquet>
diff --git a/www/plugins/notifications2/prive/squelettes/contenu/configurer_notifications.html b/www/plugins/notifications2/prive/squelettes/contenu/configurer_notifications.html
new file mode 100644 (file)
index 0000000..6af670e
--- /dev/null
@@ -0,0 +1,5 @@
+[(#AUTORISER{configurer,notifications}|sinon_interdire_acces)]
+<h1 class="grostitre"><:notifications:notifications:></h1>
+<div class="ajax">
+#FORMULAIRE_CONFIGURER_NOTIFICATIONS
+</div>
\ No newline at end of file
diff --git a/www/plugins/notifications2/svn.revision b/www/plugins/notifications2/svn.revision
new file mode 100644 (file)
index 0000000..b4800aa
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/notifications/trunk
+Revision: 73845
+Dernier commit: 2013-06-25 06:00:41 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/notifications/trunk</origine>
+<revision>73845</revision>
+<commit>2013-06-25 06:00:41 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/action/odt2spip_importe.php b/www/plugins/odt2spip_30/action/odt2spip_importe.php
new file mode 100644 (file)
index 0000000..9043a0d
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * Créer un article à partir d'un fichier au format odt
+ *
+ * @author cy_altern
+ * @license GNU/LGPL
+ *
+ * @package plugins
+ * @subpackage odt2spip
+ * @category import
+ *
+ * @version $Id: odt2spip_importe.php 71726 2013-04-07 01:27:30Z cy_altern@yahoo.fr $
+ *
+ */
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Création de l'article et redirection vers celui-ci
+ *
+ * Le fichier .odt est envoyé par un formulaire, ainsi que des informations sur
+ * la rubrique dans laquelle créer l'article, un flag qui indique s'il faut joindre
+ * le document à l'article créé, etc..
+ * Cette fonction s'assure avant tout que l'utilisateur peut y ajouter un article.
+ * Le fichier .odt est traité et transformé en article.
+ * En fin de traitement, on est redirigé vers l'article qui vient d'être créé.
+ *
+ * {@internal
+ * Un répertoire temporaire, spécifique à l'utilisateur en cours, est utilisé et
+ * créé si nécessaire. Il est supprimé en fin de traitement.
+ * Le format odt correspond à une archive .zip, et regroupe le contenu dans un fichier
+ * content.xml : ce fichier est transformé par XSLT afin de générer un texte
+ * utilisant les balises SPIP pour sa mise en forme.
+ * }}
+ * 
+ */
+function action_odt2spip_importe() {
+       global $visiteur_session;
+
+       $id_auteur = $visiteur_session['id_auteur'];
+       $arg = _request('arg');
+       $args = explode(":", $arg);
+
+       // le 1er élément de _request('arg') est id_rubrique=XXX
+       $Targs = explode("=", $args[0]);
+       $id_rubrique = intval($Targs[1]);
+       $hash = _request('hash');
+
+       $redirect = _request('redirect');
+       if ($redirect == NULL) {
+               $redirect = "";
+       }
+
+       include_spip("inc/securiser_action");
+
+       if (!autoriser('creerarticledans', 'rubrique', $id_rubrique)) {
+               die(_T('avis_non_acces_page'));
+       }
+
+       // ss-rep temporaire specifique de l'auteur en cours: tmp/odt2spip/id_auteur/
+       // => le créer s'il n'existe pas
+       $base_dezip = _DIR_TMP . "odt2spip/";     // avec / final
+       if (!is_dir($base_dezip) AND !sous_repertoire(_DIR_TMP, 'odt2spip')) {
+               die (_T('odtspip:err_repertoire_tmp'));
+       }
+       $rep_dezip = $base_dezip . $id_auteur . '/';
+       if (!is_dir($rep_dezip) AND !sous_repertoire($base_dezip, $id_auteur)) {
+               die (_T('odtspip:err_repertoire_tmp'));
+       }
+    $rep_pictures = $rep_dezip."Pictures/";
+    
+       // paramètres de conversion de taille des images : cm -> px (en 96 dpi puisque c'est ce que semble utiliser Writer)
+       $conversion_image = 96/2.54;
+    
+       // traitement d'un fichier odt envoye par $_POST
+       $fichier_zip = addslashes($_FILES['fichier_odt']['name']);
+       if ($_FILES['fichier_odt']['name'] == '' 
+           OR $_FILES['fichier_odt']['error'] != 0
+           OR !move_uploaded_file($_FILES['fichier_odt']['tmp_name'], $rep_dezip . $fichier_zip)) {
+               die(_T('odtspip:err_telechargement_fichier'));
+       }
+
+       // dezipper le fichier odt a la mode SPIP
+       include_spip("inc/pclzip");
+       $zip = new PclZip($rep_dezip . $fichier_zip);
+       $ok = $zip->extract(
+                       PCLZIP_OPT_PATH, $rep_dezip,
+                       PCLZIP_OPT_SET_CHMOD, _SPIP_CHMOD,
+                       PCLZIP_OPT_REPLACE_NEWER
+       );
+       if ($zip->error_code < 0) {
+               spip_log('charger_decompresser erreur zip ' . 
+                               $zip->error_code . ' pour fichier ' . $rep_dezip . $fichier_zip);
+               die($zip->errorName(true));      //$zip->error_code
+       }
+
+       // Création de l'array avec les parametres de l'article:
+       // c'est ici que le gros de l'affaire se passe!
+       $odt2spip_generer_sortie = charger_fonction('odt2spip_generer_sortie', 'inc');
+       $Tarticle = $odt2spip_generer_sortie($id_auteur, $rep_dezip);
+
+       // créer l'article
+       include_spip('action/editer_article');
+       $id_article = article_inserer($id_rubrique);
+       
+       // le remplir
+       article_modifier($id_article, $Tarticle);
+
+       // si necessaire recup les id_doc des images associées et les lier à l'article
+       if (isset($Tarticle['Timages']) AND count($Tarticle['Timages']) > 0){
+               foreach($Tarticle['Timages'] as $id_img) {
+                       $champs = array(
+                               'parents' => array("article|$id_article"),
+                               'statut' => 'publie'
+                       );
+                       document_modifier($id_img, $champs);
+               }
+       }
+       
+       // si nécessaire attacher le fichier odt original à l'article
+       // et lui mettre un titre signifiant
+       if (_request('attacher_odt') == '1') {
+               $titre = $Tarticle['titre'];
+               if (!isset($ajouter_documents)) {
+                       $ajouter_documents = charger_fonction('ajouter_documents', 'action');
+               }
+               if ($id_document = $ajouter_documents('new',
+                       array(array('tmp_name' =>  $rep_dezip . $fichier_zip, 'name' => $fichier_zip, 'titrer' => 0, 'distant' => 0, 'type' => 'document')),
+                       'article', $id_article, 'document')
+                       AND $id_doc_odt = intval($id_document[0])
+                       AND $id_doc_odt == $id_document[0]) {
+                               $c = array(
+                                       'titre' => $titre,
+                                       'descriptif' => _T('odtspip:cet_article_version_odt'),
+                                       'statut' => 'publie'
+                                       );
+                               document_modifier($id_doc_odt, $c);
+               }
+       }
+
+       // vider le contenu du rep de dezippage
+       if (!function_exists('effacer_repertoire_temporaire')) {
+               include_spip('inc/getdocument');
+       }
+       effacer_repertoire_temporaire($rep_dezip);
+       
+       // aller sur la page de l'article qui vient d'être créée
+       redirige_par_entete(
+                       parametre_url(
+                                       str_replace("&amp;", "&", urldecode($redirect)),
+                                       'id_article', $id_article, '&'
+                       )
+       );
+}
+
+?>
diff --git a/www/plugins/odt2spip_30/formulaires/odt2spip.html b/www/plugins/odt2spip_30/formulaires/odt2spip.html
new file mode 100644 (file)
index 0000000..cd455b3
--- /dev/null
@@ -0,0 +1,40 @@
+#CACHE{0}
+<div id="boite_odt2spip" class="formulaire_spip formulaire_odt2spip" style="">
+       <style type="text/css">#boite_odt2spip label { display: inline; }</style>
+       <h3 class="titrem"><:odtspip:importer_fichier:></h3>
+       [<img class="cadre-icone" width="24" height="24" alt="" src="(#CHEMIN{odt2spip-24.png})"/>]
+       <form action="#URL_ACTION_AUTEUR{'odt2spip_importe','id_rubrique='#ENV{id_rubrique},#URL_ECRIRE{article}}" method="POST" enctype="multipart/form-data">
+               <ul>
+                       <li>
+                               <label for='fichier_odt'><strong><:odtspip:choix_fichier:></strong></label>
+                               <input class="file" type='file' name='fichier_odt' id='fichier_odt' size="16" />
+                       </li>
+                       <li>
+                               <strong class="explications"><:odtspip:attacher_fichier_odt:></strong>
+                               <label for='attacher_oui'><:odtspip:oui:>
+                               <input type='radio' name='attacher_odt' value='1' id='attacher_oui' checked='checked' /></label>
+                               <label for='attacher_non'><input type='radio' name='attacher_odt' value='0' id='attacher_non' />
+                               <:odtspip:non:></label>
+                       </li>
+                       <li>
+                               <strong><:odtspip:images_mode_document:></strong>
+                               <label for='mode_image'><:odtspip:mode_image:>
+                               <input type='radio' name='mode_image' value='image' id='mode_image' checked='checked'/></label>
+                               <label for='mode_document'><input type='radio' name='mode_image' value='document' id='mode_document'/>
+                               <:odtspip:mode_document:></label>
+                       </li>
+                       <li>
+                               <strong><:odtspip:langue_publication:></strong>
+                               #SET{lang_ec,#EVAL{$GLOBALS['meta']['langue_site'];}}
+                               <select name='lang_publi' id='lang_publi' style='font-size:1em;'>
+                                       <BOUCLE_langues(DATA){liste #EVAL{$GLOBALS['meta']['langues_proposees'];}}>
+                                       <option value="#VALEUR"[ (#VALEUR|=={#GET{lang_ec}}|oui) selected="selected"]>#VALEUR</option>
+                                       </BOUCLE_langues>
+                               </select>       
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" name="Valider" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </form>
+</div>
diff --git a/www/plugins/odt2spip_30/inc/odt2spip.xsl b/www/plugins/odt2spip_30/inc/odt2spip.xsl
new file mode 100644 (file)
index 0000000..8f574b7
--- /dev/null
@@ -0,0 +1,526 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<xsl:stylesheet version="1.0"\r
+       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+    xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"\r
+    xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"\r
+    xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0"\r
+    xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"\r
+    xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"\r
+    xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"\r
+    xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"\r
+    xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"\r
+    xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"\r
+    xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"\r
+    xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"\r
+    xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"\r
+    xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"\r
+    xmlns:anim="urn:oasis:names:tc:opendocument:xmlns:animation:1.0"\r
+\r
+    xmlns:dc="http://purl.org/dc/elements/1.1/"\r
+    xmlns:xlink="http://www.w3.org/1999/xlink"\r
+    xmlns:math="http://www.w3.org/1998/Math/MathML"\r
+    xmlns:xforms="http://www.w3.org/2002/xforms"\r
+\r
+    xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"\r
+    xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"\r
+    xmlns:smil="urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0"\r
+       \r
+    xmlns:ooo="http://openoffice.org/2004/office"\r
+    xmlns:ooow="http://openoffice.org/2004/writer"\r
+    xmlns:oooc="http://openoffice.org/2004/calc"\r
+    xmlns:int="http://catcode.com/odf_to_xhtml/internal"\r
+    \r
+    exclude-result-prefixes="office meta config text table draw presentation\r
+               dr3d chart form script style number anim dc xlink math xforms fo\r
+               svg smil ooo ooow oooc int"\r
+>\r
+\r
+<xsl:output method = "xml"\r
+            encoding="UTF-8"\r
+            indent="yes" />\r
+<xsl:preserve-space elements="*" />\r
+\r
+<!-- Récuperation des parametres venant de PHP: \r
+  IntertitresRiches = oui|non \r
+  en fct de la presence d'un des plugins enluminure_typo ou intertitres_enrichis -->\r
+<xsl:param name="IntertitresRiches"/>\r
+\r
+\r
+<!-- gestion des titres de façon la plus generique possible -->\r
+<!-- si @text:style-name='Heading' est utilise, recuperer 'Heading' dans $STyleTitreGeneral -->\r
+<xsl:variable name="StyleTitreGeneral">\r
+  <xsl:if test="count(//*[node()][@text:style-name='Heading']) > 0">Heading</xsl:if>\r
+</xsl:variable>\r
+\r
+<!-- trouver le niveau de titre qui servira de $NivoTitre1 (= {{{intertitres}}})... a la bourrin !  -->\r
+<xsl:variable name="NivoTitre1">\r
+    <xsl:choose>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='1'] \r
+                              | //*[node()][@text:style-name='Heading_20_1']) > 0">1</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='2'] \r
+                              | //*[node()][@text:style-name='Heading_20_2']) > 0">2</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='3'] \r
+                              | //*[node()][@text:style-name='Heading_20_3']) > 0">3</xsl:when>    \r
+        <xsl:when test="count(//*[node()][@text:outline-level='4'] \r
+                              | //*[node()][@text:style-name='Heading_20_4']) > 0">4</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='5'] \r
+                              | //*[node()][@text:style-name='Heading_20_5']) > 0">5</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='6'] \r
+                              | //*[node()][@text:style-name='Heading_20_6']) > 0">6</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='7'] \r
+                              | //*[node()][@text:style-name='Heading_20_7']) > 0">7</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='8'] \r
+                              | //*[node()][@text:style-name='Heading_20_8']) > 0">8</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='9'] \r
+                              | //*[node()][@text:style-name='Heading_20_9']) > 0">9</xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='10'] \r
+                              | //*[node()][@text:style-name='Heading_20_10']) > 0">10</xsl:when>\r
+    </xsl:choose>\r
+</xsl:variable>\r
+<!-- idem pour le niveau $NivoTitre2 (= {{titres_gras}}) en se basant sur le niveau de $NivoTitre1... Hue! -->\r
+<xsl:variable name="NivoTitre2">\r
+    <xsl:choose>\r
+        <xsl:when test="count(//*[node()][@text:outline-level=$NivoTitre1 + 1] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 1)]) > 0"><xsl:value-of select="$NivoTitre1 + 1"/></xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 2'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 2)]) > 0"><xsl:value-of select="$NivoTitre1 + 2"/></xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 3'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 3)]) > 0"><xsl:value-of select="$NivoTitre1 + 3"/></xsl:when>    \r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 4'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 4)]) > 0"><xsl:value-of select="$NivoTitre1 + 4"/></xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 5'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 5)]) > 0"><xsl:value-of select="$NivoTitre1 + 5"/></xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 6'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 6)]) > 0"><xsl:value-of select="$NivoTitre1 + 6"/></xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 7'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 7)]) > 0"><xsl:value-of select="$NivoTitre1 + 7"/></xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 8'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 8)]) > 0"><xsl:value-of select="$NivoTitre1 + 8"/></xsl:when>\r
+        <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre1 + 9'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1 + 9)]) > 0"><xsl:value-of select="$NivoTitre1 + 9"/></xsl:when>\r
+    </xsl:choose>\r
+</xsl:variable>\r
+\r
+<!-- si il n'existe pas de $StyleTitreGeneral et si il n'y a qu'un seul element de $NivoTitre1 dans le doc \r
+     utiliser $NivoTitre1 comme $StyleTitreGeneral => $DecalerTitres = oui -->\r
+<xsl:variable name="DecalerTitres">\r
+    <xsl:if test="not($StyleTitreGeneral = 'Heading')\r
+                  and count(//*[@text:outline-level='$NivoTitre1'] \r
+                            | //*[@text:style-name=concat('Heading_20_',$NivoTitre1)]) = 1">oui</xsl:if>\r
+</xsl:variable>\r
+        \r
+<!--  si $DecalerTitres == oui => du fait du decalage on va avoir besoin d'un $NivoTitre3 \r
+      idem si enluminure-typo ou intertitres_enrichis  -->\r
+<xsl:variable name="NivoTitre3">\r
+    <xsl:if test="$DecalerTitres = 'oui' or $IntertitresRiches = 'oui'">\r
+        <xsl:choose>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 1'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 1)]) > 0"><xsl:value-of select="$NivoTitre2 + 1"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 2'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 2)]) > 0"><xsl:value-of select="$NivoTitre2 + 2"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 3'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 3)]) > 0"><xsl:value-of select="$NivoTitre2 + 3"/></xsl:when>    \r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 4'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 4)]) > 0"><xsl:value-of select="$NivoTitre2 + 4"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 5'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 5)]) > 0"><xsl:value-of select="$NivoTitre2 + 5"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 6'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 6)]) > 0"><xsl:value-of select="$NivoTitre2 + 6"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 7'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 7)]) > 0"><xsl:value-of select="$NivoTitre2 + 7"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre2 + 8'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre2 + 8)]) > 0"><xsl:value-of select="$NivoTitre2 + 8"/></xsl:when>\r
+        </xsl:choose>\r
+    </xsl:if>\r
+</xsl:variable>\r
+\r
+<!-- super-reloud! si enluminure-typo ou intertitres_enrichis on a besoin de titre4 et titre5\r
+     si en plus on a $DecalerTitres == oui il faut en plus titre6 \r
+     ca sent le besoin de pouvoir faire des boucles et/ou des fonctions en xsl...  -->\r
+<xsl:variable name="NivoTitre4">\r
+    <xsl:if test="$IntertitresRiches = 'oui'">\r
+        <xsl:choose>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre3 + 1'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre3 + 1)]) > 0"><xsl:value-of select="$NivoTitre3 + 1"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre3 + 2'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre3 + 2)]) > 0"><xsl:value-of select="$NivoTitre3 + 2"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre3 + 3'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre3 + 3)]) > 0"><xsl:value-of select="$NivoTitre3 + 3"/></xsl:when>    \r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre3 + 4'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre3 + 4)]) > 0"><xsl:value-of select="$NivoTitre3 + 4"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre3 + 5'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre3 + 5)]) > 0"><xsl:value-of select="$NivoTitre3 + 5"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre3 + 6'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre3 + 6)]) > 0"><xsl:value-of select="$NivoTitre3 + 6"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre3 + 7'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre3 + 7)]) > 0"><xsl:value-of select="$NivoTitre3 + 7"/></xsl:when>\r
+        </xsl:choose>\r
+    </xsl:if>\r
+</xsl:variable>\r
+<xsl:variable name="NivoTitre5">\r
+    <xsl:if test="$IntertitresRiches = 'oui'">\r
+        <xsl:choose>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre4 + 1'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre4 + 1)]) > 0"><xsl:value-of select="$NivoTitre4 + 1"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre4 + 2'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre4 + 2)]) > 0"><xsl:value-of select="$NivoTitre4 + 2"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre4 + 3'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre4 + 3)]) > 0"><xsl:value-of select="$NivoTitre4 + 3"/></xsl:when>    \r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre4 + 4'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre4 + 4)]) > 0"><xsl:value-of select="$NivoTitre4 + 4"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre4 + 5'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre4 + 5)]) > 0"><xsl:value-of select="$NivoTitre4 + 5"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre4 + 6'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre4 + 6)]) > 0"><xsl:value-of select="$NivoTitre4 + 6"/></xsl:when>\r
+        </xsl:choose>\r
+    </xsl:if>\r
+</xsl:variable>\r
+<xsl:variable name="NivoTitre6">\r
+    <xsl:if test="$DecalerTitres = 'oui' and $IntertitresRiches = 'oui'">\r
+        <xsl:choose>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre5 + 1'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre5 + 1)]) > 0"><xsl:value-of select="$NivoTitre5 + 1"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre5 + 2'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre5 + 2)]) > 0"><xsl:value-of select="$NivoTitre5 + 2"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre5 + 3'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre5 + 3)]) > 0"><xsl:value-of select="$NivoTitre5 + 3"/></xsl:when>    \r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre5 + 4'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre5 + 4)]) > 0"><xsl:value-of select="$NivoTitre5 + 4"/></xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level='$NivoTitre5 + 5'] \r
+                              | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre5 + 5)]) > 0"><xsl:value-of select="$NivoTitre5 + 5"/></xsl:when>\r
+        </xsl:choose>\r
+    </xsl:if>\r
+</xsl:variable>\r
+\r
+\r
+<!-- trouver un titre general au document: \r
+     si $StyleTitreGeneral existe, concatener tous les elements avec ce style\r
+     sinon utiliser le premier element ayant le niveau de style $NivoTitre1\r
+     sinon utiliser le premier element text:h ou text:p et basta! -->\r
+<xsl:variable name="ContenuTitreDoc">\r
+        <xsl:choose>\r
+            <xsl:when test="$StyleTitreGeneral='Heading'">\r
+                <xsl:for-each select="//*[node()][@text:style-name='Heading']"><xsl:value-of select="."/> </xsl:for-each>\r
+            </xsl:when>\r
+            <xsl:when test="count(//*[node()][@text:outline-level=$NivoTitre1]\r
+                                  | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1)]\r
+                                  ) > 0">\r
+                <xsl:value-of select="//*[node()][@text:outline-level=$NivoTitre1][1]\r
+                                      | //*[node()][@text:style-name=concat('Heading_20_',$NivoTitre1)][1]"/>\r
+            </xsl:when>\r
+           <xsl:otherwise>\r
+                <xsl:value-of select="//text:h[node()][1] | //text:p[node()][1]"/>\r
+            </xsl:otherwise>\r
+        </xsl:choose>\r
+</xsl:variable>\r
+\r
+\r
+<!-- traitement de l'ensemble du doc -->\r
+<xsl:template match="/office:document-content">\r
+<!--  test niveaux de titres\r
+t1= <xsl:value-of select="$NivoTitre1" />\r
+t2= <xsl:value-of select="$NivoTitre2" />\r
+t3= <xsl:value-of select="$NivoTitre3" />\r
+tG= <xsl:value-of select="$StyleTitreGeneral" />\r
+-->\r
+<!-- test recuperation du parametre passe par PHP \r
+intertitres_riches= <xsl:value-of select="$IntertitresRiches" />\r
+-->\r
+<!-- le XML de sortie -->\r
+<articles>\r
+<article>\r
+       <titre><xsl:value-of select="$ContenuTitreDoc"/></titre>\r
+       <texte>\r
+               <xsl:apply-templates select="office:body/office:text"/>\r
+       </texte>\r
+</article>\r
+</articles>\r
+</xsl:template>\r
+\r
+\r
+<!-- virer les eventuels table des matieres et index -->\r
+<xsl:template match="//text:table-of-content | //text:alphabetical-index"/>\r
+\r
+\r
+<!-- les paragraphes y compris les vides utilises pour saut de ligne -->\r
+<xsl:template match="table:table-cell//text:p">\r
+       <xsl:apply-templates/>\r
+    <xsl:if test="count(node())=0">\r
+               <xsl:text>&#xA;&#xA;</xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+<xsl:template match="text:p">\r
+       <xsl:apply-templates/>\r
+       <xsl:text >&#xA;&#xA;</xsl:text>\r
+    <xsl:if test="count(node())=0">\r
+               <xsl:text>&#xA;&#xA;</xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+\r
+\r
+\r
+<!-- bidouiller pour ne pas afficher le titre du document dans le texte (part 1) -->\r
+<xsl:template match="//*[@text:style-name='Heading']"/>\r
+\r
+<!-- les titres de façon dynamique en fonction des niveaux presents dans le fichier  -->\r
+<xsl:template match="//*[node()][@text:outline-level] \r
+                     | //*[node()][starts-with(@text:style-name,'Heading_20_')]">\r
+    <xsl:choose>\r
+<!-- suite de la bidouille pour ne pas afficher le titre du document dans le texte -->\r
+        <xsl:when test="not($StyleTitreGeneral='Heading') and text()=$ContenuTitreDoc"/>\r
+        <xsl:otherwise>\r
+            <xsl:call-template name="titres"/>\r
+        </xsl:otherwise>\r
+    </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template name="titres">\r
+<!-- si $DecalerTitres == oui, décaler les niveaux puisqu'il n'existe pas de $StyleTitreGeneral et qu'il n'y a qu'un $NivoTitre1 -->\r
+    <xsl:variable name="NivoTitre1_ec">\r
+      <xsl:choose>\r
+          <xsl:when test="not($DecalerTitres='oui')">\r
+            <xsl:value-of select="$NivoTitre1"/>\r
+          </xsl:when>\r
+          <xsl:otherwise>\r
+            <xsl:value-of select="$NivoTitre2"/>\r
+          </xsl:otherwise>\r
+      </xsl:choose>\r
+    </xsl:variable>\r
+    <xsl:variable name="NivoTitre2_ec">\r
+      <xsl:choose>\r
+          <xsl:when test="not($DecalerTitres='oui')">\r
+            <xsl:value-of select="$NivoTitre2"/>\r
+          </xsl:when>\r
+          <xsl:otherwise>\r
+            <xsl:value-of select="$NivoTitre3"/>\r
+          </xsl:otherwise>\r
+      </xsl:choose>\r
+    </xsl:variable>\r
+<!-- appliquer les formatages des titres -->\r
+<xsl:text >&#xA;</xsl:text>\r
+               <xsl:choose>\r
+<!-- formatages avec enluminure_typo ou intertitres_enrichis  -->\r
+        <xsl:when test="$IntertitresRiches = 'oui'">\r
+          <!-- definir les niveaux de titre 3, 4 et 5 en fonction de $DecalerTitres  -->\r
+            <xsl:variable name="NivoTitre3_ec">\r
+              <xsl:choose>\r
+                  <xsl:when test="not($DecalerTitres='oui')">\r
+                    <xsl:value-of select="$NivoTitre3"/>\r
+                  </xsl:when>\r
+                  <xsl:otherwise>\r
+                    <xsl:value-of select="$NivoTitre4"/>\r
+                  </xsl:otherwise>\r
+              </xsl:choose>\r
+            </xsl:variable>\r
+            <xsl:variable name="NivoTitre4_ec">\r
+              <xsl:choose>\r
+                  <xsl:when test="not($DecalerTitres='oui')">\r
+                    <xsl:value-of select="$NivoTitre4"/>\r
+                  </xsl:when>\r
+                  <xsl:otherwise>\r
+                    <xsl:value-of select="$NivoTitre5"/>\r
+                  </xsl:otherwise>\r
+              </xsl:choose>\r
+            </xsl:variable>\r
+            <xsl:variable name="NivoTitre5_ec">\r
+              <xsl:choose>\r
+                  <xsl:when test="not($DecalerTitres='oui')">\r
+                    <xsl:value-of select="$NivoTitre5"/>\r
+                  </xsl:when>\r
+                  <xsl:otherwise>\r
+                    <xsl:value-of select="$NivoTitre6"/>\r
+                  </xsl:otherwise>\r
+              </xsl:choose>\r
+            </xsl:variable>\r
+          <!-- appliquer le formatage proprement dit -->\r
+            <xsl:choose>\r
+                               <xsl:when test="@text:outline-level=$NivoTitre1_ec or @text:style-name=concat('Heading_20_',$NivoTitre1_ec)">\r
+{{{<xsl:apply-templates/>}}}\r
+</xsl:when>\r
+                               <xsl:otherwise>\r
+                    <!-- recuperer le niveau de titre en cours a la bourrin \r
+                    (a coup sur y'a moyen de faire mieux mais on va pas se decarcasser pour ces p*** de plugins qui forkent definitivement le code spip !  -->\r
+                    <xsl:variable name="NivoTitre_ec">\r
+                        <xsl:choose>\r
+                            <xsl:when test="@text:outline-level=$NivoTitre2_ec or @text:style-name=concat('Heading_20_',$NivoTitre2_ec)">2</xsl:when>\r
+                            <xsl:when test="@text:outline-level=$NivoTitre3_ec or @text:style-name=concat('Heading_20_',$NivoTitre3_ec)">3</xsl:when>\r
+                            <xsl:when test="@text:outline-level=$NivoTitre4_ec or @text:style-name=concat('Heading_20_',$NivoTitre4_ec)">4</xsl:when>\r
+                            <xsl:when test="@text:outline-level=$NivoTitre5_ec or @text:style-name=concat('Heading_20_',$NivoTitre5_ec)">5</xsl:when>\r
+                        </xsl:choose>\r
+                    </xsl:variable>\r
+{<xsl:value-of select="$NivoTitre_ec"/>{<xsl:apply-templates/>}<xsl:value-of select="$NivoTitre_ec"/>}\r
+</xsl:otherwise>\r
+                       </xsl:choose>\r
+        </xsl:when>\r
+<!-- formatages sans enluminure_typo ou intertitres_enrichis  -->\r
+        <xsl:otherwise>\r
+            <xsl:choose>\r
+                               <xsl:when test="@text:outline-level=$NivoTitre1_ec or @text:style-name=concat('Heading_20_',$NivoTitre1_ec)">\r
+{{{<xsl:apply-templates/>}}}\r
+</xsl:when>\r
+                               <xsl:when test="@text:outline-level=$NivoTitre2_ec or @text:style-name=concat('Heading_20_',$NivoTitre2_ec)">\r
+{{<xsl:apply-templates/>}}\r
+</xsl:when>\r
+                               <xsl:otherwise>\r
+{<xsl:apply-templates/>}\r
+</xsl:otherwise>\r
+                       </xsl:choose>\r
+        </xsl:otherwise>\r
+    </xsl:choose>\r
+<xsl:text >&#xA;</xsl:text>\r
+</xsl:template>\r
+\r
+\r
+<!-- traitement des listes -->\r
+<xsl:template match="text:list">\r
+  <xsl:variable name="level" select="count(ancestor::text:list)+1"/>\r
+\r
+       <!-- le type de liste est le @text:style-name de l'element <text:list> le plus exterieur des listes imbriquees -->\r
+       <xsl:variable name="listClass">\r
+               <xsl:choose>\r
+                       <xsl:when test="$level=1">\r
+                               <xsl:value-of select="@text:style-name"/>\r
+                       </xsl:when>\r
+                       <xsl:otherwise>\r
+                               <xsl:value-of select="ancestor::text:list[last()]/@text:style-name"/>\r
+                       </xsl:otherwise>\r
+               </xsl:choose>\r
+       </xsl:variable>\r
+\r
+       <!-- choisir le bon type de liste en fonction du <text:list-level-style-XXX> du  <text:list-style> dans les styles pre-definis\r
+       <xsl:variable name="node" select="key('listTypes', $listClass)/*[@text:level='$level']"/>  -->\r
+  <xsl:variable name="node" select="/office:document-content/office:automatic-styles/text:list-style[@style:name=$listClass]/*[1]"/>  \r
+       \r
+  <xsl:variable name="s">\r
+    <xsl:choose>\r
+       <xsl:when test="local-name($node)='list-level-style-number'">#</xsl:when>\r
+               <xsl:otherwise>*</xsl:otherwise>\r
+    </xsl:choose>\r
+  </xsl:variable>\r
+<!-- -->\r
+  <xsl:call-template name="process-list">\r
+    <xsl:with-param name="s" select="$s"/>\r
+       </xsl:call-template>\r
+  \r
+  <xsl:text >&#xA;</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template name="process-list"> \r
+  <xsl:param name="s"/>\r
+  <xsl:for-each select="descendant::text:list-item/text:p[node()]">\r
+-<xsl:for-each select="ancestor::*"><!-- gestion des listes imbriquées -->\r
+        <xsl:if test="name()='text:list-item'"><xsl:value-of select="$s"/></xsl:if>\r
+</xsl:for-each> \r
+    <xsl:apply-templates />\r
+  </xsl:for-each>\r
+</xsl:template>\r
+\r
+\r
+<!-- traitement des tableaux -->\r
+<xsl:template match="table:table">\r
+<xsl:text >&#xA;</xsl:text>\r
+               <xsl:apply-templates select="table:table-row | */table:table-row"/>\r
+<xsl:text >&#xA;</xsl:text>        \r
+</xsl:template>\r
+\r
+<xsl:template match="table:table-row | */table:table-row">\r
+<xsl:text >&#xA;</xsl:text>|<xsl:choose>\r
+<!-- si c'est la premiere ligne *et* qu'il n'y a as de cellules fusionnees verticalement utiliser {{ }} pour faire un thead -->\r
+   <xsl:when test="position()=1 and count(table:table-cell[@table:number-rows-spanned])=0">\r
+       <xsl:apply-templates select="table:table-cell | table:covered-table-cell" mode="thead"/>\r
+   </xsl:when>\r
+   <xsl:otherwise>\r
+        <xsl:apply-templates select="table:table-cell | table:covered-table-cell" mode="tbody"/>\r
+   </xsl:otherwise>\r
+</xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template match="table:table-cell" mode="thead">{{<xsl:apply-templates select="*[node()]"/>}}|</xsl:template>\r
+<xsl:template match="table:table-cell" mode="tbody"><xsl:apply-templates select="*[node()]"/>|</xsl:template>\r
+\r
+<!-- ca c'est la mauvaise bidouille pour avoir le meme traitement pour les cellules de fusion alors qu'elles ont un mode different -->\r
+<xsl:template match="table:covered-table-cell" mode="thead"><xsl:call-template name="cells_fusionnees"/></xsl:template>\r
+<xsl:template match="table:covered-table-cell" mode="tbody"><xsl:call-template name="cells_fusionnees"/></xsl:template>\r
+\r
+<!-- traitement des cellules masquees du fait de fusions par colonnes/lignes \r
+     bidouille: si dans les cellules precedentes de la meme ligne il y a un table:number-columns-spanned="XX"\r
+     alors c'est une fusion de cellules d'une meme ligne (code <|) sinon fusion de cellules d'une meme colonne (code ^|) -->\r
+<xsl:template name="cells_fusionnees">\r
+  <xsl:variable name="fusion">\r
+               <xsl:for-each select="preceding-sibling::*">\r
+                   <xsl:if test="@table:number-columns-spanned &gt; 1">&lt;</xsl:if>\r
+    </xsl:for-each>\r
+       </xsl:variable>\r
+       <xsl:variable name="caractere_fusion">\r
+    <xsl:choose>\r
+        <xsl:when test="$fusion = ''">^</xsl:when>\r
+        <xsl:otherwise>&lt;</xsl:otherwise>\r
+    </xsl:choose>\r
+  </xsl:variable>\r
+<xsl:value-of select="$caractere_fusion"/>|</xsl:template>\r
+\r
+\r
+<!-- les liens -->\r
+<xsl:template match="text:a">[<xsl:apply-templates />-><xsl:value-of select="@xlink:href" />]</xsl:template>\r
+\r
+<!-- les ancres -->\r
+<xsl:template match="text:bookmark-start|text:bookmark">[<xsl:value-of select="@text:name" />&lt;-]\r
+</xsl:template>\r
+\r
+<!-- notes de bas de page      -->\r
+<xsl:template match="text:note-citation"/>\r
+<xsl:template match="text:note-body">[[<xsl:apply-templates />]]</xsl:template>\r
+       \r
+<!-- les sauts de ligne -->\r
+<xsl:template match="text:line-break">\r
+_ <xsl:apply-templates />\r
+</xsl:template>\r
+\r
+<!-- gras et italiques -->\r
+<xsl:template match="text:span">\r
+       <xsl:variable name="StyleType" select="@text:style-name"/>\r
+       <xsl:variable name="weight" select="/office:document-content/office:automatic-styles/style:style[@style:name=$StyleType]/style:text-properties/@fo:font-weight"/>\r
+       <xsl:variable name="style" select="/office:document-content/office:automatic-styles/style:style[@style:name=$StyleType]/style:text-properties/@fo:font-style"/>\r
+       <xsl:choose>\r
+    <xsl:when test="$weight='bold'">{{<xsl:apply-templates />}}</xsl:when>\r
+       <xsl:when test="$style='italic'">{<xsl:apply-templates />}</xsl:when>\r
+       <xsl:otherwise>\r
+                       <xsl:apply-templates />\r
+               </xsl:otherwise>\r
+       </xsl:choose>   \r
+</xsl:template>\r
+\r
+\r
+<!-- nettement plus bricolage : les images... \r
+     on met le nom de fichier de l'image qu'il faudra echanger en php par son id document spip une fois qu'il sera reference dans la table documents -->       \r
+<xsl:template match="draw:image">\r
+<!-- on filtre les elements draw:image qui ont un frere draw:object cad qui ne sont pas des images -->   \r
+   <xsl:if test="count(parent::draw:frame/draw:object)=0">\r
+      <xsl:call-template name="img2texte" />\r
+   </xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:template name="img2texte">&#60;img<xsl:value-of select="substring(@xlink:href,10)"/>;;;<xsl:value-of select="substring-before(parent::draw:frame/@svg:width,'cm')" />;;;<xsl:value-of select="substring-before(parent::draw:frame/@svg:height,'cm')" />;;;|<xsl:choose>\r
+<!-- sale bidouille pour approximer la position de l'image (|left |center |right) -->\r
+<xsl:when test="substring-before(parent::draw:frame/@svg:x, 'cm') &lt;= 2">left</xsl:when>\r
+<xsl:when test="substring-before(parent::draw:frame/@svg:x, 'cm') &gt;= 5">right</xsl:when>\r
+<xsl:otherwise>center</xsl:otherwise>\r
+</xsl:choose>&#62;</xsl:template>\r
+\r
+<!-- pour continuer dans les bidouillages: les objets integres \r
+     i.e. les formules de math sous forme d'un fichier MathML externe stocke dans un ss-rep: /Object X/content.xml \r
+     ici on cree une balise <math>Object X</math> qui sera ensuite post-traitee pour recuperer la formule   -->\r
+<xsl:template match="draw:object[@xlink:href]">\r
+&#60;math&#62;<xsl:value-of select="substring(@xlink:href,3)"/>&#60;/math&#62;\r
+</xsl:template>\r
+\r
+<!--\r
+       This template is too dangerous to leave active...\r
+<xsl:template match="text()">\r
+       <xsl:if test="normalize-space(.) !=''">\r
+               <xsl:value-of select="normalize-space(.)"/>\r
+       </xsl:if>\r
+</xsl:template>\r
+-->\r
+\r
+</xsl:stylesheet>\r
diff --git a/www/plugins/odt2spip_30/inc/odt2spip_generer_sortie.php b/www/plugins/odt2spip_30/inc/odt2spip_generer_sortie.php
new file mode 100644 (file)
index 0000000..82f1c0d
--- /dev/null
@@ -0,0 +1,184 @@
+<?php\r
+/**\r
+ * Créer un article à partir d'un fichier au format odt\r
+ *\r
+ * @author cy_altern\r
+ * @license GNU/LGPL\r
+ *\r
+ * @package plugins\r
+ * @subpackage odt2spip\r
+ * @category import\r
+ *\r
+ *\r
+ */\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * Création de l'Array contenant les paramètres du futur article\r
+ *\r
+ * Le fichier content.xml a été extrait de l'archive .odt, et placé dans le dossier\r
+ * temporaire propre à l'utilisateur courant. Un premier traitement est effectué\r
+ * par cette fonction pour qu'il soit finalement transformé en texte utilisant les\r
+ * balises SPIP. On tient compte de la présence des plugins enluminure_typo et\r
+ * intertitre_enrichis. Les images sont extraites du document .odt et sont prêtes\r
+ * à être insérées dans le futur article SPIP.\r
+ * \r
+ * @param int $id_auteur Utilisateur courant\r
+ * @param string $rep_dezip Répertoire où est dezippé le fichier odt\r
+ * @return Array\r
+ */\r
+function inc_odt2spip_generer_sortie($id_auteur, $rep_dezip){\r
+       // variables en dur pour xml en entree et xslt utilisee\r
+       // $xml_entre = $rep_dezip . 'content.xml';  // chemin du fichier xml a lire    \r
+       $xml_entre = _DIR_TMP . 'odt2spip/' . $id_auteur . '/content.xml';  // chemin du fichier xml a lire\r
+       $xslt_texte = _DIR_PLUGIN_ODT2SPIP . 'inc/odt2spip.xsl'; // chemin de la xslt a utiliser pour le texte\r
+\r
+       // determiner si le plugin enluminure_typo ou intertitres_enrichis est present & actif\r
+       include_spip('inc/plugin');\r
+       $Tplugins = liste_plugin_actifs();\r
+       $intertitres_riches = ((array_key_exists('TYPOENLUMINEE', $Tplugins) OR array_key_exists('INTERTITRESTDM', $Tplugins)) ? 'oui' : 'non'); \r
+\r
+       // si il n'existe pas de titre:h dans le doc, on parametre ici la longueur max du paragraphe utilise pour remplacer\r
+       $nb_caracteres_titre = 50;\r
+\r
+       // faut il mettre les images en mode document?\r
+    $type = (_request('mode_image') AND _request('mode_image') == 'document') ? 'document' : 'image';\r
+    $ModeImages = ($type == 'document' ? 'doc' : 'img');\r
+    \r
+       // récupérer la langue de publication + verifier la valeur envoyée\r
+    $Tlangues = explode(',', $GLOBALS['meta']['langues_proposees']);\r
+    $LanguePublication = (in_array(_request('lang_publi'), $Tlangues) ? _request('lang_publi') : $GLOBALS['meta']['langue_site']);\r
+    \r
+       // date pour les champs date et date_modif\r
+       $date_jour = date("Y-m-d H:i:s");\r
+\r
+       // appliquer la transformation XSLT sur le fichier content.xml\r
+       // on est php5: utiliser les fonctions de la classe XSLTProcessor\r
+       // verifier que l'extension xslt est active\r
+       if (!class_exists('XSLTProcessor')) {\r
+               die(_T('odtspip:err_extension_xslt'));\r
+       }\r
+       $proc = new XSLTProcessor();\r
+\r
+       // passage des parametres a la xslt\r
+       $proc->setParameter(null, 'IntertitresRiches', $intertitres_riches);  \r
+\r
+       $xml = new DOMDocument();\r
+       $xml->load($xml_entre);\r
+       $xsl = new DOMDocument();\r
+       $xsl->load($xslt_texte);\r
+       $proc->importStylesheet($xsl); // attachement des regles xsl\r
+\r
+       // lancer le parseur\r
+       if (!$xml_sortie = $proc->transformToXml($xml)) {\r
+               die(_T('odtspip:err_transformation_xslt'));\r
+       }\r
+\r
+       // construire l'array des parametres de l'article\r
+       preg_match('/<titre>(.*?)<\/titre>/',$xml_sortie, $t);\r
+       $Tarticle['titre'] = $t[1];\r
+       preg_match('/<texte>(.*?)<\/texte>/s',$xml_sortie, $a);\r
+       $Tarticle['texte'] = $a[1];\r
+       $Tarticle['date_redac'] = '0000-00-00 00:00:00';\r
+       $Tarticle['date'] = $Tarticle['date_modif'] = $date_jour;\r
+       $Tarticle['lang'] = $LanguePublication;\r
+       $Tarticle['statut'] = 'prop';\r
+       $Tarticle['accepter_forum'] = 'non';\r
+       \r
+       // traitements complementaires du texte de l'article\r
+       // remplacer les &gt; et &lt;\r
+       $a_remplacer = array('&#60;', '&#62;', '&lt;', '&gt;', '"');\r
+       $remplace = array('<', '>', '<', '>', "'");\r
+       \r
+    // si plugin TYPOENLUMINE est en version 3 (ou plus) utiliser la syntaxe {{{**titre 2}}} a la place de {2{titre 2}2}\r
+    // (cf http://www.spip-contrib.net/odt2spip-creation-d-articles-a-partir-de-fichiers#forum435614)\r
+    if (array_key_exists('TYPOENLUMINEE', $Tplugins) AND intval(substr($Tplugins['TYPOENLUMINEE']['version'], 0, 1)) >= 3) {\r
+               array_push($a_remplacer, '{2{', '}2}', '{3{', '}3}', '{4{', '}4}', '{5{', '}5}');\r
+               array_push($remplace, '{{{**', '}}}', '{{{***', '}}}', '{{{****', '}}}', '{{{*****', '}}}');\r
+       }\r
+       \r
+       $Tarticle['texte'] = str_replace($a_remplacer, $remplace, $Tarticle['texte']);\r
+\r
+       // gerer la conversion des <math>Object X</math> => on delegue a /inc/odt2spip_traiter_mathml.php\r
+       if (preg_match_all('/<math>(.*?)<\/math>/', $Tarticle['texte'], $match, PREG_PATTERN_ORDER) > 0) {\r
+               include_spip('inc/odt2spip_traiter_mathml');\r
+               foreach ($match[1] as $balise) {\r
+                       $fic_content = $rep_dezip . $balise . '/content.xml';\r
+                       // si le fichier /Object X/content.xml ne contient pas du mathML, virer la balise <math>\r
+                       if (substr_count(file_get_contents($fic_content), '<!DOCTYPE math:math') < 1) {\r
+                               $Tarticle['texte'] = str_replace('<math>' . $balise . '</math>', '', $Tarticle['texte']);\r
+                               continue;\r
+                       }\r
+                       // sinon faire la transfo xsl du contenu du fichier pour obtenir le LateX qu'on place dans la balise\r
+                       $Tarticle['texte'] = str_replace($balise, odt2spip_traiter_mathml($fic_content), $Tarticle['texte']);\r
+               }\r
+       }\r
+\r
+       // virer les sauts de ligne multiples\r
+       $Tarticle['texte'] = preg_replace('/([\r\n]{2})[ \r\n]*/m', "$1", $Tarticle['texte']);\r
+\r
+    // si malgré toutes les magouille xslt la balise  <titre> est vide, mettre le nom du fichier odt\r
+    if ($Tarticle['titre'] == '')\r
+               $Tarticle['titre'] = str_replace(array('_','-','.odt'), array(' ',' ',''), $fichier_zip);\r
+               \r
+       // traiter les images: dans tous les cas il faut les integrer dans la table documents \r
+       $rep_pictures = $rep_dezip . "Pictures/";\r
+\r
+       // parametres de conversion de taille des images : cm -> px (en 96 dpi puisque c'est ce que semble utiliser Writer)\r
+       $conversion_image = 96 / 2.54;\r
+\r
+       preg_match_all('/<img([;a-zA-Z0-9\.]*)/', $Tarticle['texte'], $match, PREG_PATTERN_ORDER);\r
+       if (@count($match) > 0) {\r
+               if (!isset($odt2spip_retailler_img)) {\r
+                       $odt2spip_retailler_img = charger_fonction('odt2spip_retailler_img', 'inc');\r
+               }\r
+               if (!isset($ajouter_documents)) {\r
+                       $ajouter_documents = charger_fonction('ajouter_documents', 'action');\r
+               }\r
+               $Timages = array();\r
+               foreach($match[1] as $ch) {\r
+                       $Tdims = explode(';;;', $ch);\r
+                       $img = $Tdims[0];\r
+                       // si l'extension du fichier image n'est pas jpg/gif/png virer la balise\r
+            if (!in_array(strtolower(substr($img, -3)), array('jpg','gif','png')))\r
+                               $Tarticle['texte'] = str_replace($ch, '', $Tarticle['texte']);\r
+            elseif (file_exists($rep_pictures . $img)) {\r
+                               // retailler l'image en fct des parametres ;;;largeur;;;hauteur;;;\r
+                               $largeur = round($Tdims[1] * $conversion_image);\r
+                               $hauteur = round($Tdims[2] * $conversion_image);\r
+                               $odt2spip_retailler_img($rep_pictures . $img, $largeur, $hauteur);\r
+                               if ($id_document = $ajouter_documents('new',\r
+                                       array(array('tmp_name' =>  $rep_pictures . $img, 'name' => $img, 'titrer' => 0, 'distant' => 0, 'type' => $type)),\r
+                                       '', 0, $type)\r
+                                       AND $id_img = intval($id_document[0])\r
+                                       AND $id_img == $id_document[0]) {\r
+                                       $Timages[] = $id_img;\r
+\r
+                                       // remplacer les noms de fichier par leur id_document dans les <imgLeNomDuFichier.jpg> du texte\r
+                                       $Tarticle['texte'] = str_replace($ch, $id_img, $Tarticle['texte']);\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               // si les images doivent êtres intégrées en mode document, remplacer la balise <imgXY> par <docXY>\r
+               if ($type == 'document')\r
+                       preg_replace('/<img/', '<doc', $Tarticle['texte']);\r
+\r
+               // intégrer l'array des images dans les parametres de l'article\r
+               // ce qui permettra de faire la liaison lorsqu'on aura l'id_article\r
+               $Tarticle['Timages'] = $Timages;\r
+       }\r
+\r
+       // encodage des caracteres pour gerer aussi les SPIP 3 en ISO-8859-1\r
+       // cf http://contrib.spip.net/odt2spip-creation-d-articles-a-partir-de-fichiers#forum466929\r
+       if ($GLOBALS['meta']['charset'] != 'utf-8'){\r
+               include_spip('inc/charsets');\r
+               $Tarticle['texte'] = importer_charset($Tarticle['texte'], 'utf-8');\r
+               $Tarticle['titre'] = importer_charset($Tarticle['titre'], 'utf-8');\r
+       }\r
+       \r
+       return $Tarticle;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/odt2spip_30/inc/odt2spip_retailler_img.php b/www/plugins/odt2spip_30/inc/odt2spip_retailler_img.php
new file mode 100644 (file)
index 0000000..98ebee4
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Créer un article à partir d'un fichier au format odt
+ *
+ * @author cy_altern
+ * @license GNU/LGPL
+ *
+ * @package plugins
+ * @subpackage odt2spip
+ * @category import
+ *
+ *
+ */
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * retailler une image : (ne gère que les images GIF, JPG et PNG)
+ *
+ * @internal Gestion de la transparence des PNG : code de matt1walsh@gmail.com sur {@link http://fr2.php.net/manual/fr/function.imagecopyresampled.php}
+ * @param string $img_ini Le fichier à retailler
+ * @param int $l Largeur max de l'image finale
+ * @param int $h Hauteur max
+ * @return string Le message d'erreur en cas de problème
+ */
+function inc_odt2spip_retailler_img($img_ini, $l = 0, $h = 400){
+       if (!file_exists($img_ini)) {
+               return 'Le fichier ' . $img_ini . ' n\'existe pas';
+       }
+       // determiner le type de fonction de creation d'image a utiliser 
+       $param_img = getimagesize($img_ini);
+       $type_img = $param_img[2];
+       switch ($type_img) {
+               case 1 :
+                       $fct_creation_ext = 'imagecreatefromgif';
+                       $fct_ecrire = 'imagegif';
+               break;
+               case 2 :
+                       $fct_creation_ext = 'imagecreatefromjpeg';
+                       $fct_ecrire = 'imagejpeg';
+               break;
+               case 3 :
+                       $fct_creation_ext = 'imagecreatefrompng';
+                       $fct_ecrire = 'imagepng';
+               break;
+               default :
+                       return;
+               break;
+       } 
+       // calculer le ratio a appliquer aux dimensions initiales
+       $l_ini = $param_img[0];
+       $h_ini = $param_img[1];
+       $ratio = ($l != 0 ? (abs($l_ini - $l) >= abs($h_ini - $h) ? $l / $l_ini : $h / $h_ini) : $h / $h_ini);
+       $img_nv = imagecreatetruecolor($l_ini * $ratio, $h_ini * $ratio); 
+       $img_acopier = $fct_creation_ext($img_ini);
+
+       // gerer la transparence pour les images PNG (le mec qui a trouve ce code est genial! :-)
+       if ($type_img == 3) {
+               imagecolortransparent($img_nv, imagecolorallocate($img_nv, 0, 0, 0));
+               imagealphablending($img_nv, false);
+               imagesavealpha($img_nv, true);
+       }
+       imagecopyresampled($img_nv, $img_acopier, 0, 0, 0, 0, $l_ini * $ratio, $h_ini * $ratio, $l_ini, $h_ini);                                         
+       // sauvegarder l'image et eventuellement detruire le fichier image initial
+       $fct_ecrire($img_nv, $img_ini);
+       imagedestroy($img_nv);
+       imagedestroy($img_acopier);
+}
+
+?>
diff --git a/www/plugins/odt2spip_30/inc/odt2spip_traiter_mathml.php b/www/plugins/odt2spip_30/inc/odt2spip_traiter_mathml.php
new file mode 100644 (file)
index 0000000..9fd6797
--- /dev/null
@@ -0,0 +1,54 @@
+<?php\r
+/**\r
+ * Créer un article à partir d'un fichier au format odt\r
+ *\r
+ * @author cy_altern\r
+ * @license GNU/LGPL\r
+ *\r
+ * @package plugins\r
+ * @subpackage odt2spip\r
+ * @category import\r
+ *\r
+ *\r
+ */\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * appliquer la transformation XSLT spécifique des <maths> sur le fichier content.xml extrait du .ODT\r
+ *\r
+ * @internal XSLT pour la transformation MathML 2.0 to LaTeX :\r
+ *             Vasil Yaroshevich, <yarosh@raleigh.ru>\r
+ *             http://www.raleigh.ru/MathML/mmltex/index.php?lang=en\r
+ * @param string $chemin_fichier Le chemin du fichier contenant le MathML\r
+ * @return string Le LateX de sortie\r
+ * \r
+ */\r
+function odt2spip_traiter_mathml($chemin_fichier) {\r
+       // recuperer le contenu du fichier\r
+       if (!$mathml = file_get_contents($chemin_fichier))\r
+               return(_T('odtspip:err_transformation_xslt_mathml'));\r
+\r
+       // virer le DOCTYPE qui plante le parseur vu que la dtd n'est pas disponible\r
+       $mathml = preg_replace('/<!DOCTYPE.*?>/i', '', $mathml);\r
+\r
+       // appliquer la transformation XSLT sur le fichier content.xml\r
+       // chemin du fichier xslt a utiliser pour les maths\r
+       $xslt_texte = _DIR_PLUGIN_ODT2SPIP.'inc/xsltml/mmltex.xsl';\r
+       \r
+       // on est php5: utiliser les fonctions de la classe XSLTProcessor\r
+       $proc = new XSLTProcessor();\r
+\r
+       $xml = new DOMDocument();\r
+       $xml->loadXML($mathml);\r
+       $xsl = new DOMDocument();\r
+       $xsl->load($xslt_texte);\r
+       $proc->importStylesheet($xsl); // attachement des règles xsl\r
+\r
+       // lancer le parseur\r
+       if (!$latex_sortie = $proc->transformToXml($xml))\r
+               return(_T('odtspip:err_transformation_xslt_mathml'));\r
+  \r
+    return $latex_sortie;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/odt2spip_30/inc/xsltml/README b/www/plugins/odt2spip_30/inc/xsltml/README
new file mode 100644 (file)
index 0000000..6d173af
--- /dev/null
@@ -0,0 +1,97 @@
+README for the XSLT MathML Library\r
+\r
+XSLT MathML Library is a set of XSLT stylesheets to transform\r
+MathML 2.0 to LaTeX.\r
+\r
+For more information, see\r
+http://www.raleigh.ru/MathML/mmltex/index.php?lang=en\r
+\r
+Manifest\r
+--------\r
+\r
+README        this file\r
+mmltex.xsl\r
+tokens.xsl\r
+glayout.xsl\r
+scripts.xsl\r
+tables.xsl\r
+entities.xsl\r
+cmarkup.xsl\r
+\r
+Use\r
+---\r
+\r
+There are two ways of using the library:\r
+\r
+    * Use a local copy of the library.\r
+\r
+        1. Download the distribution (see below).\r
+\r
+        2. Unpack the distribution, using unzip.\r
+\r
+        3. In your stylesheet import or include either the main\r
+           stylesheet, mmltex.xsl, or the stylesheet module you\r
+           wish to use, such as tokens.xsl. This example assumes\r
+           that the distribution has been extracted into the same\r
+           directory as your own stylesheet:\r
+\r
+           <xsl:import href="mmltex.xsl"/>\r
+\r
+    * Import or include either the main stylesheet, or the\r
+      stylesheet module you wish to use, directly from the library\r
+      website; http://www.raleigh.ru/MathML/mmltex/. For example:\r
+\r
+      <xsl:import href="http://www.raleigh.ru/MathML/mmltex/mmltex.xsl"/>\r
+\r
+Obtaining The Library\r
+---------------------\r
+\r
+The XSLT MathML Library is available for download as:\r
+\r
+    * Zip file: http://www.raleigh.ru/MathML/mmltex/mmltex.zip\r
+\r
+Copyright\r
+---------\r
+\r
+Copyright (C) 2001, 2002 Vasil Yaroshevich\r
+\r
+Permission is hereby granted, free of charge, to any person\r
+obtaining a copy of this software and associated documentation\r
+files (the ``Software''), to deal in the Software without\r
+restriction, including without limitation the rights to use,\r
+copy, modify, merge, publish, distribute, sublicense, and/or\r
+sell copies of the Software, and to permit persons to whom the\r
+Software is furnished to do so, subject to the following\r
+conditions:\r
+\r
+The above copyright notice and this permission notice shall be\r
+included in all copies or substantial portions of the Software.\r
+\r
+Except as contained in this notice, the names of individuals\r
+credited with contribution to this software shall not be used in\r
+advertising or otherwise to promote the sale, use or other\r
+dealings in this Software without prior written authorization\r
+from the individuals in question.\r
+\r
+Any stylesheet derived from this Software that is publically\r
+distributed will be identified with a different name and the\r
+version strings in any derived Software will be changed so that\r
+no possibility of confusion between the derived package and this\r
+Software will exist.\r
+\r
+Warranty\r
+--------\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\r
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+NONINFRINGEMENT.  IN NO EVENT SHALL NORMAN WALSH OR ANY OTHER\r
+CONTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\r
+OTHER DEALINGS IN THE SOFTWARE.\r
+\r
+Contacting the Author\r
+---------------------\r
+\r
+These stylesheets are maintained by Vasil Yaroshevich, <yarosh@raleigh.ru>.\r
diff --git a/www/plugins/odt2spip_30/inc/xsltml/cmarkup.xsl b/www/plugins/odt2spip_30/inc/xsltml/cmarkup.xsl
new file mode 100644 (file)
index 0000000..c7a7219
--- /dev/null
@@ -0,0 +1,1093 @@
+<?xml version='1.0' encoding="UTF-8"?>\r
+<xsl:stylesheet\r
+               xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+               xmlns:m="http://www.w3.org/1998/Math/MathML"\r
+               version='1.0'>\r
+                \r
+<!-- ====================================================================== -->\r
+<!-- $id: tokens.xsl, 2002/22/11 Exp $\r
+     This file is part of the XSLT MathML Library distribution.\r
+     See ./README or http://www.raleigh.ru/MathML/mmltex for\r
+     copyright and other information                                        -->\r
+<!-- ====================================================================== -->\r
+\r
+<!-- 4.4.1.1 cn -->\r
+<xsl:template match="m:cn"><xsl:apply-templates/></xsl:template>\r
+\r
+<xsl:template match="m:cn[@type='complex-cartesian']">\r
+       <xsl:apply-templates select="text()[1]"/>\r
+       <xsl:text>+</xsl:text>\r
+       <xsl:apply-templates select="text()[2]"/>\r
+       <xsl:text>i</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:cn[@type='rational']">\r
+       <xsl:apply-templates select="text()[1]"/>\r
+       <xsl:text>/</xsl:text>\r
+       <xsl:apply-templates select="text()[2]"/>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:cn[@type='integer' and @base!=10]">\r
+               <xsl:apply-templates/>\r
+               <xsl:text>_{</xsl:text><xsl:value-of select="@base"/><xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:cn[@type='complex-polar']">\r
+       <xsl:apply-templates select="text()[1]"/>\r
+       <xsl:text>e^{i </xsl:text>\r
+       <xsl:apply-templates select="text()[2]"/>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:cn[@type='e-notation']">\r
+    <xsl:apply-templates select="text()[1]"/>\r
+    <xsl:text>E</xsl:text>\r
+    <xsl:apply-templates select="text()[2]"/>\r
+</xsl:template>\r
+\r
+<!-- 4.4.1.1 ci 4.4.1.2 csymbol -->\r
+<xsl:template match="m:ci | m:csymbol">\r
+       <xsl:choose>\r
+               <xsl:when test="string-length(normalize-space(text()))>1">\r
+                       <xsl:text>\mathrm{</xsl:text><xsl:apply-templates/><xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise><xsl:apply-templates/></xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.1 apply 4.4.2.2 reln -->\r
+<xsl:template match="m:apply | m:reln">\r
+       <xsl:apply-templates select="*[1]">\r
+       <!-- <? -->\r
+               <xsl:with-param name="p" select="10"/>\r
+       </xsl:apply-templates>\r
+       <!-- ?> -->\r
+       <xsl:text>(</xsl:text>\r
+       <xsl:for-each select="*[position()>1]">\r
+               <xsl:apply-templates select="."/>\r
+               <xsl:if test="not(position()=last())"><xsl:text>, </xsl:text></xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:text>)</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.3 fn -->\r
+<xsl:template match="m:fn[m:apply[1]]"> <!-- for m:fn using default rule -->\r
+       <xsl:text>(</xsl:text><xsl:apply-templates/><xsl:text>)</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.4 interval -->\r
+<xsl:template match="m:interval[*[2]]">\r
+       <xsl:choose>\r
+               <xsl:when test="@closure='open' or @closure='open-closed'">\r
+                       <xsl:text>\left(</xsl:text>             \r
+               </xsl:when>\r
+               <xsl:otherwise><xsl:text>\left[</xsl:text></xsl:otherwise> \r
+       </xsl:choose>\r
+       <xsl:apply-templates select="*[1]"/>\r
+       <xsl:text> , </xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:choose>\r
+               <xsl:when test="@closure='open' or @closure='closed-open'">\r
+                       <xsl:text>\right)</xsl:text>            \r
+               </xsl:when>\r
+               <xsl:otherwise><xsl:text>\right]</xsl:text></xsl:otherwise> \r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:interval">\r
+       <xsl:text>\left\{</xsl:text><xsl:apply-templates/><xsl:text>\right\}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.5 inverse -->\r
+<xsl:template match="m:apply[*[1][self::m:inverse]]">\r
+       <xsl:apply-templates select="*[2]"/><xsl:text>^{(-1)}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.6 sep 4.4.2.7 condition -->\r
+<xsl:template match="m:sep | m:condition"><xsl:apply-templates/></xsl:template>\r
+\r
+<!-- 4.4.2.9 lambda -->\r
+<xsl:template match="m:lambda">\r
+       <xsl:text>\mathrm{lambda}\: </xsl:text>\r
+       <xsl:apply-templates select="m:bvar/*"/>\r
+       <xsl:text>.\: </xsl:text>\r
+  <xsl:apply-templates select="*[last()]"/>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.10 compose -->\r
+<xsl:template match="m:apply[*[1][self::m:compose]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="1"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\circ </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.11 ident -->\r
+<xsl:template match="m:ident"><xsl:text>\mathrm{id}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.2.12 domain 4.4.2.13 codomain 4.4.2.14 image 4.4.3.21 arg 4.4.3.24 lcm\r
+               4.4.5.9 grad 4.4.5.10 curl 4.4.9.4 median 4.4.9.5 mode-->\r
+<xsl:template match="m:domain | m:codomain | m:image | m:arg | m:lcm | m:grad |\r
+                                                                m:curl | m:median | m:mode">\r
+       <xsl:text>\mathop{\mathrm{</xsl:text>\r
+       <xsl:value-of select="local-name()"/>\r
+       <xsl:text>}}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.15 domainofapplication -->\r
+<xsl:template match="m:domainofapplication"/>\r
+\r
+<!-- 4.4.2.16 piecewise -->\r
+<xsl:template match="m:piecewise">\r
+       <xsl:text>\begin{cases}</xsl:text>\r
+       <xsl:apply-templates select="m:piece"/>\r
+       <xsl:apply-templates select="m:otherwise"/>\r
+       <xsl:text>\end{cases}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:piece">\r
+               <xsl:apply-templates select="*[1]"/>\r
+               <xsl:text> &amp; \text{if $</xsl:text>\r
+               <xsl:apply-templates select="*[2]"/>\r
+               <xsl:text>$}</xsl:text>\r
+               <xsl:if test="not(position()=last()) or ../m:otherwise"><xsl:text>\\ </xsl:text></xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:otherwise">\r
+       <xsl:apply-templates select="*[1]"/>\r
+       <xsl:text> &amp; \text{otherwise}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.1 quotient -->\r
+<xsl:template match="m:apply[*[1][self::m:quotient]]">\r
+       <xsl:text>\left\lfloor\frac{</xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:text>}{</xsl:text>\r
+       <xsl:apply-templates select="*[3]"/>\r
+       <xsl:text>}\right\rfloor </xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.2 factorial -->\r
+<xsl:template match="m:apply[*[1][self::m:factorial]]">\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+       <xsl:text>!</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.3 divide -->\r
+<xsl:template match="m:apply[*[1][self::m:divide]]">\r
+       <xsl:param name="p" select="0"/>\r
+  <xsl:param name="this-p" select="3"/>\r
+  <xsl:if test="$this-p &lt; $p"><xsl:text>\left(</xsl:text></xsl:if>\r
+  <xsl:text>\frac{</xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+<!--           <xsl:with-param name="p" select="$this-p"/>\r
+       </xsl:apply-templates>-->\r
+       <xsl:text>}{</xsl:text>\r
+       <xsl:apply-templates select="*[3]"/>\r
+<!--           <xsl:with-param name="p" select="$this-p"/>\r
+       </xsl:apply-templates>-->\r
+       <xsl:text>}</xsl:text>\r
+       <xsl:if test="$this-p &lt; $p"><xsl:text>\right)</xsl:text></xsl:if>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.4 max min -->\r
+<xsl:template match="m:apply[*[1][self::m:max or self::m:min]]">\r
+       <xsl:text>\</xsl:text>\r
+       <xsl:value-of select="local-name(*[1])"/>\r
+       <xsl:text>\{</xsl:text>\r
+   <xsl:choose>\r
+               <xsl:when test="m:condition">\r
+               <xsl:apply-templates select="*[last()]"/>\r
+               <xsl:text>, </xsl:text>\r
+                       <xsl:apply-templates select="m:condition/node()"/>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:for-each select="*[position() &gt; 1]">\r
+                               <xsl:apply-templates select="."/>\r
+                               <xsl:if test="position() !=last()"><xsl:text> , </xsl:text></xsl:if>\r
+                       </xsl:for-each>\r
+               </xsl:otherwise>\r
+   </xsl:choose>\r
+       <xsl:text>\}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.5  minus-->\r
+<xsl:template match="m:apply[*[1][self::m:minus] and count(*)=2]">\r
+       <xsl:text>-</xsl:text>\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="5"/>\r
+       </xsl:apply-templates>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:apply[*[1][self::m:minus] and count(*)&gt;2]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="mo">-</xsl:with-param>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="this-p" select="2"/>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.6  plus-->\r
+<xsl:template match="m:apply[*[1][self::m:plus]]">\r
+  <xsl:param name="p" select="0"/>\r
+  <xsl:if test="$p &gt; 2">\r
+               <xsl:text>(</xsl:text>\r
+       </xsl:if>\r
+  <xsl:for-each select="*[position()&gt;1]">\r
+   <xsl:if test="position() &gt; 1">\r
+    <xsl:choose>\r
+      <xsl:when test="self::m:apply[*[1][self::m:times] and\r
+      *[2][self::m:apply/*[1][self::m:minus] or self::m:cn[not(m:sep) and\r
+      (number(.) &lt; 0)]]]">-</xsl:when>\r
+      <xsl:otherwise>+</xsl:otherwise>\r
+    </xsl:choose>\r
+   </xsl:if>   \r
+    <xsl:choose>\r
+      <xsl:when test="self::m:apply[*[1][self::m:times] and\r
+      *[2][self::m:cn[not(m:sep) and (number(.) &lt;0)]]]">\r
+                       <xsl:value-of select="-(*[2])"/>\r
+                       <xsl:apply-templates select=".">\r
+                    <xsl:with-param name="first" select="2"/>\r
+                    <xsl:with-param name="p" select="2"/>\r
+                  </xsl:apply-templates>\r
+       </xsl:when>\r
+      <xsl:when test="self::m:apply[*[1][self::m:times] and\r
+      *[2][self::m:apply/*[1][self::m:minus]]]">\r
+                               <xsl:apply-templates select="./*[2]/*[2]"/>\r
+                               <xsl:apply-templates select=".">\r
+                                       <xsl:with-param name="first" select="2"/>\r
+                                       <xsl:with-param name="p" select="2"/>\r
+                               </xsl:apply-templates>\r
+                       </xsl:when>\r
+                       <xsl:otherwise>\r
+                               <xsl:apply-templates select=".">\r
+                                       <xsl:with-param name="p" select="2"/>\r
+                               </xsl:apply-templates>\r
+                       </xsl:otherwise>\r
+               </xsl:choose>\r
+       </xsl:for-each>\r
+       <xsl:if test="$p &gt; 2">\r
+               <xsl:text>)</xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.7 power -->\r
+<xsl:template match="m:apply[*[1][self::m:power]]">\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="5"/>\r
+       </xsl:apply-templates>\r
+       <xsl:text>^{</xsl:text>\r
+       <xsl:apply-templates select="*[3]">\r
+               <xsl:with-param name="p" select="5"/>\r
+       </xsl:apply-templates>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.8 remainder -->\r
+<xsl:template match="m:apply[*[1][self::m:rem]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="mo">\mod </xsl:with-param>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="this-p" select="3"/>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.9  times-->\r
+<xsl:template match="m:apply[*[1][self::m:times]]" name="times">\r
+  <xsl:param name="p" select="0"/>\r
+  <xsl:param name="first" select="1"/>\r
+  <xsl:if test="$p &gt; 3"><xsl:text>(</xsl:text></xsl:if>\r
+  <xsl:for-each select="*[position()&gt;1]">\r
+               <xsl:if test="position() &gt; 1">\r
+                       <xsl:choose>\r
+                               <xsl:when test="self::m:cn">\times <!-- times --></xsl:when>\r
+                               <xsl:otherwise><!--invisible times--></xsl:otherwise>\r
+                       </xsl:choose>\r
+               </xsl:if> \r
+               <xsl:if test="position()&gt;= $first">\r
+                       <xsl:apply-templates select=".">\r
+                               <xsl:with-param name="p" select="3"/>\r
+                       </xsl:apply-templates>\r
+               </xsl:if>\r
+       </xsl:for-each>\r
+  <xsl:if test="$p &gt; 3"><xsl:text>)</xsl:text></xsl:if>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.10 root -->\r
+<xsl:template match="m:apply[*[1][self::m:root]]">\r
+       <xsl:text>\sqrt</xsl:text>\r
+       <xsl:if test="m:degree!=2">\r
+               <xsl:text>[</xsl:text>\r
+               <xsl:apply-templates select="m:degree/*"/>\r
+               <xsl:text>]</xsl:text>\r
+       </xsl:if>\r
+       <xsl:text>{</xsl:text>\r
+       <xsl:apply-templates select="*[position()&gt;1 and not(self::m:degree)]"/>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.11 gcd -->\r
+<xsl:template match="m:gcd"><xsl:text>\gcd </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.3.12 and -->\r
+<xsl:template match="m:apply[*[1][self::m:and]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\land <!-- and --></xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.13 or -->\r
+<xsl:template match="m:apply[*[1][self::m:or]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="3"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\lor </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.14 xor -->\r
+<xsl:template match="m:apply[*[1][self::m:xor]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="3"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\mathop{\mathrm{xor}}</xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.15 not -->\r
+<xsl:template match="m:apply[*[1][self::m:not]]">\r
+       <xsl:text>\neg </xsl:text>\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.16 implies -->\r
+<xsl:template match="m:apply[*[1][self::m:implies]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="mo">\implies </xsl:with-param>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="this-p" select="3"/>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.17 forall 4.4.3.18 exists -->\r
+<xsl:template match="m:apply[*[1][self::m:forall or self::m:exists]]">\r
+       <xsl:text>\</xsl:text>\r
+       <xsl:value-of select="local-name(*[1])"/>\r
+       <xsl:text> </xsl:text>\r
+       <xsl:apply-templates select="m:bvar"/>\r
+       <xsl:if test="m:condition">\r
+               <xsl:text>, </xsl:text><xsl:apply-templates select="m:condition"/>\r
+       </xsl:if>\r
+       <xsl:if test="*[last()][local-name()!='condition'][local-name()!='bvar']">\r
+               <xsl:text>\colon </xsl:text>\r
+         <xsl:apply-templates select="*[last()]"/>\r
+  </xsl:if>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.19 abs -->\r
+<xsl:template match="m:apply[*[1][self::m:abs]]">\r
+       <xsl:text>\left|</xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:text>\right|</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.20 conjugate -->\r
+<xsl:template match="m:apply[*[1][self::m:conjugate]]">\r
+       <xsl:text>\overline{</xsl:text><xsl:apply-templates select="*[2]"/><xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.22 real -->\r
+<xsl:template match="m:real"><xsl:text>\Re </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.3.23 imaginary -->\r
+<xsl:template match="m:imaginary"><xsl:text>\Im </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.3.25 floor -->\r
+<xsl:template match="m:apply[*[1][self::m:floor]]">\r
+       <xsl:text>\lfloor </xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:text>\rfloor </xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.3.25 ceiling -->\r
+<xsl:template match="m:apply[*[1][self::m:ceiling]]">\r
+       <xsl:text>\lceil </xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:text>\rceil </xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.1 eq -->\r
+<xsl:template match="m:apply[*[1][self::m:eq]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="1"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">=</xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.2 neq -->\r
+<xsl:template match="m:apply[*[1][self::m:neq]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="1"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\neq </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.3 gt -->\r
+<xsl:template match="m:apply[*[1][self::m:gt]]">\r
+<xsl:param name="p" select="0"/>\r
+<xsl:call-template name="infix">\r
+       <xsl:with-param name="this-p" select="1"/>\r
+       <xsl:with-param name="p" select="$p"/>\r
+       <xsl:with-param name="mo">&gt; </xsl:with-param>\r
+</xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.4 lt -->\r
+<xsl:template match="m:apply[*[1][self::m:lt]]">\r
+<xsl:param name="p" select="0"/>\r
+<xsl:call-template name="infix">\r
+       <xsl:with-param name="this-p" select="1"/>\r
+       <xsl:with-param name="p" select="$p"/>\r
+       <xsl:with-param name="mo">&lt; </xsl:with-param>\r
+</xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.5 geq -->\r
+<xsl:template match="m:apply[*[1][self::m:geq]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="1"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\ge </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.6 leq -->\r
+<xsl:template match="m:apply[*[1][self::m:leq]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="1"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\le </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.7 equivalent -->\r
+<xsl:template match="m:apply[*[1][self::m:equivalent]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="1"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\equiv </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.8 approx -->\r
+<xsl:template match="m:apply[*[1][self::m:approx]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="1"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\approx </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.4.9 factorof -->\r
+<xsl:template match="m:apply[*[1][self::m:factorof]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="mo"> | </xsl:with-param>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="this-p" select="3"/>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.5.1 int -->\r
+<xsl:template match="m:apply[*[1][self::m:int]]">\r
+       <xsl:text>\int</xsl:text>\r
+       <xsl:if test="m:lowlimit/*|m:interval/*[1]|m:condition/*">\r
+               <xsl:text>_{</xsl:text>\r
+               <xsl:apply-templates select="m:lowlimit/*|m:interval/*[1]|m:condition/*"/>\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="m:uplimit/*|m:interval/*[2]">\r
+               <xsl:text>^{</xsl:text>\r
+               <xsl:apply-templates select="m:uplimit/*|m:interval/*[2]"/>\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:text> </xsl:text>\r
+       <xsl:apply-templates select="*[last()]"/>\r
+       <xsl:text>\,d </xsl:text>\r
+       <xsl:apply-templates select="m:bvar"/>\r
+</xsl:template>\r
+\r
+<!-- 4.4.5.2 diff -->\r
+<xsl:template match="m:apply[*[1][self::m:diff] and m:ci and count(*)=2]" priority="2">\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:text>^\prime </xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:apply[*[1][self::m:diff]]" priority="1">\r
+       <xsl:text>\frac{</xsl:text>\r
+       <xsl:choose>\r
+               <xsl:when test="m:bvar/m:degree">\r
+                       <xsl:text>d^{</xsl:text>\r
+                       <xsl:apply-templates select="m:bvar/m:degree/node()"/>\r
+                       <xsl:text>}</xsl:text>\r
+                       <xsl:apply-templates select="*[last()]"/>\r
+                       <xsl:text>}{d</xsl:text>\r
+                       <xsl:apply-templates select="m:bvar/node()"/>\r
+                       <xsl:text>^{</xsl:text>\r
+                       <xsl:apply-templates select="m:bvar/m:degree/node()"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:text>d </xsl:text>\r
+                       <xsl:apply-templates select="*[last()]"/>\r
+                       <xsl:text>}{d </xsl:text>\r
+                       <xsl:apply-templates select="m:bvar"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.5.3 partialdiff -->\r
+<xsl:template match="m:apply[*[1][self::m:partialdiff] and m:list and m:ci and count(*)=3]" priority="2">\r
+       <xsl:text>D_{</xsl:text>\r
+       <xsl:for-each select="m:list[1]/*">\r
+               <xsl:apply-templates select="."/>\r
+               <xsl:if test="position()&lt;last()"><xsl:text>, </xsl:text></xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:text>}</xsl:text>\r
+       <xsl:apply-templates select="*[3]"/>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:apply[*[1][self::m:partialdiff]]" priority="1">\r
+       <xsl:text>\frac{\partial^{</xsl:text>\r
+       <xsl:choose>\r
+               <xsl:when test="m:degree">\r
+                       <xsl:apply-templates select="m:degree/node()"/>\r
+               </xsl:when>\r
+               <xsl:when test="m:bvar/m:degree[string(number(.))='NaN']">\r
+                       <xsl:for-each select="m:bvar/m:degree">\r
+                               <xsl:apply-templates select="node()"/>\r
+                               <xsl:if test="position()&lt;last()"><xsl:text>+</xsl:text></xsl:if>\r
+                       </xsl:for-each>\r
+                       <xsl:if test="count(m:bvar[not(m:degree)])&gt;0">\r
+                               <xsl:text>+</xsl:text>\r
+                               <xsl:value-of select="count(m:bvar[not(m:degree)])"/>\r
+                       </xsl:if>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:value-of select="sum(m:bvar/m:degree)+count(m:bvar[not(m:degree)])"/>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+       <xsl:text>}</xsl:text>\r
+       <xsl:apply-templates select="*[last()]"/>\r
+       <xsl:text>}{</xsl:text>\r
+       <xsl:for-each select="m:bvar">\r
+               <xsl:text>\partial </xsl:text>\r
+               <xsl:apply-templates select="node()"/>\r
+               <xsl:if test="m:degree">\r
+                       <xsl:text>^{</xsl:text>\r
+                       <xsl:apply-templates select="m:degree/node()"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.2.8 declare 4.4.5.4 lowlimit 4.4.5.5 uplimit 4.4.5.7 degree 4.4.9.5 momentabout -->\r
+<xsl:template match="m:declare | m:lowlimit | m:uplimit | m:degree | m:momentabout"/>\r
+\r
+<!-- 4.4.5.6  bvar-->\r
+<xsl:template match="m:bvar">\r
+       <xsl:apply-templates/>\r
+       <xsl:if test="following-sibling::m:bvar"><xsl:text>, </xsl:text></xsl:if>\r
+</xsl:template>\r
+\r
+<!-- 4.4.5.8 divergence-->\r
+<xsl:template match="m:divergence"><xsl:text>\mathop{\mathrm{div}}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.5.11 laplacian-->\r
+<xsl:template match="m:laplacian"><xsl:text>\nabla^2 </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.6.1 set -->\r
+<xsl:template match="m:set">\r
+       <xsl:text>\{</xsl:text><xsl:call-template name="set"/><xsl:text>\}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.2 list -->\r
+<xsl:template match="m:list">\r
+       <xsl:text>\left[</xsl:text><xsl:call-template name="set"/><xsl:text>\right]</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template name="set">\r
+   <xsl:choose>\r
+               <xsl:when test="m:condition">\r
+               <xsl:apply-templates select="m:bvar/*[not(self::bvar or self::condition)]"/>\r
+               <xsl:text>\colon </xsl:text>\r
+                       <xsl:apply-templates select="m:condition/node()"/>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:for-each select="*">\r
+                               <xsl:apply-templates select="."/>\r
+                               <xsl:if test="position()!=last()"><xsl:text>, </xsl:text></xsl:if>\r
+                       </xsl:for-each>\r
+               </xsl:otherwise>\r
+   </xsl:choose>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.3 union -->\r
+<xsl:template match="m:apply[*[1][self::m:union]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\cup </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.4 intersect -->\r
+<xsl:template match="m:apply[*[1][self::m:intersect]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="3"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\cap </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.5 in -->\r
+<xsl:template match="m:apply[*[1][self::m:in]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="mo">\in </xsl:with-param>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="this-p" select="3"/>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.5 notin -->\r
+<xsl:template match="m:apply[*[1][self::m:notin]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="mo">\notin </xsl:with-param>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="this-p" select="3"/>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.7 subset -->\r
+<xsl:template match="m:apply[*[1][self::m:subset]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\subseteq </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.8 prsubset -->\r
+<xsl:template match="m:apply[*[1][self::m:prsubset]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\subset </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.9 notsubset -->\r
+<xsl:template match="m:apply[*[1][self::m:notsubset]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\nsubseteq </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.10 notprsubset -->\r
+<xsl:template match="m:apply[*[1][self::m:notprsubset]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\not\subset </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.11 setdiff -->\r
+<xsl:template match="m:apply[*[1][self::m:setdiff]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\setminus </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.12 card -->\r
+<xsl:template match="m:apply[*[1][self::m:card]]">\r
+       <xsl:text>|</xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:text>|</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.6.13 cartesianproduct 4.4.10.6 vectorproduct -->\r
+<xsl:template match="m:apply[*[1][self::m:cartesianproduct or self::m:vectorproduct]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\times </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<xsl:template\r
+match="m:apply[*[1][self::m:cartesianproduct][count(following-sibling::m:reals)=count(following-sibling::*)]]"\r
+priority="2">\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="5"/>\r
+       </xsl:apply-templates>\r
+       <xsl:text>^{</xsl:text>\r
+       <xsl:value-of select="count(*)-1"/>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.7.1 sum -->\r
+<xsl:template match="m:apply[*[1][self::m:sum]]">\r
+       <xsl:text>\sum</xsl:text><xsl:call-template name="series"/>\r
+</xsl:template>\r
+\r
+<!-- 4.4.7.2 product -->\r
+<xsl:template match="m:apply[*[1][self::m:product]]">\r
+       <xsl:text>\prod</xsl:text><xsl:call-template name="series"/>\r
+</xsl:template>\r
+       \r
+<xsl:template name="series">\r
+       <xsl:if test="m:lowlimit/*|m:interval/*[1]|m:condition/*">\r
+               <xsl:text>_{</xsl:text>\r
+               <xsl:if test="not(m:condition)">\r
+                       <xsl:apply-templates select="m:bvar"/>\r
+                       <xsl:text>=</xsl:text>\r
+               </xsl:if>\r
+               <xsl:apply-templates select="m:lowlimit/*|m:interval/*[1]|m:condition/*"/>\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="m:uplimit/*|m:interval/*[2]">\r
+               <xsl:text>^{</xsl:text>\r
+               <xsl:apply-templates select="m:uplimit/*|m:interval/*[2]"/>\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:text> </xsl:text>\r
+       <xsl:apply-templates select="*[last()]"/>\r
+</xsl:template>\r
+\r
+<!-- 4.4.7.3 limit -->\r
+<xsl:template match="m:apply[*[1][self::m:limit]]">\r
+       <xsl:text>\lim_{</xsl:text>\r
+       <xsl:apply-templates select="m:lowlimit|m:condition/*"/>\r
+       <xsl:text>}</xsl:text>\r
+       <xsl:apply-templates select="*[last()]"/>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:apply[m:limit]/m:lowlimit" priority="3">\r
+       <xsl:apply-templates select="../m:bvar/node()"/>\r
+       <xsl:text>\to </xsl:text>\r
+       <xsl:apply-templates/>\r
+</xsl:template>\r
+\r
+<!-- 4.4.7.4 tendsto -->\r
+<xsl:template match="m:apply[*[1][self::m:tendsto]]">\r
+       <xsl:param name="p"/>\r
+       <xsl:call-template name="binary">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\r
+                       <xsl:choose>\r
+                               <xsl:when test="@type='above'">\searrow </xsl:when>\r
+                               <xsl:when test="@type='below'">\nearrow </xsl:when>\r
+                               <xsl:when test="@type='two-sided'">\rightarrow </xsl:when>\r
+                               <xsl:otherwise>\to </xsl:otherwise>\r
+                       </xsl:choose>\r
+               </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.8.1 common tringonometric functions 4.4.8.3 natural logarithm -->\r
+<xsl:template match="m:apply[*[1][\r
+ self::m:sin or                self::m:cos or  self::m:tan or          self::m:sec or\r
+ self::m:csc or                self::m:cot or  self::m:sinh or         self::m:cosh or\r
+ self::m:tanh or               self::m:coth or self::m:arcsin or       self::m:arccos or\r
+ self::m:arctan or     self::m:ln]]">\r
+       <xsl:text>\</xsl:text>\r
+       <xsl:value-of select="local-name(*[1])"/>\r
+       <xsl:text> </xsl:text>\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:sin | m:cos | m:tan | m:sec | m:csc |\r
+                                                                m:cot | m:sinh | m:cosh | m:tanh | m:coth |\r
+                                                                m:arcsin | m:arccos | m:arctan | m:ln">\r
+       <xsl:text>\</xsl:text>\r
+       <xsl:value-of select="local-name(.)"/>\r
+       <xsl:text> </xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:apply[*[1][\r
+ self::m:sech or               self::m:csch or         self::m:arccosh or\r
+ self::m:arccot or     self::m:arccoth or      self::m:arccsc or\r
+ self::m:arccsch or self::m:arcsec or  self::m:arcsech or\r
+ self::m:arcsinh or self::m:arctanh]]">\r
+       <xsl:text>\mathrm{</xsl:text>\r
+       <xsl:value-of select="local-name(*[1])"/>\r
+       <xsl:text>\,}</xsl:text>\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:sech | m:csch | m:arccosh | m:arccot |\r
+                                                                m:arccoth | m:arccsc |m:arccsch |m:arcsec |\r
+                                                                m:arcsech | m:arcsinh | m:arctanh">\r
+       <xsl:text>\mathrm{</xsl:text>\r
+       <xsl:value-of select="local-name(.)"/>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.8.2 exp -->\r
+<xsl:template match="m:apply[*[1][self::m:exp]]">\r
+       <xsl:text>e^{</xsl:text><xsl:apply-templates select="*[2]"/><xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.8.4 log -->\r
+<xsl:template match="m:apply[*[1][self::m:log]]">\r
+       <xsl:text>\lg </xsl:text>\r
+       <xsl:apply-templates select="*[last()]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:apply[*[1][self::m:log] and m:logbase != 10]">\r
+       <xsl:text>\log_{</xsl:text>\r
+       <xsl:apply-templates select="m:logbase/node()"/>\r
+       <xsl:text>}</xsl:text>\r
+       <xsl:apply-templates select="*[last()]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+</xsl:template>\r
+\r
+<!-- 4.4.9.1 mean -->\r
+<xsl:template match="m:apply[*[1][self::m:mean]]">\r
+       <xsl:text>\langle </xsl:text>\r
+       <xsl:for-each select="*[position()&gt;1]">\r
+               <xsl:apply-templates select="."/>\r
+               <xsl:if test="position() !=last()"><xsl:text>, </xsl:text></xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:text>\rangle </xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.9.2 sdef -->\r
+<xsl:template match="m:sdev"><xsl:text>\sigma </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.9.3 variance -->\r
+<xsl:template match="m:apply[*[1][self::m:variance]]">\r
+       <xsl:text>\sigma(</xsl:text>\r
+       <xsl:apply-templates select="*[2]"/>\r
+       <xsl:text>)^2</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.9.5 moment -->\r
+<xsl:template match="m:apply[*[1][self::m:moment]]">\r
+       <xsl:text>\langle </xsl:text>\r
+       <xsl:apply-templates select="*[last()]"/>\r
+       <xsl:text>^{</xsl:text>\r
+       <xsl:apply-templates select="m:degree/node()"/>\r
+       <xsl:text>}\rangle</xsl:text>\r
+       <xsl:if test="m:momentabout">\r
+               <xsl:text>_{</xsl:text>\r
+               <xsl:apply-templates select="m:momentabout/node()"/>\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:text> </xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.10.1 vector  -->\r
+<xsl:template match="m:vector">\r
+       <xsl:text>\left(\begin{array}{c}</xsl:text>\r
+       <xsl:for-each select="*">\r
+               <xsl:apply-templates select="."/>\r
+               <xsl:if test="position()!=last()"><xsl:text>\\ </xsl:text></xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:text>\end{array}\right)</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.10.2 matrix  -->\r
+<xsl:template match="m:matrix">\r
+       <xsl:text>\begin{pmatrix}</xsl:text>\r
+       <xsl:apply-templates/>\r
+       <xsl:text>\end{pmatrix}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.10.3 matrixrow  -->\r
+<xsl:template match="m:matrixrow">\r
+       <xsl:for-each select="*">\r
+               <xsl:apply-templates select="."/>\r
+               <xsl:if test="position()!=last()"><xsl:text> &amp; </xsl:text></xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:if test="position()!=last()"><xsl:text>\\ </xsl:text></xsl:if>\r
+</xsl:template>\r
+\r
+<!-- 4.4.10.4 determinant  -->\r
+<xsl:template match="m:apply[*[1][self::m:determinant]]">\r
+       <xsl:text>\det </xsl:text>\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:apply[*[1][self::m:determinant]][*[2][self::m:matrix]]" priority="2">\r
+       <xsl:text>\begin{vmatrix}</xsl:text>\r
+       <xsl:apply-templates select="m:matrix/*"/>\r
+       <xsl:text>\end{vmatrix}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.10.5 transpose -->\r
+<xsl:template match="m:apply[*[1][self::m:transpose]]">\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+       <xsl:text>^T</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.10.5 selector -->\r
+<xsl:template match="m:apply[*[1][self::m:selector]]">\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="7"/>\r
+       </xsl:apply-templates>\r
+       <xsl:text>_{</xsl:text>\r
+       <xsl:for-each select="*[position()&gt;2]">\r
+               <xsl:apply-templates select="."/>\r
+               <xsl:if test="position() !=last()"><xsl:text>, </xsl:text></xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<!-- 4.4.10.7 scalarproduct 4.4.10.8 outerproduct -->\r
+<xsl:template match="m:apply[*[1][self::m:scalarproduct or self::m:outerproduct]]">\r
+       <xsl:param name="p" select="0"/>\r
+       <xsl:call-template name="infix">\r
+               <xsl:with-param name="this-p" select="2"/>\r
+               <xsl:with-param name="p" select="$p"/>\r
+               <xsl:with-param name="mo">\dot </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<!-- 4.4.11.2 semantics -->\r
+<xsl:template match="m:semantics"><xsl:apply-templates select="*[1]"/></xsl:template>\r
+\r
+<xsl:template match="m:semantics[m:annotation/@encoding='TeX']">\r
+       <xsl:apply-templates select="m:annotation[@encoding='TeX']/node()"/>\r
+</xsl:template>\r
+\r
+<!-- 4.4.12.1 integers -->\r
+<xsl:template match="m:integers"><xsl:text>\mathbb{Z}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.2 reals -->\r
+<xsl:template match="m:reals"><xsl:text>\mathbb{R}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.3 rationals -->\r
+<xsl:template match="m:rationals"><xsl:text>\mathbb{Q}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.4 naturalnumbers -->\r
+<xsl:template match="m:naturalnumbers"><xsl:text>\mathbb{N}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.5 complexes -->\r
+<xsl:template match="m:complexes"><xsl:text>\mathbb{C}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.6 primes -->\r
+<xsl:template match="m:primes"><xsl:text>\mathbb{P}</xsl:text></xsl:template>\r
+       \r
+<!-- 4.4.12.7 exponentiale -->\r
+<xsl:template match="m:exponentiale"><xsl:text>e</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.8 imaginaryi -->\r
+<xsl:template match="m:imaginaryi"><xsl:text>i</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.9 notanumber -->\r
+<xsl:template match="m:notanumber"><xsl:text>NaN</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.10 true -->\r
+<xsl:template match="m:true"><xsl:text>\mbox{true}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.11 false -->\r
+<xsl:template match="m:false"><xsl:text>\mbox{false}</xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.12 emptyset -->\r
+<xsl:template match="m:emptyset"><xsl:text>\emptyset </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.13 pi -->\r
+<xsl:template match="m:pi"><xsl:text>\pi </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.14 eulergamma -->\r
+<xsl:template match="m:eulergamma"><xsl:text>\gamma </xsl:text></xsl:template>\r
+\r
+<!-- 4.4.12.15 infinity -->\r
+<xsl:template match="m:infinity"><xsl:text>\infty </xsl:text></xsl:template>\r
+\r
+<!-- ****************************** -->\r
+<xsl:template name="infix" >\r
+  <xsl:param name="mo"/>\r
+  <xsl:param name="p" select="0"/>\r
+  <xsl:param name="this-p" select="0"/>\r
+  <xsl:if test="$this-p &lt; $p"><xsl:text>(</xsl:text></xsl:if>\r
+  <xsl:for-each select="*[position()&gt;1]">\r
+               <xsl:if test="position() &gt; 1">\r
+                       <xsl:copy-of select="$mo"/>\r
+               </xsl:if>   \r
+               <xsl:apply-templates select=".">\r
+                       <xsl:with-param name="p" select="$this-p"/>\r
+               </xsl:apply-templates>\r
+       </xsl:for-each>\r
+  <xsl:if test="$this-p &lt; $p"><xsl:text>)</xsl:text></xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:template name="binary" >\r
+  <xsl:param name="mo"/>\r
+  <xsl:param name="p" select="0"/>\r
+  <xsl:param name="this-p" select="0"/>\r
+  <xsl:if test="$this-p &lt; $p"><xsl:text>(</xsl:text></xsl:if>\r
+       <xsl:apply-templates select="*[2]">\r
+               <xsl:with-param name="p" select="$this-p"/>\r
+       </xsl:apply-templates>\r
+       <xsl:value-of select="$mo"/>\r
+       <xsl:apply-templates select="*[3]">\r
+       <xsl:with-param name="p" select="$this-p"/>\r
+       </xsl:apply-templates>\r
+       <xsl:if test="$this-p &lt; $p"><xsl:text>)</xsl:text></xsl:if>\r
+</xsl:template>\r
+\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/inc/xsltml/entities.xsl b/www/plugins/odt2spip_30/inc/xsltml/entities.xsl
new file mode 100644 (file)
index 0000000..75bebf6
--- /dev/null
@@ -0,0 +1,316 @@
+<?xml version='1.0' encoding="UTF-8"?>\r
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+               xmlns:m="http://www.w3.org/1998/Math/MathML"\r
+                version='1.0'>\r
+                \r
+<!-- ====================================================================== -->\r
+<!-- $id: entities.xsl, 2002/22/11 Exp $\r
+     This file is part of the XSLT MathML Library distribution.\r
+     See ./README or http://www.raleigh.ru/MathML/mmltex for\r
+     copyright and other information                                        -->\r
+<!-- ====================================================================== -->\r
+\r
+<xsl:template name="replaceEntities">\r
+       <xsl:param name="content"/>\r
+       <xsl:if test="string-length($content)>0">\r
+       <xsl:choose>\r
+               <xsl:when test="starts-with($content,'&#x0025B;')"><xsl:value-of select="'\varepsilon '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0025B;')"/></xsl:call-template></xsl:when>    <!--/varepsilon -->\r
+\r
+<!-- ====================================================================== -->\r
+<!--   Unicode 3.2\r
+       Greek\r
+       Range: 0370-03FF\r
+       http://www.unicode.org/charts/PDF/U0370.pdf                         -->\r
+<!-- ====================================================================== -->        \r
+               <xsl:when test="starts-with($content,'&#x00393;')"><xsl:value-of select="'\Gamma '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x00393;')"/></xsl:call-template></xsl:when> <!--/Gamma capital Gamma, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x00394;')"><xsl:value-of select="'\Delta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x00394;')"/></xsl:call-template></xsl:when> <!--/Delta capital Delta, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x00398;')"><xsl:value-of select="'\Theta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x00398;')"/></xsl:call-template></xsl:when> <!--/Theta capital Theta, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x0039B;')"><xsl:value-of select="'\Lambda '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0039B;')"/></xsl:call-template></xsl:when>        <!--/Lambda capital Lambda, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x0039E;')"><xsl:value-of select="'\Xi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0039E;')"/></xsl:call-template></xsl:when>    <!--/Xi capital Xi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003A0;')"><xsl:value-of select="'\Pi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003A0;')"/></xsl:call-template></xsl:when>    <!--/Pi capital Pi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003A3;')"><xsl:value-of select="'\Sigma '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003A3;')"/></xsl:call-template></xsl:when> <!--/Sigma capital Sigma, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003A6;')"><xsl:value-of select="'\Phi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003A6;')"/></xsl:call-template></xsl:when>   <!--/Phi capital Phi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003A8;')"><xsl:value-of select="'\Psi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003A8;')"/></xsl:call-template></xsl:when>   <!--/Psi capital Psi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003A9;')"><xsl:value-of select="'\Omega '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003A9;')"/></xsl:call-template></xsl:when> <!--/Omega capital Omega, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B1;')"><xsl:value-of select="'\alpha '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B1;')"/></xsl:call-template></xsl:when> <!--/alpha small alpha, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B2;')"><xsl:value-of select="'\beta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B2;')"/></xsl:call-template></xsl:when>  <!--/beta small beta, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B3;')"><xsl:value-of select="'\gamma '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B3;')"/></xsl:call-template></xsl:when> <!--/gamma small gamma, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B4;')"><xsl:value-of select="'\delta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B4;')"/></xsl:call-template></xsl:when> <!--/delta small delta, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B5;')"><xsl:value-of select="'\epsilon '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B5;')"/></xsl:call-template></xsl:when>       <!--/straightepsilon, small epsilon, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B6;')"><xsl:value-of select="'\zeta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B6;')"/></xsl:call-template></xsl:when>  <!--/zeta small zeta, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B7;')"><xsl:value-of select="'\eta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B7;')"/></xsl:call-template></xsl:when>   <!--/eta small eta, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B8;')"><xsl:value-of select="'\theta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B8;')"/></xsl:call-template></xsl:when> <!--/theta straight theta, small theta, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003B9;')"><xsl:value-of select="'\iota '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003B9;')"/></xsl:call-template></xsl:when>  <!--/iota small iota, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003BA;')"><xsl:value-of select="'\kappa '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003BA;')"/></xsl:call-template></xsl:when> <!--/kappa small kappa, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003BB;')"><xsl:value-of select="'\lambda '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003BB;')"/></xsl:call-template></xsl:when>        <!--/lambda small lambda, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003BC;')"><xsl:value-of select="'\mu '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003BC;')"/></xsl:call-template></xsl:when>    <!--/mu small mu, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003BD;')"><xsl:value-of select="'\nu '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003BD;')"/></xsl:call-template></xsl:when>    <!--/nu small nu, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003BE;')"><xsl:value-of select="'\xi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003BE;')"/></xsl:call-template></xsl:when>    <!--/xi small xi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C0;')"><xsl:value-of select="'\pi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C0;')"/></xsl:call-template></xsl:when>    <!--/pi small pi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C1;')"><xsl:value-of select="'\rho '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C1;')"/></xsl:call-template></xsl:when>   <!--/rho small rho, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C2;')"><xsl:value-of select="'\varsigma '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C2;')"/></xsl:call-template></xsl:when>      <!--/varsigma -->\r
+               <xsl:when test="starts-with($content,'&#x003C3;')"><xsl:value-of select="'\sigma '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C3;')"/></xsl:call-template></xsl:when> <!--/sigma small sigma, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C4;')"><xsl:value-of select="'\tau '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C4;')"/></xsl:call-template></xsl:when>   <!--/tau small tau, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C5;')"><xsl:value-of select="'\upsilon '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C5;')"/></xsl:call-template></xsl:when>       <!--/upsilon small upsilon, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C6;')"><xsl:value-of select="'\phi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C6;')"/></xsl:call-template></xsl:when>   <!--/straightphi - small phi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C7;')"><xsl:value-of select="'\chi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C7;')"/></xsl:call-template></xsl:when>   <!--/chi small chi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C8;')"><xsl:value-of select="'\psi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C8;')"/></xsl:call-template></xsl:when>   <!--/psi small psi, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003C9;')"><xsl:value-of select="'\omega '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003C9;')"/></xsl:call-template></xsl:when> <!--/omega small omega, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003D1;')"><xsl:value-of select="'\vartheta '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003D1;')"/></xsl:call-template></xsl:when>      <!--/vartheta - curly or open theta -->\r
+               <xsl:when test="starts-with($content,'&#x003D2;')"><xsl:value-of select="'\Upsilon '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003D2;')"/></xsl:call-template></xsl:when>       <!--/Upsilon capital Upsilon, Greek -->\r
+               <xsl:when test="starts-with($content,'&#x003D5;')"><xsl:value-of select="'\varphi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003D5;')"/></xsl:call-template></xsl:when>        <!--/varphi - curly or open phi -->\r
+               <xsl:when test="starts-with($content,'&#x003D6;')"><xsl:value-of select="'\varpi '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003D6;')"/></xsl:call-template></xsl:when>         <!--/varpi -->\r
+               <xsl:when test="starts-with($content,'&#x003F0;')"><xsl:value-of select="'\varkappa '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003F0;')"/></xsl:call-template></xsl:when>      <!--/varkappa -->\r
+               <xsl:when test="starts-with($content,'&#x003F1;')"><xsl:value-of select="'\varrho '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x003F1;')"/></xsl:call-template></xsl:when>        <!--/varrho -->\r
+               \r
+<!-- ====================================================================== -->\r
+               <xsl:when test="starts-with($content,'&#x0200B;')"><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0200B;')"/></xsl:call-template></xsl:when>                                            <!--short form of  &InvisibleComma; -->\r
+               <xsl:when test="starts-with($content,'&#x02026;')"><xsl:value-of select="'\dots '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02026;')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test="starts-with($content,'&#x02032;')"><xsl:value-of select="'\prime '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02032;')"/></xsl:call-template></xsl:when>         <!--/prime prime or minute -->\r
+               <xsl:when test="starts-with($content,'&#x02061;')"><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02061;')"/></xsl:call-template></xsl:when>                                            <!-- ApplyFunction -->\r
+               <xsl:when test="starts-with($content,'&#x02062;')"><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02062;')"/></xsl:call-template></xsl:when>                                            <!-- InvisibleTimes -->\r
+<!-- ====================================================================== -->\r
+<!--   Unicode 3.2\r
+       Letterlike Symbols\r
+       Range: 2100-214F\r
+       http://www.unicode.org/charts/PDF/U2100.pdf                         -->\r
+<!-- ====================================================================== -->\r
+               <xsl:when test="starts-with($content,'&#x0210F;&#x0FE00;')"><xsl:value-of select="'\hbar '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0210F;&#x0FE00;')"/></xsl:call-template></xsl:when>        <!--/hbar - Planck's over 2pi -->\r
+               <xsl:when test="starts-with($content,'&#x0210F;')"><xsl:value-of select="'\hslash '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0210F;')"/></xsl:call-template></xsl:when>        <!--/hslash - variant Planck's over 2pi --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02111;')"><xsl:value-of select="'\Im '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02111;')"/></xsl:call-template></xsl:when>            <!--/Im - imaginary   -->\r
+               <xsl:when test="starts-with($content,'&#x02113;')"><xsl:value-of select="'\ell '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02113;')"/></xsl:call-template></xsl:when>           <!--/ell - cursive small l -->\r
+               <xsl:when test="starts-with($content,'&#x02118;')"><xsl:value-of select="'\wp '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02118;')"/></xsl:call-template></xsl:when>            <!--/wp - Weierstrass p -->\r
+               <xsl:when test="starts-with($content,'&#x0211C;')"><xsl:value-of select="'\Re '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0211C;')"/></xsl:call-template></xsl:when>            <!--/Re - real -->\r
+               <xsl:when test="starts-with($content,'&#x02127;')"><xsl:value-of select="'\mho '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02127;')"/></xsl:call-template></xsl:when>           <!--/mho - conductance -->\r
+               <xsl:when test="starts-with($content,'&#x02135;')"><xsl:value-of select="'\aleph '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02135;')"/></xsl:call-template></xsl:when>         <!--/aleph aleph, Hebrew -->\r
+               <xsl:when test="starts-with($content,'&#x02136;')"><xsl:value-of select="'\beth '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02136;')"/></xsl:call-template></xsl:when>          <!--/beth - beth, Hebrew --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02137;')"><xsl:value-of select="'\gimel '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02137;')"/></xsl:call-template></xsl:when>         <!--/gimel - gimel, Hebrew --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02138;')"><xsl:value-of select="'\daleth '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02138;')"/></xsl:call-template></xsl:when>        <!--/daleth - daleth, Hebrew --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02145;')"><xsl:value-of select="'D'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02145;')"/></xsl:call-template></xsl:when>               <!--D for use in differentials, e.g., within integrals -->\r
+               <xsl:when test="starts-with($content,'&#x02146;')"><xsl:value-of select="'d'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02146;')"/></xsl:call-template></xsl:when>               <!--d for use in differentials, e.g., within integrals -->\r
+               <xsl:when test="starts-with($content,'&#x02147;')"><xsl:value-of select="'e'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02147;')"/></xsl:call-template></xsl:when>               <!--e use for the exponential base of the natural logarithms -->\r
+               <xsl:when test="starts-with($content,'&#x02148;')"><xsl:value-of select="'i'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02148;')"/></xsl:call-template></xsl:when>               <!--i for use as a square root of -1 -->\r
+\r
+<!-- ====================================================================== -->\r
+               <xsl:when test="starts-with($content,'&#x02192;')"><xsl:value-of select="'\to '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02192;')"/></xsl:call-template></xsl:when>            <!--/rightarrow /to A: =rightward arrow -->\r
+               \r
+<!-- ====================================================================== -->\r
+<!--   Unicode 3.2\r
+       Mathematical Operators\r
+       Range: 2200-22FF\r
+       http://www.unicode.org/charts/PDF/U2200.pdf                         -->\r
+<!-- ====================================================================== -->        \r
+               <xsl:when test="starts-with($content,'&#x02200;')"><xsl:value-of select="'\forall '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02200;')"/></xsl:call-template></xsl:when>        <!--/forall for all -->\r
+               <xsl:when test="starts-with($content,'&#x02201;')"><xsl:value-of select="'\complement '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02201;')"/></xsl:call-template></xsl:when>    <!--/complement - complement sign --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02202;')"><xsl:value-of select="'\partial '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02202;')"/></xsl:call-template></xsl:when>       <!--/partial partial differential -->\r
+               <xsl:when test="starts-with($content,'&#x02203;')"><xsl:value-of select="'\exists '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02203;')"/></xsl:call-template></xsl:when>        <!--/exists at least one exists -->\r
+               <xsl:when test="starts-with($content,'&#x02204;')"><xsl:value-of select="'\nexists '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02204;')"/></xsl:call-template></xsl:when>       <!--/nexists - negated exists --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02205;&#x0FE00;')"><xsl:value-of select="'\emptyset '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02205;&#x0FE00;')"/></xsl:call-template></xsl:when>    <!--/emptyset - zero, slash -->\r
+               <xsl:when test="starts-with($content,'&#x02205;')"><xsl:value-of select="'\varnothing '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02205;')"/></xsl:call-template></xsl:when>    <!--/varnothing - circle, slash --> <!-- Required amssymb -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02206;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02206;')"/></xsl:call-template></xsl:when>-->\r
+               <xsl:when test="starts-with($content,'&#x02207;')"><xsl:value-of select="'\nabla '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02207;')"/></xsl:call-template></xsl:when>         <!--/nabla del, Hamilton operator -->\r
+               <xsl:when test="starts-with($content,'&#x02208;')"><xsl:value-of select="'\in '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02208;')"/></xsl:call-template></xsl:when>            <!--/in R: set membership  -->\r
+               <xsl:when test="starts-with($content,'&#x02209;')"><xsl:value-of select="'\notin '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02209;')"/></xsl:call-template></xsl:when>         <!--/notin N: negated set membership -->\r
+               <xsl:when test="starts-with($content,'&#x0220B;')"><xsl:value-of select="'\ni '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0220B;')"/></xsl:call-template></xsl:when>            <!--/ni /owns R: contains -->\r
+               <xsl:when test="starts-with($content,'&#x0220C;')"><xsl:value-of select="'\not\ni '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0220C;')"/></xsl:call-template></xsl:when>        <!--negated contains -->\r
+               <xsl:when test="starts-with($content,'&#x0220F;')"><xsl:value-of select="'\prod '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0220F;')"/></xsl:call-template></xsl:when>          <!--/prod L: product operator -->\r
+               <xsl:when test="starts-with($content,'&#x02210;')"><xsl:value-of select="'\coprod '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02210;')"/></xsl:call-template></xsl:when>        <!--/coprod L: coproduct operator -->\r
+               <xsl:when test="starts-with($content,'&#x02211;')"><xsl:value-of select="'\sum '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02211;')"/></xsl:call-template></xsl:when>           <!--/sum L: summation operator -->\r
+               <xsl:when test="starts-with($content,'&#x02212;')"><xsl:value-of select="'-'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02212;')"/></xsl:call-template></xsl:when>               <!--B: minus sign -->           \r
+               <xsl:when test="starts-with($content,'&#x02213;')"><xsl:value-of select="'\mp '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02213;')"/></xsl:call-template></xsl:when>            <!--/mp B: minus-or-plus sign -->\r
+               <xsl:when test="starts-with($content,'&#x02214;')"><xsl:value-of select="'\dotplus '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02214;')"/></xsl:call-template></xsl:when>       <!--/dotplus B: plus sign, dot above --> <!-- Required amssymb -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02215;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02215;')"/></xsl:call-template></xsl:when>-->\r
+               <xsl:when test="starts-with($content,'&#x02216;')"><xsl:value-of select="'\setminus '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02216;')"/></xsl:call-template></xsl:when>      <!--/setminus B: reverse solidus -->\r
+               <xsl:when test="starts-with($content,'&#x02217;')"><xsl:value-of select="'\ast '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02217;')"/></xsl:call-template></xsl:when>           <!--low asterisk -->\r
+               <xsl:when test="starts-with($content,'&#x02218;')"><xsl:value-of select="'\circ '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02218;')"/></xsl:call-template></xsl:when>          <!--/circ B: composite function (small circle) -->\r
+               <xsl:when test="starts-with($content,'&#x02219;')"><xsl:value-of select="'\bullet '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02219;')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test="starts-with($content,'&#x0221A;')"><xsl:value-of select="'\surd '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0221A;')"/></xsl:call-template></xsl:when>          <!--/surd radical -->\r
+               <xsl:when test="starts-with($content,'&#x0221D;')"><xsl:value-of select="'\propto '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0221D;')"/></xsl:call-template></xsl:when>        <!--/propto R: is proportional to -->\r
+               <xsl:when test="starts-with($content,'&#x0221E;')"><xsl:value-of select="'\infty '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0221E;')"/></xsl:call-template></xsl:when>         <!--/infty infinity -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0221F;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0221F;')"/></xsl:call-template></xsl:when>               right (90 degree) angle -->\r
+               <xsl:when test="starts-with($content,'&#x02220;')"><xsl:value-of select="'\angle '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02220;')"/></xsl:call-template></xsl:when>         <!--/angle - angle -->\r
+               <xsl:when test="starts-with($content,'&#x02221;')"><xsl:value-of select="'\measuredangle '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02221;')"/></xsl:call-template></xsl:when> <!--/measuredangle - angle-measured --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02222;')"><xsl:value-of select="'\sphericalangle '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02222;')"/></xsl:call-template></xsl:when><!--/sphericalangle angle-spherical --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02223;')"><xsl:value-of select="'\mid '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02223;')"/></xsl:call-template></xsl:when>           <!--/mid R: -->\r
+               <xsl:when test="starts-with($content,'&#x02224;&#x0FE00;')"><xsl:value-of select="'\nshortmid '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02224;&#x0FE00;')"/></xsl:call-template></xsl:when>   <!--/nshortmid --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02224;')"><xsl:value-of select="'\nmid '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02224;')"/></xsl:call-template></xsl:when>          <!--/nmid --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02225;')"><xsl:value-of select="'\parallel '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02225;')"/></xsl:call-template></xsl:when>      <!--/parallel R: parallel -->\r
+               <xsl:when test="starts-with($content,'&#x02226;&#x0FE00;')"><xsl:value-of select="'\nshortparallel '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02226;&#x0FE00;')"/></xsl:call-template></xsl:when>      <!--/nshortparallel N: not short par --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02226;')"><xsl:value-of select="'\nparallel '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02226;')"/></xsl:call-template></xsl:when>     <!--/nparallel N: not parallel --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02227;')"><xsl:value-of select="'\wedge '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02227;')"/></xsl:call-template></xsl:when>         <!--/wedge /land B: logical and -->\r
+               <xsl:when test="starts-with($content,'&#x02228;')"><xsl:value-of select="'\vee '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02228;')"/></xsl:call-template></xsl:when>           <!--/vee /lor B: logical or -->\r
+               <xsl:when test="starts-with($content,'&#x02229;')"><xsl:value-of select="'\cap '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02229;')"/></xsl:call-template></xsl:when>           <!--/cap B: intersection -->\r
+               <xsl:when test="starts-with($content,'&#x0222A;')"><xsl:value-of select="'\cup '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0222A;')"/></xsl:call-template></xsl:when>           <!--/cup B: union or logical sum -->            \r
+               <xsl:when test="starts-with($content,'&#x0222B;')"><xsl:value-of select="'\int '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0222B;')"/></xsl:call-template></xsl:when>           <!--/int L: integral operator -->\r
+               <xsl:when test="starts-with($content,'&#x0222C;')"><xsl:value-of select="'\iint '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0222C;')"/></xsl:call-template></xsl:when>          <!--double integral operator --> <!-- Required amsmath -->\r
+               <xsl:when test="starts-with($content,'&#x0222D;')"><xsl:value-of select="'\iiint '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0222D;')"/></xsl:call-template></xsl:when>         <!--/iiint triple integral operator --> <!-- Required amsmath -->\r
+               <xsl:when test="starts-with($content,'&#x0222E;')"><xsl:value-of select="'\oint '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0222E;')"/></xsl:call-template></xsl:when>          <!--/oint L: contour integral operator -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0222F;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0222F;')"/></xsl:call-template></xsl:when>-->\r
+<!--           <xsl:when test="starts-with($content,'&#x02230;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02230;')"/></xsl:call-template></xsl:when>-->\r
+<!--           <xsl:when test="starts-with($content,'&#x02231;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02231;')"/></xsl:call-template></xsl:when>-->\r
+<!--           <xsl:when test="starts-with($content,'&#x02232;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02232;')"/></xsl:call-template></xsl:when>-->\r
+<!--           <xsl:when test="starts-with($content,'&#x02233;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02233;')"/></xsl:call-template></xsl:when>-->\r
+               <xsl:when test="starts-with($content,'&#x02234;')"><xsl:value-of select="'\therefore '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02234;')"/></xsl:call-template></xsl:when>     <!--/therefore R: therefore --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02235;')"><xsl:value-of select="'\because '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02235;')"/></xsl:call-template></xsl:when>       <!--/because R: because --> <!-- Required amssymb -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x02236;')"><xsl:value-of select="':'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02236;')"/></xsl:call-template></xsl:when>               <!--/ratio -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x02237;')"><xsl:value-of select="'\colon\colon '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02237;')"/></xsl:call-template></xsl:when>   <!--/Colon, two colons -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x02238;')"><xsl:value-of select="'\dot{-}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02238;')"/></xsl:call-template></xsl:when>         <!--/dotminus B: minus sign, dot above -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02239;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02239;')"/></xsl:call-template></xsl:when>               -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0223A;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0223A;')"/></xsl:call-template></xsl:when>               minus with four dots, geometric properties -->          \r
+<!--           <xsl:when test="starts-with($content,'&#x0223B;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0223B;')"/></xsl:call-template></xsl:when>               homothetic -->\r
+               <xsl:when test="starts-with($content,'&#x0223C;')"><xsl:value-of select="'\sim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0223C;')"/></xsl:call-template></xsl:when>           <!--/sim R: similar -->\r
+               <xsl:when test="starts-with($content,'&#x0223D;')"><xsl:value-of select="'\backsim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0223D;')"/></xsl:call-template></xsl:when>       <!--/backsim R: reverse similar --> <!-- Required amssymb -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0223E;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0223E;')"/></xsl:call-template></xsl:when>               most positive -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0223F;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0223F;')"/></xsl:call-template></xsl:when>               ac current -->\r
+               <xsl:when test="starts-with($content,'&#x02240;')"><xsl:value-of select="'\wr '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02240;')"/></xsl:call-template></xsl:when>            <!--/wr B: wreath product -->\r
+               <xsl:when test="starts-with($content,'&#x02241;')"><xsl:value-of select="'\nsim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02241;')"/></xsl:call-template></xsl:when>          <!--/nsim N: not similar --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02242;')"><xsl:value-of select="'\eqsim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02242;')"/></xsl:call-template></xsl:when>         <!--/esim R: equals, similar --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02243;')"><xsl:value-of select="'\simeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02243;')"/></xsl:call-template></xsl:when>         <!--/simeq R: similar, equals -->\r
+               <xsl:when test="starts-with($content,'&#x02244;')"><xsl:value-of select="'\not\simeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02244;')"/></xsl:call-template></xsl:when>     <!--/nsimeq N: not similar, equals -->\r
+               <xsl:when test="starts-with($content,'&#x02245;')"><xsl:value-of select="'\cong '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02245;')"/></xsl:call-template></xsl:when>          <!--/cong R: congruent with -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02246;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02246;')"/></xsl:call-template></xsl:when>               similar, not equals -->\r
+               <xsl:when test="starts-with($content,'&#x02247;')"><xsl:value-of select="'\ncong '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02247;')"/></xsl:call-template></xsl:when>         <!--/ncong N: not congruent with --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02248;')"><xsl:value-of select="'\approx '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02248;')"/></xsl:call-template></xsl:when>        <!--/approx R: approximate -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02249;&#x00338;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02249;&#x00338;')"/></xsl:call-template></xsl:when>     not, vert, approximate -->\r
+               <xsl:when test="starts-with($content,'&#x02249;')"><xsl:value-of select="'\not\approx '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02249;')"/></xsl:call-template></xsl:when>    <!--/napprox N: not approximate -->\r
+               <xsl:when test="starts-with($content,'&#x0224A;')"><xsl:value-of select="'\approxeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0224A;')"/></xsl:call-template></xsl:when>      <!--/approxeq R: approximate, equals --> <!-- Required amssymb -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0224B;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0224B;')"/></xsl:call-template></xsl:when>               approximately identical to -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0224C;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0224C;')"/></xsl:call-template></xsl:when>               /backcong R: reverse congruent -->\r
+               <xsl:when test="starts-with($content,'&#x0224D;')"><xsl:value-of select="'\asymp '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0224D;')"/></xsl:call-template></xsl:when>         <!--/asymp R: asymptotically equal to -->\r
+               <xsl:when test="starts-with($content,'&#x0224E;')"><xsl:value-of select="'\Bumpeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0224E;')"/></xsl:call-template></xsl:when>        <!--/Bumpeq R: bumpy equals --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x0224F;')"><xsl:value-of select="'\bumpeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0224F;')"/></xsl:call-template></xsl:when>        <!--/bumpeq R: bumpy equals, equals --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02250;')"><xsl:value-of select="'\doteq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02250;')"/></xsl:call-template></xsl:when>         <!--/doteq R: equals, single dot above -->\r
+               <xsl:when test="starts-with($content,'&#x02251;')"><xsl:value-of select="'\doteqdot '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02251;')"/></xsl:call-template></xsl:when>      <!--/doteqdot /Doteq R: eq, even dots --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02252;')"><xsl:value-of select="'\fallingdotseq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02252;')"/></xsl:call-template></xsl:when> <!--/fallingdotseq R: eq, falling dots --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02253;')"><xsl:value-of select="'\risingdotseq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02253;')"/></xsl:call-template></xsl:when>  <!--/risingdotseq R: eq, rising dots --> <!-- Required amssymb -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02254;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02254;')"/></xsl:call-template></xsl:when>               /coloneq R: colon, equals -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02255;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02255;')"/></xsl:call-template></xsl:when>               /eqcolon R: equals, colon -->\r
+               <xsl:when test="starts-with($content,'&#x02256;')"><xsl:value-of select="'\eqcirc '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02256;')"/></xsl:call-template></xsl:when>        <!--/eqcirc R: circle on equals sign --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02257;')"><xsl:value-of select="'\circeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02257;')"/></xsl:call-template></xsl:when>        <!--/circeq R: circle, equals --> <!-- Required amssymb -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x02258;')"><xsl:value-of select="'\stackrel{\frown}{=}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02258;')"/></xsl:call-template></xsl:when>\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x02259;')"><xsl:value-of select="'\stackrel{\wedge}{=}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02259;')"/></xsl:call-template></xsl:when>    <!--/wedgeq R: corresponds to (wedge, equals) -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x0225A;')"><xsl:value-of select="'\stackrel{\vee}{=}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0225A;')"/></xsl:call-template></xsl:when>      <!--logical or, equals -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x0225B;')"><xsl:value-of select="'\stackrel{\star}{=}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0225B;')"/></xsl:call-template></xsl:when>     <!--equal, asterisk above -->\r
+               <xsl:when test="starts-with($content,'&#x0225C;')"><xsl:value-of select="'\triangleq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0225C;')"/></xsl:call-template></xsl:when>     <!--/triangleq R: triangle, equals --> <!-- Required amssymb -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x0225D;')"><xsl:value-of select="'\stackrel{\scriptscriptstyle\mathrm{def}}{=}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0225D;')"/></xsl:call-template></xsl:when>\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x0225E;')"><xsl:value-of select="'\stackrel{\scriptscriptstyle\mathrm{m}}{=}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0225E;')"/></xsl:call-template></xsl:when>      \r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x0225F;')"><xsl:value-of select="'\stackrel{?}{=}'" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0225F;')"/></xsl:call-template></xsl:when> <!--/questeq R: equal with questionmark -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02260;&#x0FE00;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02260;&#x0FE00;')"/></xsl:call-template></xsl:when>     not equal, dot -->\r
+               <xsl:when test="starts-with($content,'&#x02260;')"><xsl:value-of select="'\ne '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02260;')"/></xsl:call-template></xsl:when>            <!--/ne /neq R: not equal -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02261;&#x020E5;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02261;&#x020E5;')"/></xsl:call-template></xsl:when>     reverse not equivalent -->\r
+               <xsl:when test="starts-with($content,'&#x02261;')"><xsl:value-of select="'\equiv '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02261;')"/></xsl:call-template></xsl:when>         <!--/equiv R: identical with -->\r
+               <xsl:when test="starts-with($content,'&#x02262;')"><xsl:value-of select="'\not\equiv '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02262;')"/></xsl:call-template></xsl:when>     <!--/nequiv N: not identical with -->\r
+<!--           <xsl:when test="starts-with($content,'&#x02263;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02263;')"/></xsl:call-template></xsl:when>               -->\r
+               <xsl:when test="starts-with($content,'&#x02264;')"><xsl:value-of select="'\le '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02264;')"/></xsl:call-template></xsl:when>            <!--/leq /le R: less-than-or-equal -->\r
+               <xsl:when test="starts-with($content,'&#x02265;')"><xsl:value-of select="'\ge '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02265;')"/></xsl:call-template></xsl:when>            <!--/geq /ge R: greater-than-or-equal -->\r
+               <xsl:when test="starts-with($content,'&#x02266;')"><xsl:value-of select="'\leqq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02266;')"/></xsl:call-template></xsl:when>          <!--/leqq R: less, double equals --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02267;')"><xsl:value-of select="'\geqq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02267;')"/></xsl:call-template></xsl:when>          <!--/geqq R: greater, double equals --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02268;')"><xsl:value-of select="'\lneqq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02268;')"/></xsl:call-template></xsl:when>         <!--/lneqq N: less, not double equals --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02269;')"><xsl:value-of select="'\gneqq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02269;')"/></xsl:call-template></xsl:when>         <!--/gneqq N: greater, not dbl equals --> <!-- Required amssymb -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0226A;&#x00338;&#x0FE00;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226A;&#x00338;&#x0FE00;')"/></xsl:call-template></xsl:when>   not much less than, variant -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0226A;&#x00338;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226A;&#x00338;')"/></xsl:call-template></xsl:when>     not, vert, much less than -->\r
+               <xsl:when test="starts-with($content,'&#x0226A;')"><xsl:value-of select="'\ll '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226A;')"/></xsl:call-template></xsl:when>            <!--/ll R: double less-than sign -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0226B;&#x00338;&#x0FE00;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226B;&#x00338;&#x0FE00;')"/></xsl:call-template></xsl:when>   not much greater than, variant -->\r
+<!--           <xsl:when test="starts-with($content,'&#x0226B;&#x00338;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226B;&#x00338;')"/></xsl:call-template></xsl:when>     not, vert, much greater than -->\r
+               <xsl:when test="starts-with($content,'&#x0226B;')"><xsl:value-of select="'\gg '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226B;')"/></xsl:call-template></xsl:when>            <!--/gg R: dbl greater-than sign -->\r
+               <xsl:when test="starts-with($content,'&#x0226C;')"><xsl:value-of select="'\between '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226C;')"/></xsl:call-template></xsl:when>       <!--/between R: between --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x0226D;')"><xsl:value-of select="'\not\asymp '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226D;')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test="starts-with($content,'&#x0226E;')"><xsl:value-of select="'\nless '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226E;')"/></xsl:call-template></xsl:when>         <!--/nless N: not less-than --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x0226F;')"><xsl:value-of select="'\ngtr '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0226F;')"/></xsl:call-template></xsl:when>          <!--/ngtr N: not greater-than --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02270;&#x020E5;')"><xsl:value-of select="'\nleq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02270;&#x020E5;')"/></xsl:call-template></xsl:when>        <!--/nleq N: not less-than-or-equal --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02270;')"><xsl:value-of select="'\nleqq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02270;')"/></xsl:call-template></xsl:when>         <!--/nleqq N: not less, dbl equals --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02271;&#x020E5;')"><xsl:value-of select="'\ngeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02271;&#x020E5;')"/></xsl:call-template></xsl:when>        <!--/ngeq N: not greater-than-or-equal --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02271;')"><xsl:value-of select="'\ngeqq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02271;')"/></xsl:call-template></xsl:when>         <!--/ngeqq N: not greater, dbl equals --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02272;')"><xsl:value-of select="'\lesssim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02272;')"/></xsl:call-template></xsl:when>       <!--/lesssim R: less, similar --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02273;')"><xsl:value-of select="'\gtrsim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02273;')"/></xsl:call-template></xsl:when>        <!--/gtrsim R: greater, similar --> <!-- Required amssymb -->           \r
+               <xsl:when test="starts-with($content,'&#x02274;')"><xsl:value-of select="'\not\lesssim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02274;')"/></xsl:call-template></xsl:when>   <!--not less, similar --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02275;')"><xsl:value-of select="'\not\gtrsim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02275;')"/></xsl:call-template></xsl:when>    <!--not greater, similar --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02276;')"><xsl:value-of select="'\lessgtr '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02276;')"/></xsl:call-template></xsl:when>       <!--/lessgtr R: less, greater --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02277;')"><xsl:value-of select="'\gtrless '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02277;')"/></xsl:call-template></xsl:when>       <!--/gtrless R: greater, less --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02278;')"><xsl:value-of select="'\not\lessgtr '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02278;')"/></xsl:call-template></xsl:when>   <!--not less, greater --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02279;')"><xsl:value-of select="'\not\gtrless '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02279;')"/></xsl:call-template></xsl:when>   <!--not greater, less --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x0227A;')"><xsl:value-of select="'\prec '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0227A;')"/></xsl:call-template></xsl:when>          <!--/prec R: precedes -->\r
+               <xsl:when test="starts-with($content,'&#x0227B;')"><xsl:value-of select="'\succ '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0227B;')"/></xsl:call-template></xsl:when>          <!--/succ R: succeeds -->\r
+               <xsl:when test="starts-with($content,'&#x0227C;')"><xsl:value-of select="'\preccurlyeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0227C;')"/></xsl:call-template></xsl:when>   <!--/preccurlyeq R: precedes, curly eq --> <!-- Required amssymb -->            \r
+               <xsl:when test="starts-with($content,'&#x0227D;')"><xsl:value-of select="'\succcurlyeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0227D;')"/></xsl:call-template></xsl:when>   <!--/succcurlyeq R: succeeds, curly eq --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x0227E;')"><xsl:value-of select="'\precsim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0227E;')"/></xsl:call-template></xsl:when>       <!--/precsim R: precedes, similar --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x0227F;')"><xsl:value-of select="'\succsim '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0227F;')"/></xsl:call-template></xsl:when>       <!--/succsim R: succeeds, similar --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02280;')"><xsl:value-of select="'\nprec '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02280;')"/></xsl:call-template></xsl:when>         <!--/nprec N: not precedes --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02281;')"><xsl:value-of select="'\nsucc '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02281;')"/></xsl:call-template></xsl:when>         <!--/nsucc N: not succeeds --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x02282;')"><xsl:value-of select="'\subset '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02282;')"/></xsl:call-template></xsl:when>        <!--/subset R: subset or is implied by -->\r
+               <xsl:when test="starts-with($content,'&#x02283;')"><xsl:value-of select="'\supset '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02283;')"/></xsl:call-template></xsl:when>        <!--/supset R: superset or implies -->\r
+               <xsl:when test="starts-with($content,'&#x02284;')"><xsl:value-of select="'\not\subset '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02284;')"/></xsl:call-template></xsl:when>    <!--not subset -->\r
+               <xsl:when test="starts-with($content,'&#x02285;')"><xsl:value-of select="'\not\supset '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02285;')"/></xsl:call-template></xsl:when>    <!--not superset -->\r
+               <xsl:when test="starts-with($content,'&#x02286;')"><xsl:value-of select="'\subseteq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02286;')"/></xsl:call-template></xsl:when>      <!--/subseteq R: subset, equals -->\r
+               <xsl:when test="starts-with($content,'&#x02287;')"><xsl:value-of select="'\supseteq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02287;')"/></xsl:call-template></xsl:when>      <!--/supseteq R: superset, equals -->\r
+               <xsl:when test="starts-with($content,'&#x0228E;')"><xsl:value-of select="'\uplus '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0228E;')"/></xsl:call-template></xsl:when>         <!--/uplus B: plus sign in union -->\r
+               <xsl:when test="starts-with($content,'&#x02293;')"><xsl:value-of select="'\sqcap '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02293;')"/></xsl:call-template></xsl:when>         <!--/sqcap B: square intersection -->\r
+               <xsl:when test="starts-with($content,'&#x02294;')"><xsl:value-of select="'\bigsqcup '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02294;')"/></xsl:call-template></xsl:when>              <!--/sqcup B: square union -->\r
+               <xsl:when test="starts-with($content,'&#x02295;')"><xsl:value-of select="'\oplus '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02295;')"/></xsl:call-template></xsl:when>         <!--/oplus B: plus sign in circle -->\r
+               <xsl:when test="starts-with($content,'&#x02296;')"><xsl:value-of select="'\ominus '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02296;')"/></xsl:call-template></xsl:when>        <!--/ominus B: minus sign in circle -->\r
+               <xsl:when test="starts-with($content,'&#x02297;')"><xsl:value-of select="'\otimes '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02297;')"/></xsl:call-template></xsl:when>        <!--/otimes B: multiply sign in circle -->\r
+               <xsl:when test="starts-with($content,'&#x02298;')"><xsl:value-of select="'\oslash '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02298;')"/></xsl:call-template></xsl:when>        <!--/oslash B: solidus in circle -->\r
+<!-- ? -->     <xsl:when test="starts-with($content,'&#x02299;')"><xsl:value-of select="'\odot '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x02299;')"/></xsl:call-template></xsl:when>          <!--/odot B: middle dot in circle --> <!--/bigodot L: circle dot operator -->\r
+               <xsl:when test="starts-with($content,'&#x0229F;')"><xsl:value-of select="'\boxminus '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x0229F;')"/></xsl:call-template></xsl:when>      <!--/boxminus B: minus sign in box --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x022A4;')"><xsl:value-of select="'\top '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022A4;')"/></xsl:call-template></xsl:when>           <!--/top top -->\r
+               <xsl:when test="starts-with($content,'&#x022A5;')"><xsl:value-of select="'\perp '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022A5;')"/></xsl:call-template></xsl:when>          <!--/perp R: perpendicular --><!--/bot bottom -->\r
+               <xsl:when test="starts-with($content,'&#x022A6;')"><xsl:value-of select="'\vdash '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022A6;')"/></xsl:call-template></xsl:when>         <!--/vdash R: vertical, dash -->\r
+               <xsl:when test="starts-with($content,'&#x022A7;')"><xsl:value-of select="'\vDash '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022A7;')"/></xsl:call-template></xsl:when>         <!--/vDash R: vertical, dbl dash --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x022A8;')"><xsl:value-of select="'\models '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022A8;')"/></xsl:call-template></xsl:when>        <!--/models R: -->\r
+               <xsl:when test="starts-with($content,'&#x022AA;')"><xsl:value-of select="'\Vvdash '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022AA;')"/></xsl:call-template></xsl:when>        <!--/Vvdash R: triple vertical, dash --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x022C0;')"><xsl:value-of select="'\bigwedge '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C0;')"/></xsl:call-template></xsl:when>      <!--/bigwedge L: logical or operator -->\r
+               <xsl:when test="starts-with($content,'&#x022C1;')"><xsl:value-of select="'\bigvee '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C1;')"/></xsl:call-template></xsl:when>        <!--/bigcap L: intersection operator -->\r
+               <xsl:when test="starts-with($content,'&#x022C2;')"><xsl:value-of select="'\bigcap '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C2;')"/></xsl:call-template></xsl:when>        <!--/bigvee L: logical and operator -->\r
+               <xsl:when test="starts-with($content,'&#x022C3;')"><xsl:value-of select="'\bigcup '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C3;')"/></xsl:call-template></xsl:when>        <!--/bigcup L: union operator -->\r
+               <xsl:when test="starts-with($content,'&#x022C4;')"><xsl:value-of select="'\diamond '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C4;')"/></xsl:call-template></xsl:when>       <!--/diamond B: open diamond -->\r
+               <xsl:when test="starts-with($content,'&#x022C5;')"><xsl:value-of select="'\cdot '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C5;')"/></xsl:call-template></xsl:when>          <!--/cdot B: small middle dot -->\r
+               <xsl:when test="starts-with($content,'&#x022C6;')"><xsl:value-of select="'\star '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C6;')"/></xsl:call-template></xsl:when>          <!--/star B: small star, filled -->\r
+               <xsl:when test="starts-with($content,'&#x022C7;')"><xsl:value-of select="'\divideontimes '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C7;')"/></xsl:call-template></xsl:when> <!--/divideontimes B: division on times --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x022C8;')"><xsl:value-of select="'\bowtie '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022C8;')"/></xsl:call-template></xsl:when>        <!--/bowtie R: -->\r
+               <xsl:when test="starts-with($content,'&#x022CD;')"><xsl:value-of select="'\backsimeq '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022CD;')"/></xsl:call-template></xsl:when>     <!--/backsimeq R: reverse similar, eq --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x022EF;')"><xsl:value-of select="'\cdots '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022EF;')"/></xsl:call-template></xsl:when>         <!--/cdots, three dots, centered -->\r
+<!--           <xsl:when test="starts-with($content,'&#x022F0;')"><xsl:value-of select="' '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022F0;')"/></xsl:call-template></xsl:when>               three dots, ascending -->\r
+               <xsl:when test="starts-with($content,'&#x022F1;')"><xsl:value-of select="'\ddots '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x022F1;')"/></xsl:call-template></xsl:when>         <!--/ddots, three dots, descending -->\r
+\r
+<!-- ====================================================================== -->                \r
+               <xsl:when test="starts-with($content,'&#x025A1;')"><xsl:value-of select="'\square '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x025A1;')"/></xsl:call-template></xsl:when>        <!--/square, square --> <!-- Required amssymb -->\r
+               <xsl:when test="starts-with($content,'&#x025AA;')"><xsl:value-of select="'\blacksquare '" /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '&#x025AA;')"/></xsl:call-template></xsl:when>   <!--/blacksquare, square, filled  --> <!-- Required amssymb -->\r
+               \r
+               <xsl:when test='starts-with($content,"&apos;")'><xsl:value-of select='"\text{&apos;}"' /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select='substring-after($content, "&apos;")'/></xsl:call-template></xsl:when><!-- \text required amslatex -->\r
+               <xsl:when test='starts-with($content,"(")'><xsl:value-of select='"\left("' /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '(')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test='starts-with($content,")")'><xsl:value-of select='"\right)"' /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, ')')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test='starts-with($content,"[")'><xsl:value-of select='"\left["' /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '[')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test='starts-with($content,"]")'><xsl:value-of select='"\right]"' /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, ']')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test='starts-with($content,"{")'><xsl:value-of select='"\left\{"' /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '{')"/></xsl:call-template></xsl:when>\r
+               <xsl:when test='starts-with($content,"}")'><xsl:value-of select='"\right\}"' /><xsl:call-template name="replaceEntities"><xsl:with-param name="content" select="substring-after($content, '}')"/></xsl:call-template></xsl:when>\r
+               \r
+\r
+               <xsl:otherwise>\r
+                       <xsl:value-of select="substring($content,1,1)"/>\r
+                       <xsl:call-template name="replaceEntities">\r
+                               <xsl:with-param name="content" select="substring($content, 2)"/>\r
+                       </xsl:call-template>\r
+               </xsl:otherwise>\r
+       </xsl:choose></xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:template name="replaceMtextEntities">\r
+       <xsl:param name="content"/>\r
+       <xsl:choose>\r
+       <xsl:when test="contains($content,'&#x02009;&#x0200A;&#x0200A;')">      <!-- ThickSpace - space of width 5/18 em -->\r
+               <xsl:call-template name="replaceMtextEntities">\r
+                       <xsl:with-param name="content" select="concat(substring-before($content,'&#x02009;&#x0200A;&#x0200A;'),'\hspace{0.28em}',substring-after($content,'&#x02009;&#x0200A;&#x0200A;'))"/>\r
+               </xsl:call-template>\r
+       </xsl:when>\r
+       <xsl:when test="contains($content,'&#x02009;')">        <!-- ThinSpace - space of width 3/18 em -->\r
+               <xsl:call-template name="replaceMtextEntities">\r
+                       <xsl:with-param name="content" select="concat(substring-before($content,'&#x02009;'),'\hspace{0.17em}',substring-after($content,'&#x02009;'))"/>\r
+               </xsl:call-template>\r
+       </xsl:when>\r
+       <xsl:otherwise>\r
+               <xsl:value-of select="normalize-space($content)"/>\r
+       </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/inc/xsltml/glayout.xsl b/www/plugins/odt2spip_30/inc/xsltml/glayout.xsl
new file mode 100644 (file)
index 0000000..021a4ef
--- /dev/null
@@ -0,0 +1,220 @@
+<?xml version='1.0' encoding="UTF-8"?>\r
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+               xmlns:m="http://www.w3.org/1998/Math/MathML"\r
+                version='1.0'>\r
+\r
+<!-- ====================================================================== -->\r
+<!-- $id: glayout.xsl, 2002/17/05 Exp $\r
+     This file is part of the XSLT MathML Library distribution.\r
+     See ./README or http://www.raleigh.ru/MathML/mmltex for\r
+     copyright and other information                                        -->\r
+<!-- ====================================================================== -->\r
+\r
+<xsl:template match="m:mfrac">\r
+       <xsl:choose>\r
+               <xsl:when test="@bevelled='true'">\r
+<!--                   <xsl:text>\raisebox{1ex}{</xsl:text>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}\!\left/ \!\raisebox{-1ex}{</xsl:text>\r
+                       <xsl:apply-templates select="./*[2]"/>\r
+                       <xsl:text>}\right.</xsl:text>-->\r
+               </xsl:when>\r
+               <xsl:when test="@linethickness">\r
+                       <xsl:text>\genfrac{}{}{</xsl:text>\r
+                       <xsl:choose>\r
+                               <xsl:when test="number(@linethickness)">\r
+                                       <xsl:value-of select="@linethickness div 10"/>\r
+                                       <xsl:text>ex</xsl:text>\r
+                               </xsl:when>\r
+                               <xsl:when test="@linethickness='thin'">\r
+                                       <xsl:text>.05ex</xsl:text>\r
+                               </xsl:when>\r
+                               <xsl:when test="@linethickness='medium'"/>\r
+                               <xsl:when test="@linethickness='thick'">\r
+                                       <xsl:text>.2ex</xsl:text>\r
+                               </xsl:when>\r
+                               <xsl:otherwise>\r
+                                       <xsl:value-of select="@linethickness"/>\r
+                               </xsl:otherwise>\r
+                       </xsl:choose>\r
+                       <xsl:text>}{}{</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:text>\frac{</xsl:text>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+       <xsl:if test="@numalign='right'">\r
+               <xsl:text>\hfill </xsl:text>\r
+       </xsl:if>\r
+       <xsl:apply-templates select="./*[1]"/>\r
+       <xsl:if test="@numalign='left'">\r
+               <xsl:text>\hfill </xsl:text>\r
+       </xsl:if>\r
+       <xsl:text>}{</xsl:text> \r
+       <xsl:if test="@denomalign='right'">\r
+               <xsl:text>\hfill </xsl:text>\r
+       </xsl:if>\r
+       <xsl:apply-templates select="./*[2]"/>\r
+               <xsl:if test="@denomalign='left'">\r
+               <xsl:text>\hfill </xsl:text>\r
+       </xsl:if>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mroot">\r
+       <xsl:choose>\r
+               <xsl:when test="count(./*)=2">\r
+                       <xsl:text>\sqrt[</xsl:text>\r
+                       <xsl:apply-templates select="./*[2]"/>\r
+                       <xsl:text>]{</xsl:text> \r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>  \r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+               <!-- number of argumnets is not 2 - code 25 -->\r
+                       <xsl:message>exception 25:</xsl:message>\r
+                       <xsl:text>\text{exception 25:}</xsl:text> \r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:msqrt">\r
+       <xsl:text>\sqrt{</xsl:text>\r
+       <xsl:apply-templates/>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mfenced">\r
+       <xsl:choose>\r
+               <xsl:when test="@open">\r
+                       <xsl:if test="translate(@open,'{}[]()|','{{{{{{{')='{'">\r
+                               <xsl:text>\left</xsl:text>\r
+                       </xsl:if>\r
+                       <xsl:if test="@open='{' or @open='}'">\r
+                               <xsl:text>\</xsl:text>\r
+                       </xsl:if>\r
+                       <xsl:value-of select="@open"/>\r
+               </xsl:when>\r
+               <xsl:otherwise><xsl:text>\left(</xsl:text></xsl:otherwise>\r
+       </xsl:choose>\r
+       <xsl:choose>\r
+               <xsl:when test="count(./*)>1">\r
+                       <xsl:variable name="symbol">\r
+                               <xsl:choose>\r
+                                       <xsl:when test="@separators">\r
+                                               <xsl:call-template name="startspace">\r
+                                                       <xsl:with-param name="symbol" select="@separators"/>\r
+                                               </xsl:call-template>\r
+                                       </xsl:when>\r
+                                       <xsl:otherwise>,</xsl:otherwise>\r
+                               </xsl:choose>\r
+                       </xsl:variable>\r
+                       <xsl:for-each select="./*">\r
+                               <xsl:apply-templates select="."/>\r
+                               <xsl:if test="not(position()=last())">\r
+                                       <xsl:choose>\r
+                                               <xsl:when test="position()>string-length($symbol)">\r
+                                                       <xsl:value-of select="substring($symbol,string-length($symbol))"/>\r
+                                               </xsl:when>\r
+                                               <xsl:otherwise>\r
+                                                       <xsl:value-of select="substring($symbol,position(),1)"/>\r
+                                               </xsl:otherwise>\r
+                                       </xsl:choose>\r
+                               </xsl:if>\r
+                       </xsl:for-each>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:apply-templates/>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+       <xsl:choose>\r
+               <xsl:when test="@close">\r
+                       <xsl:if test="translate(@open,'{}[]()|','{{{{{{{')='{'">\r
+                               <xsl:text>\right</xsl:text>\r
+                       </xsl:if>\r
+                       <xsl:if test="@open='{' or @open='}'">\r
+                               <xsl:text>\</xsl:text>\r
+                       </xsl:if>               \r
+                       <xsl:value-of select="@close"/>\r
+               </xsl:when>\r
+               <xsl:otherwise><xsl:text>\right)</xsl:text></xsl:otherwise>\r
+       </xsl:choose>   \r
+</xsl:template>\r
+\r
+<xsl:template match="m:mphantom">\r
+       <xsl:text>\phantom{</xsl:text>\r
+       <xsl:apply-templates/>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:menclose">\r
+       <xsl:choose>\r
+               <xsl:when test="@notation = 'actuarial'">\r
+                       <xsl:text>\overline{</xsl:text>\r
+                       <xsl:apply-templates/>\r
+                       <xsl:text>\hspace{.2em}|}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="@notation = 'radical'">\r
+                       <xsl:text>\sqrt{</xsl:text>\r
+                       <xsl:apply-templates/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:text>\overline{)</xsl:text>\r
+                       <xsl:apply-templates/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mrow">\r
+       <xsl:apply-templates/>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mstyle">\r
+       <xsl:if test="@background">\r
+               <xsl:text>\colorbox[rgb]{</xsl:text>\r
+               <xsl:call-template name="color">\r
+                       <xsl:with-param name="color" select="@background"/>\r
+               </xsl:call-template>\r
+               <xsl:text>}{$</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="@color">\r
+               <xsl:text>\textcolor[rgb]{</xsl:text>\r
+               <xsl:call-template name="color">\r
+                       <xsl:with-param name="color" select="@color"/>\r
+               </xsl:call-template>\r
+               <xsl:text>}{</xsl:text>\r
+       </xsl:if>\r
+       <xsl:apply-templates/>\r
+       <xsl:if test="@color">\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="@background">\r
+               <xsl:text>$}</xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+<!--\r
+\r
+<xsl:template match="m:mstyle">\r
+       <xsl:if test="@displaystyle='true'">\r
+               <xsl:text>{\displaystyle</xsl:text>\r
+       </xsl:if>                       \r
+       <xsl:if test="@scriptlevel=2">\r
+               <xsl:text>{\scriptscriptstyle</xsl:text>        \r
+       </xsl:if>\r
+       <xsl:apply-templates/>\r
+       <xsl:if test="@scriptlevel=2">\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="@displaystyle='true'">\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+-->\r
+\r
+<xsl:template match="m:merror">\r
+       <xsl:apply-templates/>\r
+</xsl:template>\r
+\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/inc/xsltml/mmltex.xsl b/www/plugins/odt2spip_30/inc/xsltml/mmltex.xsl
new file mode 100644 (file)
index 0000000..a7d735c
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding="UTF-8"?>\r
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+               xmlns:m="http://www.w3.org/1998/Math/MathML"\r
+                version='1.0'>\r
+                \r
+<xsl:output method="text" indent="no" encoding="UTF-8"/>\r
+\r
+<!-- ====================================================================== -->\r
+<!-- $id: mmltex.xsl, 2002/22/11 Exp $\r
+     This file is part of the XSLT MathML Library distribution.\r
+     See ./README or http://www.raleigh.ru/MathML/mmltex for\r
+     copyright and other information                                        -->\r
+<!-- ====================================================================== -->\r
+\r
+<xsl:include href="tokens.xsl"/>\r
+<xsl:include href="glayout.xsl"/>\r
+<xsl:include href="scripts.xsl"/>\r
+<xsl:include href="tables.xsl"/>\r
+<xsl:include href="entities.xsl"/>\r
+<xsl:include href="cmarkup.xsl"/>\r
+\r
+<!-- Note: variables colora (template color) and symbola (template startspace) only for Sablotron -->\r
+\r
+<xsl:template name="startspace">\r
+       <xsl:param name="symbol"/>\r
+       <xsl:if test="contains($symbol,' ')">\r
+               <xsl:variable name="symbola" select="concat(substring-before($symbol,' '),substring-after($symbol,' '))"/>\r
+               <xsl:call-template name="startspace">\r
+                       <xsl:with-param name="symbol" select="$symbola"/>\r
+               </xsl:call-template>\r
+       </xsl:if>\r
+       <xsl:if test="not(contains($symbol,' '))">\r
+               <xsl:value-of select="$symbol"/>\r
+       </xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:strip-space elements="m:*"/>\r
+\r
+<xsl:template match="m:math">\r
+       <xsl:text>&#x00024;</xsl:text>\r
+       <xsl:apply-templates/>\r
+       <xsl:text>&#x00024;</xsl:text>\r
+</xsl:template>\r
+\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/inc/xsltml/scripts.xsl b/www/plugins/odt2spip_30/inc/xsltml/scripts.xsl
new file mode 100644 (file)
index 0000000..fcaab18
--- /dev/null
@@ -0,0 +1,292 @@
+<?xml version='1.0' encoding="UTF-8"?>\r
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+               xmlns:m="http://www.w3.org/1998/Math/MathML"\r
+                version='1.0'>\r
+                \r
+<!-- ====================================================================== -->\r
+<!-- $Id: scripts.xsl,v 1.1.1.1 2002/10/26 14:20:06 shade33 Exp $\r
+     This file is part of the XSLT MathML Library distribution.\r
+     See ./README or http://www.raleigh.ru/MathML/mmltex for\r
+     copyright and other information                                        -->\r
+<!-- ====================================================================== -->\r
+\r
+<xsl:template match="m:munderover">\r
+       <xsl:variable name="base">\r
+               <xsl:call-template name="startspace">\r
+                       <xsl:with-param name="symbol" select="./*[1]"/>\r
+               </xsl:call-template>\r
+       </xsl:variable>\r
+       <xsl:variable name="under">\r
+               <xsl:call-template name="startspace">\r
+                       <xsl:with-param name="symbol" select="./*[2]"/>\r
+               </xsl:call-template>\r
+       </xsl:variable>\r
+       <xsl:variable name="over">\r
+               <xsl:call-template name="startspace">\r
+                       <xsl:with-param name="symbol" select="./*[3]"/>\r
+               </xsl:call-template>\r
+       </xsl:variable>\r
+       \r
+       <xsl:choose>\r
+               <xsl:when test="$over='&#x000AF;'">     <!-- OverBar - over bar -->\r
+                       <xsl:text>\overline{</xsl:text>\r
+                       <xsl:call-template name="munder">\r
+                               <xsl:with-param name="base" select="$base"/>\r
+                               <xsl:with-param name="under" select="$under"/>\r
+                       </xsl:call-template>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="$over='&#x0FE37;'">     <!-- OverBrace - over brace -->\r
+                       <xsl:text>\overbrace{</xsl:text>\r
+                       <xsl:call-template name="munder">\r
+                               <xsl:with-param name="base" select="$base"/>\r
+                               <xsl:with-param name="under" select="$under"/>\r
+                       </xsl:call-template>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="$under='&#x00332;'">    <!-- UnderBar - combining low line -->\r
+                       <xsl:text>\underline{</xsl:text>\r
+                       <xsl:call-template name="mover">\r
+                               <xsl:with-param name="base" select="$base"/>\r
+                               <xsl:with-param name="over" select="$over"/>\r
+                               <xsl:with-param name="pos_over" select="3"/>\r
+                       </xsl:call-template>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="$under='&#x0FE38;'">    <!-- UnderBrace - under brace -->\r
+                       <xsl:text>\underbrace{</xsl:text>\r
+                       <xsl:call-template name="mover">\r
+                               <xsl:with-param name="base" select="$base"/>\r
+                               <xsl:with-param name="over" select="$over"/>\r
+                               <xsl:with-param name="pos_over" select="3"/>\r
+                       </xsl:call-template>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="translate($base,'&#x0220F;&#x02210;&#x022c2;&#x022c3;&#x02294;',\r
+                                               '&#x02211;&#x02211;&#x02211;&#x02211;&#x02211;')='&#x02211;'">\r
+<!-- if $base is operator, such as\r
+                       &#x02211;       /sum L: summation operator\r
+                       &#x0220F;       /prod L: product operator\r
+                       &#x02210;       /coprod L: coproduct operator\r
+                       &#x022c2;       /bigcap\r
+                       &#x022c3;       /bigcup\r
+                       &#x02294;       /bigsqcup\r
+-->\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>_{</xsl:text>\r
+                       <xsl:apply-templates select="./*[2]"/>\r
+                       <xsl:text>}^{</xsl:text>\r
+                       <xsl:apply-templates select="./*[3]"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:text>\underset{</xsl:text>\r
+                       <xsl:apply-templates select="./*[2]"/>\r
+                       <xsl:text>}{\overset{</xsl:text>\r
+                       <xsl:apply-templates select="./*[3]"/>\r
+                       <xsl:text>}{</xsl:text>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}}</xsl:text>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mover">\r
+       <xsl:call-template name="mover">\r
+               <xsl:with-param name="base">\r
+                       <xsl:call-template name="startspace">\r
+                               <xsl:with-param name="symbol" select="./*[1]"/>\r
+                       </xsl:call-template>\r
+               </xsl:with-param>\r
+               <xsl:with-param name="over">\r
+                       <xsl:call-template name="startspace">\r
+                               <xsl:with-param name="symbol" select="./*[2]"/>\r
+                       </xsl:call-template>\r
+               </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:munder">\r
+       <xsl:call-template name="munder">\r
+               <xsl:with-param name="base">\r
+                       <xsl:call-template name="startspace">\r
+                               <xsl:with-param name="symbol" select="./*[1]"/>\r
+                       </xsl:call-template>\r
+               </xsl:with-param>\r
+               <xsl:with-param name="under">\r
+                       <xsl:call-template name="startspace">\r
+                               <xsl:with-param name="symbol" select="./*[2]"/>\r
+                       </xsl:call-template>\r
+               </xsl:with-param>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+<xsl:template name="mover">\r
+       <xsl:param name="base"/>\r
+       <xsl:param name="over"/>\r
+       <xsl:param name="pos_over" select="2"/>\r
+       <xsl:choose>\r
+               <xsl:when test="$over='&#x000AF;'">     <!-- OverBar - over bar -->\r
+                       <xsl:text>\overline{</xsl:text>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="$over='&#x0FE37;'">     <!-- OverBrace - over brace -->\r
+                       <xsl:text>\overbrace{</xsl:text>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="translate($base,'&#x0220F;&#x02210;&#x022c2;&#x022c3;&#x02294;',\r
+                                               '&#x02211;&#x02211;&#x02211;&#x02211;&#x02211;')='&#x02211;'">\r
+<!-- if $base is operator, such as\r
+                       &#x02211;       /sum L: summation operator\r
+                       &#x0220F;       /prod L: product operator\r
+                       &#x02210;       /coprod L: coproduct operator\r
+                       &#x022c2;       /bigcap\r
+                       &#x022c3;       /bigcup\r
+                       &#x02294;       /bigsqcup\r
+-->\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>^{</xsl:text>\r
+                       <xsl:apply-templates select="./*[$pos_over]"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:text>\stackrel{</xsl:text>\r
+                       <xsl:apply-templates select="./*[$pos_over]"/>\r
+                       <xsl:text>}{</xsl:text>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>\r
+                       <!--\r
+                       <xsl:text>\overset{</xsl:text>\r
+                       <xsl:apply-templates select="./*[$pos_over]"/>\r
+                       <xsl:text>}{</xsl:text> \r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>-->\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template name="munder">\r
+       <xsl:param name="base"/>\r
+       <xsl:param name="under"/>\r
+       <xsl:choose>\r
+               <xsl:when test="$under='&#x00332;'">    <!-- UnderBar - combining low line -->\r
+                       <xsl:text>\underline{</xsl:text>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="$under='&#x0FE38;'">    <!-- UnderBrace - under brace -->\r
+                       <xsl:text>\underbrace{</xsl:text>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:when test="translate($base,'&#x0220F;&#x02210;&#x022c2;&#x022c3;&#x02294;',\r
+                                               '&#x02211;&#x02211;&#x02211;&#x02211;&#x02211;')='&#x02211;'">\r
+<!-- if $base is operator, such as\r
+                       &#x02211;       /sum L: summation operator\r
+                       &#x0220F;       /prod L: product operator\r
+                       &#x02210;       /coprod L: coproduct operator\r
+                       &#x022c2;       /bigcap\r
+                       &#x022c3;       /bigcup\r
+                       &#x02294;       /bigsqcup\r
+-->\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>_{</xsl:text>\r
+                       <xsl:apply-templates select="./*[2]"/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:text>\underset{</xsl:text>         <!-- Required AmsMath package -->\r
+                       <xsl:apply-templates select="./*[2]"/>\r
+                       <xsl:text>}{</xsl:text> \r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:text>}</xsl:text>  \r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:msubsup">\r
+       <xsl:text>{</xsl:text>  \r
+       <xsl:apply-templates select="./*[1]"/>\r
+       <xsl:text>}_{</xsl:text>\r
+       <xsl:apply-templates select="./*[2]"/>\r
+       <xsl:text>}^{</xsl:text>        \r
+       <xsl:apply-templates select="./*[3]"/>\r
+       <xsl:text>}</xsl:text>  \r
+</xsl:template>\r
+\r
+<xsl:template match="m:msup">\r
+       <xsl:text>{</xsl:text>  \r
+       <xsl:apply-templates select="./*[1]"/>\r
+       <xsl:text>}^{</xsl:text>        \r
+       <xsl:apply-templates select="./*[2]"/>\r
+       <xsl:text>}</xsl:text>  \r
+</xsl:template>\r
+\r
+<xsl:template match="m:msub">\r
+       <xsl:text>{</xsl:text>  \r
+       <xsl:apply-templates select="./*[1]"/>\r
+       <xsl:text>}_{</xsl:text>        \r
+       <xsl:apply-templates select="./*[2]"/>\r
+       <xsl:text>}</xsl:text>  \r
+</xsl:template>\r
+\r
+<xsl:template match="m:mmultiscripts" mode="mprescripts">\r
+       <xsl:for-each select="m:mprescripts/following-sibling::*">\r
+               <xsl:if test="position() mod 2 and local-name(.)!='none'">\r
+                       <xsl:text>{}_{</xsl:text>       \r
+                       <xsl:apply-templates select="."/>\r
+                       <xsl:text>}</xsl:text>  \r
+               </xsl:if>\r
+               <xsl:if test="not(position() mod 2) and local-name(.)!='none'">\r
+                       <xsl:text>{}^{</xsl:text>       \r
+                       <xsl:apply-templates select="."/>\r
+                       <xsl:text>}</xsl:text>  \r
+               </xsl:if>\r
+       </xsl:for-each>\r
+       <xsl:apply-templates select="./*[1]"/>\r
+       <xsl:for-each select="m:mprescripts/preceding-sibling::*[position()!=last()]">\r
+               <xsl:if test="position()>2 and local-name(.)!='none'">\r
+                       <xsl:text>{}</xsl:text> \r
+               </xsl:if>\r
+               <xsl:if test="position() mod 2 and local-name(.)!='none'">\r
+                       <xsl:text>_{</xsl:text> \r
+                       <xsl:apply-templates select="."/>\r
+                       <xsl:text>}</xsl:text>  \r
+               </xsl:if>\r
+               <xsl:if test="not(position() mod 2) and local-name(.)!='none'">\r
+                       <xsl:text>^{</xsl:text> \r
+                       <xsl:apply-templates select="."/>\r
+                       <xsl:text>}</xsl:text>  \r
+               </xsl:if>\r
+       </xsl:for-each>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mmultiscripts">\r
+       <xsl:choose>\r
+               <xsl:when test="m:mprescripts">\r
+                       <xsl:apply-templates select="." mode="mprescripts"/>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:apply-templates select="./*[1]"/>\r
+                       <xsl:for-each select="*[position()>1]">\r
+                               <xsl:if test="position()>2 and local-name(.)!='none'">\r
+                                       <xsl:text>{}</xsl:text> \r
+                               </xsl:if>\r
+                               <xsl:if test="position() mod 2 and local-name(.)!='none'">\r
+                                       <xsl:text>_{</xsl:text> \r
+                                       <xsl:apply-templates select="."/>\r
+                                       <xsl:text>}</xsl:text>  \r
+                               </xsl:if>\r
+                               <xsl:if test="not(position() mod 2) and local-name(.)!='none'">\r
+                                       <xsl:text>^{</xsl:text> \r
+                                       <xsl:apply-templates select="."/>\r
+                                       <xsl:text>}</xsl:text>  \r
+                               </xsl:if>\r
+                       </xsl:for-each>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/inc/xsltml/tables.xsl b/www/plugins/odt2spip_30/inc/xsltml/tables.xsl
new file mode 100644 (file)
index 0000000..ad1a10a
--- /dev/null
@@ -0,0 +1,130 @@
+<?xml version='1.0' encoding="UTF-8"?>\r
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+               xmlns:m="http://www.w3.org/1998/Math/MathML"\r
+                version='1.0'>\r
+                \r
+<!-- ====================================================================== -->\r
+<!-- $id: tables.xsl, 2002/17/05 Exp $\r
+     This file is part of the XSLT MathML Library distribution.\r
+     See ./README or http://www.raleigh.ru/MathML/mmltex for\r
+     copyright and other information                                        -->\r
+<!-- ====================================================================== -->\r
+\r
+<xsl:template match="m:mtd[@columnspan]">\r
+       <xsl:text>\multicolumn{</xsl:text>\r
+       <xsl:value-of select="@columnspan"/>\r
+       <xsl:text>}{c}{</xsl:text>\r
+       <xsl:apply-templates/>\r
+       <xsl:text>}</xsl:text>\r
+       <xsl:if test="count(following-sibling::*)>0">\r
+               <xsl:text>&amp; </xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+\r
+\r
+<xsl:template match="m:mtd">\r
+       <xsl:if test="@columnalign='right' or @columnalign='center'">\r
+               <xsl:text>\hfill </xsl:text>\r
+       </xsl:if>\r
+       <xsl:apply-templates/>\r
+       <xsl:if test="@columnalign='left' or @columnalign='center'">\r
+               <xsl:text>\hfill </xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="count(following-sibling::*)>0">\r
+<!--    this test valid for Sablotron, another form - test="not(position()=last())".\r
+       Also for m:mtd[@columnspan] and m:mtr  -->\r
+               <xsl:text>&amp; </xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mtr">\r
+       <xsl:apply-templates/>\r
+       <xsl:if test="count(following-sibling::*)>0">\r
+               <xsl:text>\\ </xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mtable">\r
+       <xsl:text>\begin{array}{</xsl:text>\r
+       <xsl:if test="@frame='solid'">\r
+               <xsl:text>|</xsl:text>\r
+       </xsl:if>\r
+       <xsl:variable name="numbercols" select="count(./m:mtr[1]/m:mtd[not(@columnspan)])+sum(./m:mtr[1]/m:mtd/@columnspan)"/>\r
+       <xsl:choose>\r
+               <xsl:when test="@columnalign">\r
+                       <xsl:variable name="colalign">\r
+                               <xsl:call-template name="colalign">\r
+                                       <xsl:with-param name="colalign" select="@columnalign"/>\r
+                               </xsl:call-template>\r
+                       </xsl:variable>\r
+                       <xsl:choose>\r
+                               <xsl:when test="string-length($colalign) > $numbercols">\r
+                                       <xsl:value-of select="substring($colalign,1,$numbercols)"/>\r
+                               </xsl:when>\r
+                               <xsl:when test="string-length($colalign) &lt; $numbercols">\r
+                                       <xsl:value-of select="$colalign"/>\r
+                                       <xsl:call-template name="generate-string">\r
+                                               <xsl:with-param name="text" select="substring($colalign,string-length($colalign))"/>\r
+                                               <xsl:with-param name="count" select="$numbercols - string-length($colalign)"/>\r
+                                       </xsl:call-template>\r
+                               </xsl:when>\r
+                               <xsl:otherwise>\r
+                                       <xsl:value-of select="$colalign"/>\r
+                               </xsl:otherwise>\r
+                       </xsl:choose>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:call-template name="generate-string">\r
+                               <xsl:with-param name="text" select="'c'"/>\r
+                               <xsl:with-param name="count" select="$numbercols"/>\r
+                       </xsl:call-template>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+       <xsl:if test="@frame='solid'">\r
+               <xsl:text>|</xsl:text>\r
+       </xsl:if>\r
+       <xsl:text>}</xsl:text>\r
+       <xsl:if test="@frame='solid'">\r
+               <xsl:text>\hline </xsl:text>\r
+       </xsl:if>\r
+       <xsl:apply-templates/>\r
+       <xsl:if test="@frame='solid'">\r
+               <xsl:text>\\ \hline</xsl:text>\r
+       </xsl:if>\r
+       <xsl:text>\end{array}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template name="colalign">\r
+       <xsl:param name="colalign"/>\r
+       <xsl:choose>\r
+               <xsl:when test="contains($colalign,' ')">\r
+                       <xsl:value-of select="substring($colalign,1,1)"/>\r
+                       <xsl:call-template name="colalign">\r
+                               <xsl:with-param name="colalign" select="substring-after($colalign,' ')"/>\r
+                       </xsl:call-template>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:value-of select="substring($colalign,1,1)"/>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template name="generate-string">\r
+<!-- template from XSLT Standard Library v1.1 -->\r
+    <xsl:param name="text"/>\r
+    <xsl:param name="count"/>\r
+\r
+    <xsl:choose>\r
+      <xsl:when test="string-length($text) = 0 or $count &lt;= 0"/>\r
+\r
+      <xsl:otherwise>\r
+       <xsl:value-of select="$text"/>\r
+       <xsl:call-template name="generate-string">\r
+         <xsl:with-param name="text" select="$text"/>\r
+         <xsl:with-param name="count" select="$count - 1"/>\r
+       </xsl:call-template>\r
+      </xsl:otherwise>\r
+    </xsl:choose>\r
+</xsl:template>\r
+\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/inc/xsltml/tokens.xsl b/www/plugins/odt2spip_30/inc/xsltml/tokens.xsl
new file mode 100644 (file)
index 0000000..0d1d750
--- /dev/null
@@ -0,0 +1,296 @@
+<?xml version='1.0' encoding="UTF-8"?>\r
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"\r
+               xmlns:m="http://www.w3.org/1998/Math/MathML"\r
+                version='1.0'>\r
+                \r
+<!-- ====================================================================== -->\r
+<!-- $id: tokens.xsl, 2002/22/11 Exp $\r
+     This file is part of the XSLT MathML Library distribution.\r
+     See ./README or http://www.raleigh.ru/MathML/mmltex for\r
+     copyright and other information                                        -->\r
+<!-- ====================================================================== -->\r
+\r
+<xsl:template match="m:mi|m:mn|m:mo|m:mtext|m:ms">\r
+       <xsl:call-template name="CommonTokenAtr"/>\r
+</xsl:template>\r
+\r
+<xsl:template name="mi">\r
+       <xsl:choose>\r
+               <xsl:when test="string-length(normalize-space(.))>1 and not(@mathvariant)">\r
+                       <xsl:text>\mathrm{</xsl:text>\r
+                               <xsl:apply-templates/>\r
+                       <xsl:text>}</xsl:text>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:apply-templates/>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template name="mn">\r
+       <xsl:apply-templates/>\r
+</xsl:template>\r
+\r
+<xsl:template name="mo">\r
+       <xsl:apply-templates/>\r
+</xsl:template>\r
+\r
+<xsl:template name="mtext">\r
+       <xsl:variable name="content">\r
+               <xsl:call-template name="replaceMtextEntities">\r
+                       <xsl:with-param name="content" select="."/>\r
+               </xsl:call-template>\r
+       </xsl:variable>\r
+       <xsl:text>\text{</xsl:text>\r
+       <xsl:value-of select="$content"/>\r
+       <xsl:text>}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:mspace">\r
+       <xsl:text>\phantom{\rule</xsl:text>\r
+       <xsl:if test="@depth">\r
+               <xsl:text>[-</xsl:text>\r
+               <xsl:value-of select="@depth"/>\r
+               <xsl:text>]</xsl:text>\r
+       </xsl:if>\r
+       <xsl:text>{</xsl:text>\r
+       <xsl:if test="not(@width)">\r
+               <xsl:text>0ex</xsl:text>\r
+       </xsl:if>\r
+       <xsl:value-of select="@width"/>\r
+       <xsl:text>}{</xsl:text>\r
+       <xsl:if test="not(@height)">\r
+               <xsl:text>0ex</xsl:text>\r
+       </xsl:if>\r
+       <xsl:value-of select="@height"/>\r
+       <xsl:text>}}</xsl:text>\r
+</xsl:template>\r
+\r
+<xsl:template name="ms">\r
+       <xsl:choose>\r
+               <xsl:when test="@lquote"><xsl:value-of select="@lquote"/></xsl:when>\r
+               <xsl:otherwise><xsl:text>"</xsl:text></xsl:otherwise>\r
+       </xsl:choose><xsl:apply-templates/><xsl:choose>\r
+               <xsl:when test="@rquote"><xsl:value-of select="@rquote"/></xsl:when>\r
+               <xsl:otherwise><xsl:text>"</xsl:text></xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template name="CommonTokenAtr">\r
+       <xsl:if test="@mathbackground">\r
+               <xsl:text>\colorbox[rgb]{</xsl:text>\r
+               <xsl:call-template name="color">\r
+                       <xsl:with-param name="color" select="@mathbackground"/>\r
+               </xsl:call-template>\r
+               <xsl:text>}{$</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="@color or @mathcolor"> <!-- Note: @color is deprecated in MathML 2.0 -->\r
+               <xsl:text>\textcolor[rgb]{</xsl:text>\r
+               <xsl:call-template name="color">\r
+                       <xsl:with-param name="color" select="@color|@mathcolor"/>\r
+               </xsl:call-template>\r
+               <xsl:text>}{</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="@mathvariant">\r
+               <xsl:choose>\r
+                       <xsl:when test="@mathvariant='normal'">\r
+                               <xsl:text>\mathrm{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='bold'">\r
+                               <xsl:text>\mathbf{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='italic'">\r
+                               <xsl:text>\mathit{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='bold-italic'">    <!-- Required definition -->\r
+                               <xsl:text>\mathbit{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='double-struck'">  <!-- Required amsfonts -->\r
+                               <xsl:text>\mathbb{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='bold-fraktur'">   <!-- Error -->\r
+                               <xsl:text>{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='script'">\r
+                               <xsl:text>\mathcal{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='bold-script'">    <!-- Error -->\r
+                               <xsl:text>\mathsc{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='fraktur'">        <!-- Required amsfonts -->\r
+                               <xsl:text>\mathfrak{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='sans-serif'">\r
+                               <xsl:text>\mathsf{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='bold-sans-serif'"> <!-- Required definition -->\r
+                               <xsl:text>\mathbsf{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='sans-serif-italic'"> <!-- Required definition -->\r
+                               <xsl:text>\mathsfit{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='sans-serif-bold-italic'"> <!-- Error -->\r
+                               <xsl:text>\mathbsfit{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:when test="@mathvariant='monospace'">\r
+                               <xsl:text>\mathtt{</xsl:text>\r
+                       </xsl:when>\r
+                       <xsl:otherwise>\r
+                               <xsl:text>{</xsl:text>\r
+                       </xsl:otherwise>\r
+               </xsl:choose>\r
+       </xsl:if>\r
+       <xsl:call-template name="selectTemplate"/>\r
+       <xsl:if test="@mathvariant">\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="@color or @mathcolor">\r
+               <xsl:text>}</xsl:text>\r
+       </xsl:if>\r
+       <xsl:if test="@mathbackground">\r
+               <xsl:text>$}</xsl:text>\r
+       </xsl:if>\r
+</xsl:template>\r
+\r
+<xsl:template name="selectTemplate">\r
+<!--   <xsl:variable name="name" select="local-name()"/>\r
+       <xsl:call-template name="{$name}"/>-->\r
+       <xsl:choose>\r
+               <xsl:when test="local-name(.)='mi'">\r
+                       <xsl:call-template name="mi"/>\r
+               </xsl:when>\r
+               <xsl:when test="local-name(.)='mn'">\r
+                       <xsl:call-template name="mn"/>\r
+               </xsl:when>\r
+               <xsl:when test="local-name(.)='mo'">\r
+                       <xsl:call-template name="mo"/>\r
+               </xsl:when>\r
+               <xsl:when test="local-name(.)='mtext'">\r
+                       <xsl:call-template name="mtext"/>\r
+               </xsl:when>\r
+               <xsl:when test="local-name(.)='ms'">\r
+                       <xsl:call-template name="ms"/>\r
+               </xsl:when>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template name="color">\r
+<!-- NB: Variables colora and valueColor{n} only for Sablotron -->\r
+       <xsl:param name="color"/>\r
+       <xsl:variable name="colora" select="translate($color,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/>\r
+       <xsl:choose>\r
+       <xsl:when test="starts-with($colora,'#') and string-length($colora)=4">\r
+               <xsl:variable name="valueColor">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,2,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:value-of select="$valueColor div 15"/><xsl:text>,</xsl:text>\r
+               <xsl:variable name="valueColor1">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,3,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:value-of select="$valueColor1 div 15"/><xsl:text>,</xsl:text>\r
+               <xsl:variable name="valueColor2">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,4,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:value-of select="$valueColor2 div 15"/>\r
+       </xsl:when>\r
+       <xsl:when test="starts-with($colora,'#') and string-length($colora)=7">\r
+               <xsl:variable name="valueColor1">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,2,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:variable name="valueColor2">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,3,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:value-of select="($valueColor1*16 + $valueColor2) div 255"/><xsl:text>,</xsl:text>\r
+               <xsl:variable name="valueColor1a">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,4,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:variable name="valueColor2a">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,5,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:value-of select="($valueColor1a*16 + $valueColor2a) div 255"/><xsl:text>,</xsl:text>\r
+               <xsl:variable name="valueColor1b">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,6,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:variable name="valueColor2b">\r
+                       <xsl:call-template name="Hex2Decimal">\r
+                               <xsl:with-param name="arg" select="substring($colora,7,1)"/>\r
+                       </xsl:call-template>\r
+               </xsl:variable>\r
+               <xsl:value-of select="($valueColor1b*16 + $valueColor2b) div 255"/>\r
+       </xsl:when>\r
+<!-- ======================= if color specifed as an html-color-name ========================================== -->\r
+       <xsl:when test="$colora='aqua'"><xsl:text>0,1,1</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='black'"><xsl:text>0,0,0</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='blue'"><xsl:text>0,0,1</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='fuchsia'"><xsl:text>1,0,1</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='gray'"><xsl:text>.5,.5,.5</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='green'"><xsl:text>0,.5,0</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='lime'"><xsl:text>0,1,0</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='maroon'"><xsl:text>.5,0,0</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='navy'"><xsl:text>0,0,.5</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='olive'"><xsl:text>.5,.5,0</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='purple'"><xsl:text>.5,0,.5</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='red'"><xsl:text>1,0,0</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='silver'"><xsl:text>.75,.75,.75</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='teal'"><xsl:text>0,.5,.5</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='white'"><xsl:text>1,1,1</xsl:text></xsl:when>\r
+       <xsl:when test="$colora='yellow'"><xsl:text>1,1,0</xsl:text></xsl:when>\r
+       <xsl:otherwise>\r
+               <xsl:message>Exception at color template</xsl:message>\r
+       </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template name="Hex2Decimal">\r
+       <xsl:param name="arg"/>\r
+       <xsl:choose>\r
+               <xsl:when test="$arg='f'">\r
+                       <xsl:value-of select="15"/>\r
+               </xsl:when>\r
+               <xsl:when test="$arg='e'">\r
+                       <xsl:value-of select="14"/>\r
+               </xsl:when>\r
+               <xsl:when test="$arg='d'">\r
+                       <xsl:value-of select="13"/>\r
+               </xsl:when>\r
+               <xsl:when test="$arg='c'">\r
+                       <xsl:value-of select="12"/>\r
+               </xsl:when>\r
+               <xsl:when test="$arg='b'">\r
+                       <xsl:value-of select="11"/>\r
+               </xsl:when>\r
+               <xsl:when test="$arg='a'">\r
+                       <xsl:value-of select="10"/>\r
+               </xsl:when>\r
+               <xsl:when test="translate($arg, '0123456789', '9999999999')='9'"> <!-- if $arg is number -->\r
+                       <xsl:value-of select="$arg"/>\r
+               </xsl:when>\r
+               <xsl:otherwise>\r
+                       <xsl:message>Exception at Hex2Decimal template</xsl:message>\r
+               </xsl:otherwise>\r
+       </xsl:choose>\r
+</xsl:template>\r
+\r
+<xsl:template match="m:*/text()">\r
+       <xsl:call-template name="replaceEntities">\r
+               <xsl:with-param name="content" select="normalize-space()"/>\r
+       </xsl:call-template>\r
+</xsl:template>\r
+\r
+</xsl:stylesheet>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/lang/odtspip_de.php b/www/plugins/odt2spip_30/lang/odtspip_de.php
new file mode 100644 (file)
index 0000000..f9d69cd
--- /dev/null
@@ -0,0 +1,54 @@
+<?php\r
+/**\r
+ * Fichier de langue : Allemand\r
+ *\r
+ * @author cy_altern\r
+ * @license GNU/LGPL\r
+ *\r
+ * @package plugins\r
+ * @subpackage odt2spip\r
+ * @category import\r
+ *\r
+ * @version $Id: odtspip_de.php 36713 2010-03-28 00:02:06Z gilles.vincent@gmail.com $\r
+ *\r
+ */\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+       // A\r
+       'attacher_fichier_odt' => 'ODT-Datei an Artikel anh&auml;ngen?',\r
+\r
+       // C\r
+       'choix_fichier' => 'Diese ODT-Datei benutzen: ',\r
+               \r
+       // D\r
+       'mode_document' => 'Dokumente',\r
+\r
+       // E\r
+       'err_enregistrement_fichier_sortie' => 'Fehler beim Speichern der Datei mit dem Plugins Snippets',\r
+       'err_extension_xslt'=> 'XSLT f&uuml;r PHP nicht verf&uuml;gbar: Bitten sie ihren Administrator, die XSL Erweiterungen zu installieren.',\r
+       'err_import_snippet' => 'Fehler beim Anlegen des Artikels mit Zusatzdateien. Bitte Installation und Aktivierung von odt2spip pr&uuml;fen.',\r
+       'err_repertoire_tmp' => 'Fehler: tmp/odt2spip Ordner oder zugeh&ouml;riger Unterordner  /id auteur wurde nicht hergestellt',\r
+       'err_telechargement_fichier' => 'Fehler: die Datei konnte nicht wieder hergestellt werden',\r
+       'err_transformation_xslt' => 'Fehler beider der XSLT-Verarbeitung  der ODT-Datei',\r
+       'err_transformation_xslt_mathml' => 'XSLT-Fehler bei der Umwandlung von MathML',\r
+\r
+       // I\r
+       'images_mode_document' => 'Bilder f&uuml;r Artikel speichern als:',\r
+       'mode_image' => 'Bilder',\r
+       'importer_fichier' => 'ODT-Datei in Artikel umwandeln',\r
+               \r
+       // L\r
+       'langue_publication' => 'Sprache des Artikels', \r
+\r
+       // N\r
+       'non' => 'nein',\r
+\r
+       // O\r
+       'oui' => 'ja',\r
+\r
+       // T\r
+       'cet_article_version_odt' => 'OOo-Writer-Version dieses Artikels' \r
+\r
+);\r
+\r
+?>\r
diff --git a/www/plugins/odt2spip_30/lang/odtspip_en.php b/www/plugins/odt2spip_30/lang/odtspip_en.php
new file mode 100644 (file)
index 0000000..3976073
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Fichier de langue : Anglais
+ *
+ * @author cy_altern
+ * @license GNU/LGPL
+ *
+ * @package plugins
+ * @subpackage odt2spip
+ * @category import
+ *
+ * @version $Id: odtspip_en.php 36713 2010-03-28 00:02:06Z gilles.vincent@gmail.com $
+ *
+ */
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+       // A
+       'attacher_fichier_odt' => 'Attach the ODT file to the article ?',
+  
+       // C
+       'choix_fichier' => 'ODT file to use :',
+
+       // E
+       'err_enregistrement_fichier_sortie' => 'Error saving file snippet',
+       'err_extension_xslt'=> 'PHP\'s XSLT functions are not operational in: ask activation XSL extensions to your server administrator',
+       'err_import_snippet' => 'Error when creating the article with the plugin Snippets. Make sure it is properly installed and activated.',
+       'err_repertoire_tmp' => 'Error: tmp/odt2spip folder or its subfolder / id_auteur has not been created',
+       'err_telechargement_fichier' => 'Error: the file could not be recovered',
+       'err_transformation_xslt' => 'Error processing XSLT file ODT',
+
+       // I
+       'importer_fichier' => 'Create an article from an OOo Writer file',
+               
+       // N
+       'non' => 'no',
+               
+       // O
+       'oui' => 'yes',
+       
+       // T
+       'cet_article_version_odt' => 'OOo Writer version of this article' 
+
+);
+
+?>
diff --git a/www/plugins/odt2spip_30/lang/odtspip_fr.php b/www/plugins/odt2spip_30/lang/odtspip_fr.php
new file mode 100644 (file)
index 0000000..8f6decf
--- /dev/null
@@ -0,0 +1,52 @@
+<?php\r
+/**\r
+ * Fichier de langue : Français\r
+ *\r
+ * @author cy_altern\r
+ * @license GNU/LGPL\r
+ *\r
+ * @package plugins\r
+ * @subpackage odt2spip\r
+ * @category import\r
+ *\r
+ *\r
+ */\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+       // A\r
+       'attacher_fichier_odt' => 'Attacher le fichier ODT &agrave; l\'article?',\r
+  \r
+       // C\r
+       'choix_fichier' => 'Fichier ODT &agrave; utiliser : ',\r
+\r
+    // D\r
+    'mode_document' => 'documents',\r
+\r
+    // E\r
+       'err_enregistrement_fichier_sortie' => 'Erreur lors de l\'enregistrement du fichier de snippet ',\r
+       'err_extension_xslt'=> 'Les fonctions XSLT ne sont pas operationnelles : demandez l\'activation des extensions XSL de PHP &agrave votre administrateur de serveur',\r
+       'err_import_snippet' => 'Erreur lors de la cr&eacute;ation de l\'article par le plugin Snippets. V&eacute;rifiez que celui-ci est correctement install&eacute; et activ&eacute;.',\r
+       'err_repertoire_tmp' => 'Erreur: le dossier tmp/odt2spip ou son sous-dossier /id_auteur n\'a pu &ecirc;tre cr&eacute;&eacute;',\r
+       'err_telechargement_fichier' => 'Erreur: le fichier t&eacute;l&eacute;charg&eacute; n\'a pu &ecirc;tre r&eacute;cup&eacute;r&eacute;',\r
+       'err_transformation_xslt' => 'Erreur lors de la transformation XSLT du fichier ODT',\r
+       'err_transformation_xslt_mathml' => 'Erreur XSLT lors de la conversion du MathML',\r
+\r
+    // I\r
+       'images_mode_document' => 'Images attach&eacute;es en mode:',\r
+       'mode_image' => 'images',\r
+       'importer_fichier' => 'Cr&eacute;er un article &agrave; partir d\'un fichier OOo Writer',\r
+        \r
+    // L\r
+    'langue_publication' => 'Langue de l\'article', \r
+\r
+       // N\r
+       'non' => 'non',\r
+               \r
+       // O\r
+       'oui' => 'oui',\r
+       \r
+       // T\r
+       'cet_article_version_odt' => 'Version .odt de cet article' \r
+       \r
+);\r
+?>\r
diff --git a/www/plugins/odt2spip_30/lang/odtspip_it.php b/www/plugins/odt2spip_30/lang/odtspip_it.php
new file mode 100644 (file)
index 0000000..3277e7e
--- /dev/null
@@ -0,0 +1,44 @@
+<?php\r
+/**\r
+ * Fichier de langue : Italien\r
+ *\r
+ * @author cy_altern\r
+ * @license GNU/LGPL\r
+ *\r
+ * @package plugins\r
+ * @subpackage odt2spip\r
+ * @category import\r
+ *\r
+ * @version $Id: odtspip_it.php 36713 2010-03-28 00:02:06Z gilles.vincent@gmail.com $\r
+ *\r
+ */\r
+\r
+       $GLOBALS[$GLOBALS['idx_lang']] = array(\r
+    // A\r
+        'attacher_fichier_odt' => 'Allegare il file ODT all\'articolo?',\r
+  \r
+    // C\r
+                       'choix_fichier' => 'File ODT da utilizzare : ',\r
+\r
+    // E\r
+        'err_enregistrement_fichier_sortie' => 'Errore nella registrazione del file di snippet ',\r
+        'err_extension_xslt'=> 'Le funzioni xslt non sono operative in PHP: chiedere l\'attivazione delle estensioni XSL all\'amministratore del web server',\r
+        'err_import_snippet' => 'Errore  nella creazione dell\'articolo da parte del plugin Snippets. Verificare che esso sia correttamente istallato e attivato.',\r
+        'err_repertoire_tmp' => 'Errore : non &egrave; stato possibile creare la cartella tmp/odt2spip o la sua sottocartella /id_auteur ',\r
+        'err_telechargement_fichier' => 'Errore : non &egrave; stato possibile recuperare il file in upload',\r
+        'err_transformation_xslt' => 'Errore  nella transformazione XSLT del file ODT',\r
+        'err_transformation_xslt_mathml' => 'Errore XSLT nella conversione di MathML',\r
+\r
+    // I\r
+        'importer_fichier' => 'Generare un articolo a partire da un file OOo Writer',\r
+        \r
+    // N\r
+        'non' => 'no',\r
+        \r
+    // O\r
+        'oui' => 's&igrave;',\r
+    \r
+               // T\r
+        'cet_article_version_odt' => 'Versione OOo Writer di questo articolo' \r
+       );\r
+?>\r
diff --git a/www/plugins/odt2spip_30/lang/odtspip_ro.php b/www/plugins/odt2spip_30/lang/odtspip_ro.php
new file mode 100644 (file)
index 0000000..e28c0a7
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Fichier de langue : Roumain
+ *
+ * @author cy_altern
+ * @license GNU/LGPL
+ *
+ * @package plugins
+ * @subpackage odt2spip
+ * @category import
+ *
+ * @version $Id: odtspip_ro.php 36713 2010-03-28 00:02:06Z gilles.vincent@gmail.com $
+ *
+ */
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+       // A
+       'attacher_fichier_odt' => 'Atasezi fisierul ODT la articol?',
+       // C
+       'choix_fichier' => 'Fisierul ODT pentru a fi folosit:',
+
+       // E
+       'err_enregistrement_fichier_sortie' => 'Salvare eroare fragment fisier',
+       'err_extension_xslt'=> 'Functiile Xslt nu sunt operationale in PHP: cereti administratorului de server activarea extensiilor XSL',
+       'err_import_snippet' => 'Eroare la crearea articolului cu plugin Snippets. Asigurativa ca este instalat corespunzator si activat.',
+       'err_repertoire_tmp' => 'Eroare: folderul tmp/odt2spip sau subfolderul lui /id_auteur nu a fost creat',
+       'err_telechargement_fichier' => 'Eroare: fisierul nu a putut fi recuperat',
+       'err_transformation_xslt' => 'Eroare in procesarea fisierului XSLT in ODT',
+
+       // I
+       'importer_fichier' => 'Creare de articol din fisierul Ooo Writer',
+          
+       // N
+       'non' => 'nu',
+          
+       // O
+       'oui' => 'da',
+   
+       // T
+       'cet_article_version_odt' => 'Versiunea Ooo Writer a articolului' 
+);
+?>
diff --git a/www/plugins/odt2spip_30/lang/paquet-odt2spip_en.php b/www/plugins/odt2spip_30/lang/paquet-odt2spip_en.php
new file mode 100644 (file)
index 0000000..aff57bf
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+
+// Ceci est un fichier langue de SPIP -- This is a SPIP language file
+
+///  Fichier produit par PlugOnet\r
+// Module: paquet-odt2spip\r
+// Langue: en\r
+// Date: 02-04-2013 11:45:38\r
+// Items: 2\r
+\r
+if (!defined('_ECRIRE_INC_VERSION')) return;\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+
+// O
+       'odt2spip_description' => 'Spip\'s articles generator from OpenOffice or LibreOffice Writer files (.odt)',
+       'odt2spip_slogan' => 'Spip\'s articles generator from .odt files',
+);
+?>
diff --git a/www/plugins/odt2spip_30/lang/paquet-odt2spip_fr.php b/www/plugins/odt2spip_30/lang/paquet-odt2spip_fr.php
new file mode 100644 (file)
index 0000000..1d2b7fe
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+
+// Ceci est un fichier langue de SPIP -- This is a SPIP language file
+
+///  Fichier produit par PlugOnet\r
+// Module: paquet-odt2spip\r
+// Langue: fr\r
+// Date: 02-04-2013 11:45:38\r
+// Items: 2\r
+\r
+if (!defined('_ECRIRE_INC_VERSION')) return;\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+
+// O
+       'odt2spip_description' => 'générateur d\'articles spip à partir de fichiers OpenOffice ou LibreOffice Writer (.odt)\r
+_ La transformation des fichiers ODT impose que l\'extension XSL de PHP soit active.\r
+_ La conversion des formules mathématiques repose sur la librairie XSLT {{MathML 2.0 to LaTeX}} de Vasil Yaroshevich [->http://www.raleigh.ru/MathML/mmltex/index.php?lang=en]',
+       'odt2spip_slogan' => 'générateur d\'articles spip à partir de fichiers .odt',
+);
+?>\r
diff --git a/www/plugins/odt2spip_30/odt2spip-24.png b/www/plugins/odt2spip_30/odt2spip-24.png
new file mode 100644 (file)
index 0000000..22e36ac
Binary files /dev/null and b/www/plugins/odt2spip_30/odt2spip-24.png differ
diff --git a/www/plugins/odt2spip_30/odt2spip-64.png b/www/plugins/odt2spip_30/odt2spip-64.png
new file mode 100644 (file)
index 0000000..88a6f68
Binary files /dev/null and b/www/plugins/odt2spip_30/odt2spip-64.png differ
diff --git a/www/plugins/odt2spip_30/odt2spip_pipelines.php b/www/plugins/odt2spip_30/odt2spip_pipelines.php
new file mode 100644 (file)
index 0000000..7fb3720
--- /dev/null
@@ -0,0 +1,34 @@
+<?php\r
+/**\r
+ * Créer un article à partir d'un fichier au format odt\r
+ *\r
+ * @author cy_altern\r
+ * @license GNU/LGPL\r
+ *\r
+ * @package plugins\r
+ * @subpackage odt2spip\r
+ * @category import\r
+ *\r
+ *\r
+ */\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+/**\r
+ * Ajout une boite de creation d'un article à partir d'un fichier odt\r
+ * dans la colonne gauche des pages exec=rubrique\r
+ *\r
+ * @internal à l'aide du pipeline {@link affiche_gauche}\r
+ * @param Array $flux Le code de la colonne gauche\r
+ * @return Array Le code modifié\r
+ */\r
+function odt2spip_affiche_gauche($flux){\r
+       if ($flux['args']['exec']=='rubrique'\r
+         AND $id_rubrique = $flux['args']['id_rubrique']\r
+         AND autoriser('publierdans','rubrique',$flux['args']['id_rubrique'])){\r
+               $out = recuperer_fond('formulaires/odt2spip', array('id_rubrique' => $id_rubrique));\r
+               $flux['data'] .= $out;\r
+       }\r
+       return $flux;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/odt2spip_30/paquet.xml b/www/plugins/odt2spip_30/paquet.xml
new file mode 100644 (file)
index 0000000..c63af86
--- /dev/null
@@ -0,0 +1,18 @@
+<paquet
+       prefix="odt2spip"
+       categorie="edition"
+       version="2.0.1"
+       etat="test"
+       compatibilite="[3.0.0;3.0.*]"
+       logo="odt2spip-64.png"
+       documentation="http://contrib.spip.net/3001"
+>      
+       <nom>odt2spip</nom>     <!-- générateur d'articles spip à partir de fichiers odt -->
+       <auteur>cy_altern</auteur>
+       <copyright>2009-2013</copyright>
+       <licence lien="http://www.gnu.org/licenses/lgpl-3.0.html">LGPL 3</licence>
+       <credit lien="http://www.raleigh.ru/MathML/mmltex/index.php?lang=en">XSLT pour la transformation MathML 2.0 to LaTeX :
+       Vasil Yaroshevich, yarosh@raleigh.ru</credit>
+
+       <pipeline nom="affiche_gauche" inclure="odt2spip_pipelines.php" />
+</paquet>
diff --git a/www/plugins/odt2spip_30/svn.revision b/www/plugins/odt2spip_30/svn.revision
new file mode 100644 (file)
index 0000000..61be3e0
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/odt2spip/trunk
+Revision: 72009
+Dernier commit: 2013-04-13 21:00:12 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/odt2spip/trunk</origine>
+<revision>72009</revision>
+<commit>2013-04-13 21:00:12 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/tests/content_math_objet1.xml b/www/plugins/odt2spip_30/tests/content_math_objet1.xml
new file mode 100644 (file)
index 0000000..635fcf8
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE math:math PUBLIC "-//OpenOffice.org//DTD Modified W3C MathML 1.01//EN" "math.dtd"><math:math xmlns:math="http://www.w3.org/1998/Math/MathML"><math:semantics><math:mrow><math:mrow><math:mfrac><math:msqrt><math:mrow><math:mn>2</math:mn><math:mrow><math:mi>x</math:mi><math:mo math:stretchy="false">+</math:mo><math:mn>9</math:mn></math:mrow></math:mrow></math:msqrt><math:mrow><math:mn>4</math:mn><math:mrow><math:mi>y</math:mi><math:mo math:stretchy="false">−</math:mo><math:mn>6</math:mn></math:mrow></math:mrow></math:mfrac></math:mrow><math:mo math:stretchy="false">=</math:mo><math:mrow><math:mfrac><math:mrow><math:mo math:stretchy="false">α</math:mo><math:mn>3</math:mn></math:mrow><math:mrow><math:mo math:stretchy="false">β</math:mo><math:mn>2</math:mn></math:mrow></math:mfrac></math:mrow></math:mrow><math:annotation math:encoding="StarMath 5.0">{{alignc {{sqrt{2 x+9}}}over{4 y-6}}}={{alignc {{%alpha}3}over{{%beta}2}}}</math:annotation></math:semantics></math:math>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/tests/content_math_objet2.xml b/www/plugins/odt2spip_30/tests/content_math_objet2.xml
new file mode 100644 (file)
index 0000000..8bbf09c
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE math:math PUBLIC "-//OpenOffice.org//DTD Modified W3C MathML 1.01//EN" "math.dtd"><math:math xmlns:math="http://www.w3.org/1998/Math/MathML"><math:semantics><math:mrow><math:mn>6</math:mn><math:mrow><math:mi math:fontstyle="italic">CO2</math:mi><math:mo math:stretchy="false">+</math:mo><math:mrow><math:mn>6</math:mn><math:mi math:fontstyle="italic">H2</math:mi><math:mi>O</math:mi><math:mo math:stretchy="false">→</math:mo><math:mi math:fontstyle="italic">C6</math:mi><math:mi math:fontstyle="italic">H12</math:mi><math:mi math:fontstyle="italic">O6</math:mi></math:mrow></math:mrow></math:mrow><math:annotation math:encoding="StarMath 5.0">6 CO2 + {6 H2 O rightarrow C6 H12 O6}</math:annotation></math:semantics></math:math>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/tests/content_math_objet3.xml b/www/plugins/odt2spip_30/tests/content_math_objet3.xml
new file mode 100644 (file)
index 0000000..03d49df
--- /dev/null
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE math:math PUBLIC "-//OpenOffice.org//DTD Modified W3C MathML 1.01//EN" "math.dtd"><math:math xmlns:math="http://www.w3.org/1998/Math/MathML"><math:semantics><math:mrow><math:msqrt><math:mrow><math:mn>5</math:mn><math:mrow><math:mi>y</math:mi><math:mo math:stretchy="false">+</math:mo><math:mn>3</math:mn></math:mrow></math:mrow></math:msqrt><math:mo math:stretchy="false">=</math:mo><math:mrow><math:mfrac><math:mrow><math:mn>9</math:mn><math:mi>x</math:mi></math:mrow><math:mrow><math:mn>3</math:mn><math:mi>z</math:mi></math:mrow></math:mfrac></math:mrow></math:mrow><math:annotation math:encoding="StarMath 5.0">{{sqrt{5 y+3}}}={{alignc {9 x}over{3 z
+}}}</math:annotation></math:semantics></math:math>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/tests/content_test_complet.xml b/www/plugins/odt2spip_30/tests/content_test_complet.xml
new file mode 100644 (file)
index 0000000..d59376b
--- /dev/null
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:rdfa="http://docs.oasis-open.org/opendocument/meta/rdfa#" office:version="1.2"><office:scripts/><office:font-face-decls><style:font-face style:name="OpenSymbol" svg:font-family="OpenSymbol"/><style:font-face style:name="StarSymbol" svg:font-family="StarSymbol"/><style:font-face style:name="Tahoma1" svg:font-family="Tahoma"/><style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="roman" style:font-pitch="variable"/><style:font-face style:name="Comic Sans MS" svg:font-family="&apos;Comic Sans MS&apos;" style:font-family-generic="script" style:font-pitch="variable"/><style:font-face style:name="Arial1" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Arial" svg:font-family="Arial" style:font-adornments="Gras" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Arial Black" svg:font-family="&apos;Arial Black&apos;" style:font-adornments="Normal" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Lucida Sans Unicode" svg:font-family="&apos;Lucida Sans Unicode&apos;" style:font-family-generic="system" style:font-pitch="variable"/><style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" style:font-pitch="variable"/></office:font-face-decls><office:automatic-styles><style:style style:name="Tableau1" style:family="table"><style:table-properties style:width="16.999cm" table:align="margins"/></style:style><style:style style:name="Tableau1.A" style:family="table-column"><style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/></style:style><style:style style:name="Tableau1.A1" style:family="table-cell"><style:table-cell-properties fo:background-color="#000080" fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"><style:background-image/></style:table-cell-properties></style:style><style:style style:name="Tableau1.C1" style:family="table-cell"><style:table-cell-properties fo:background-color="#000080" fo:padding="0.097cm" fo:border="0.002cm solid #000000"><style:background-image/></style:table-cell-properties></style:style><style:style style:name="Tableau1.A2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau1.C2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau2" style:family="table"><style:table-properties style:width="16.999cm" table:align="margins"/></style:style><style:style style:name="Tableau2.A" style:family="table-column"><style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/></style:style><style:style style:name="Tableau2.A1" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/></style:style><style:style style:name="Tableau2.A2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau2.C2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau3" style:family="table"><style:table-properties style:width="16.999cm" table:align="margins"/></style:style><style:style style:name="Tableau3.A" style:family="table-column"><style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/></style:style><style:style style:name="Tableau3.A1" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau3.C1" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/></style:style><style:style style:name="Tableau3.A2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau3.C2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau4" style:family="table"><style:table-properties style:width="16.999cm" table:align="margins"/></style:style><style:style style:name="Tableau4.A" style:family="table-column"><style:table-column-properties style:column-width="4.249cm" style:rel-column-width="16383*"/></style:style><style:style style:name="Tableau4.D" style:family="table-column"><style:table-column-properties style:column-width="4.251cm" style:rel-column-width="16386*"/></style:style><style:style style:name="Tableau4.A1" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau4.C1" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/></style:style><style:style style:name="Tableau4.C2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="Tableau4.D2" style:family="table-cell"><style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/></style:style><style:style style:name="P1" style:family="paragraph" style:parent-style-name="Header"><style:paragraph-properties fo:text-align="end" style:justify-single-word="false"><style:tab-stops><style:tab-stop style:position="16.999cm" style:type="right"/></style:tab-stops></style:paragraph-properties></style:style><style:style style:name="P2" style:family="paragraph" style:parent-style-name="Footer"><style:paragraph-properties fo:text-align="end" style:justify-single-word="false"/></style:style><style:style style:name="P3" style:family="paragraph" style:parent-style-name="Table_20_Contents"><style:paragraph-properties fo:text-align="end" style:justify-single-word="false"/></style:style><style:style style:name="P4" style:family="paragraph" style:parent-style-name="Table_20_Contents"><style:paragraph-properties fo:text-align="start" style:justify-single-word="false"/><style:text-properties fo:color="#ffffff" style:text-outline="false" style:text-line-through-style="none" style:font-name="Times New Roman" fo:font-size="12pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:font-size-asian="12pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-size-complex="12pt" style:font-style-complex="normal" style:font-weight-complex="normal"/></style:style><style:style style:name="P5" style:family="paragraph" style:parent-style-name="Contents_20_1"><style:paragraph-properties><style:tab-stops><style:tab-stop style:position="16.999cm" style:type="right" style:leader-style="dotted" style:leader-text="."/></style:tab-stops></style:paragraph-properties></style:style><style:style style:name="P6" style:family="paragraph" style:parent-style-name="Contents_20_3"><style:paragraph-properties><style:tab-stops><style:tab-stop style:position="16cm" style:type="right" style:leader-style="dotted" style:leader-text="."/></style:tab-stops></style:paragraph-properties></style:style><style:style style:name="P7" style:family="paragraph" style:parent-style-name="Contents_20_2"><style:paragraph-properties><style:tab-stops><style:tab-stop style:position="16.499cm" style:type="right" style:leader-style="dotted" style:leader-text="."/></style:tab-stops></style:paragraph-properties></style:style><style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard"><style:paragraph-properties fo:background-color="#33cc66"><style:background-image/></style:paragraph-properties></style:style><style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L1"/><style:style style:name="P10" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L2"/><style:style style:name="P11" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L3"/><style:style style:name="P12" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L4"/><style:style style:name="P13" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties style:text-position="super 58%"/></style:style><style:style style:name="P14" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties style:text-position="0% 100%"/></style:style><style:style style:name="P15" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties style:text-position="0% 100%" fo:font-style="italic" fo:font-weight="normal" style:font-style-asian="italic" style:font-weight-asian="normal" style:font-style-complex="italic" style:font-weight-complex="normal"/></style:style><style:style style:name="P16" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties style:text-position="0% 100%" fo:font-style="normal" fo:font-weight="normal" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-style-complex="normal" style:font-weight-complex="normal"/></style:style><style:style style:name="P17" style:family="paragraph" style:parent-style-name="Standard"><style:text-properties style:text-position="0% 100%" fo:font-style="normal" style:font-style-asian="normal" style:font-style-complex="normal"/></style:style><style:style style:name="P18" style:family="paragraph" style:parent-style-name="Heading_20_2"><style:paragraph-properties fo:break-before="page"/></style:style><style:style style:name="P19" style:family="paragraph"><style:paragraph-properties fo:text-align="center"/></style:style><style:style style:name="T1" style:family="text"><style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/></style:style><style:style style:name="T2" style:family="text"><style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"/></style:style><style:style style:name="T3" style:family="text"><style:text-properties fo:color="#ff0000"/></style:style><style:style style:name="T4" style:family="text"><style:text-properties style:font-name="Arial1"/></style:style><style:style style:name="T5" style:family="text"><style:text-properties style:font-name="Comic Sans MS"/></style:style><style:style style:name="T6" style:family="text"><style:text-properties fo:font-size="14pt" style:font-size-asian="14pt" style:font-size-complex="14pt"/></style:style><style:style style:name="T7" style:family="text"><style:text-properties fo:font-size="16pt" style:font-size-asian="16pt" style:font-size-complex="16pt"/></style:style><style:style style:name="T8" style:family="text"><style:text-properties fo:font-size="18pt" style:font-size-asian="18pt" style:font-size-complex="18pt"/></style:style><style:style style:name="T9" style:family="text"><style:text-properties style:text-underline-style="solid" style:text-underline-width="auto" style:text-underline-color="font-color"/></style:style><style:style style:name="T10" style:family="text"><style:text-properties style:text-line-through-style="solid"/></style:style><style:style style:name="T11" style:family="text"><style:text-properties style:text-position="0% 100%"/></style:style><style:style style:name="T12" style:family="text"><style:text-properties style:text-position="0% 100%" fo:font-style="normal" style:font-style-asian="normal" style:font-style-complex="normal"/></style:style><style:style style:name="T13" style:family="text"><style:text-properties fo:font-weight="normal" style:font-weight-asian="normal" style:font-weight-complex="normal"/></style:style><style:style style:name="T14" style:family="text"><style:text-properties fo:font-style="normal"/></style:style><style:style style:name="T15" style:family="text"><style:text-properties style:font-style-asian="normal"/></style:style><style:style style:name="T16" style:family="text"><style:text-properties style:font-style-complex="normal"/></style:style><style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics"><style:graphic-properties style:run-through="foreground" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/></style:style><style:style style:name="fr2" style:family="graphic" style:parent-style-name="Graphics"><style:graphic-properties style:run-through="foreground" style:wrap="dynamic" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/></style:style><style:style style:name="fr3" style:family="graphic" style:parent-style-name="Graphics"><style:graphic-properties style:vertical-pos="top" style:vertical-rel="paragraph" style:horizontal-pos="center" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/></style:style><style:style style:name="fr4" style:family="graphic" style:parent-style-name="Formula"><style:graphic-properties fo:margin-left="0cm" fo:margin-right="0cm" style:vertical-pos="middle" style:vertical-rel="text" style:horizontal-pos="from-left" style:horizontal-rel="paragraph-content" draw:ole-draw-aspect="1"/></style:style><style:style style:name="Sect1" style:family="section"><style:section-properties style:editable="false"><style:columns fo:column-count="1" fo:column-gap="0cm"/></style:section-properties></style:style><text:list-style style:name="L1"><text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.27cm" fo:text-indent="-0.635cm" fo:margin-left="1.27cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.905cm" fo:text-indent="-0.635cm" fo:margin-left="1.905cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.54cm" fo:text-indent="-0.635cm" fo:margin-left="2.54cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.175cm" fo:text-indent="-0.635cm" fo:margin-left="3.175cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.81cm" fo:text-indent="-0.635cm" fo:margin-left="3.81cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.445cm" fo:text-indent="-0.635cm" fo:margin-left="4.445cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.08cm" fo:text-indent="-0.635cm" fo:margin-left="5.08cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.715cm" fo:text-indent="-0.635cm" fo:margin-left="5.715cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.35cm" fo:text-indent="-0.635cm" fo:margin-left="6.35cm"/></style:list-level-properties></text:list-level-style-number><text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.985cm" fo:text-indent="-0.635cm" fo:margin-left="6.985cm"/></style:list-level-properties></text:list-level-style-number></text:list-style><text:list-style style:name="L2"><text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.27cm" fo:text-indent="-0.635cm" fo:margin-left="1.27cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.905cm" fo:text-indent="-0.635cm" fo:margin-left="1.905cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.54cm" fo:text-indent="-0.635cm" fo:margin-left="2.54cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.175cm" fo:text-indent="-0.635cm" fo:margin-left="3.175cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.81cm" fo:text-indent="-0.635cm" fo:margin-left="3.81cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.445cm" fo:text-indent="-0.635cm" fo:margin-left="4.445cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.08cm" fo:text-indent="-0.635cm" fo:margin-left="5.08cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="◦"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.715cm" fo:text-indent="-0.635cm" fo:margin-left="5.715cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="▪"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.35cm" fo:text-indent="-0.635cm" fo:margin-left="6.35cm"/></style:list-level-properties></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="•"><style:list-level-properties text:list-level-position-and-space-mode="label-alignment"><style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.985cm" fo:text-indent="-0.635cm" fo:margin-left="6.985cm"/></style:list-level-properties></text:list-level-style-bullet></text:list-style><text:list-style style:name="L3"><text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="0.635cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="1.27cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="1.905cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="2.54cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="3.175cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="3.81cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="4.445cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="5.08cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="5.715cm" text:min-label-width="0.635cm"/></text:list-level-style-number><text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"><style:list-level-properties text:space-before="6.35cm" text:min-label-width="0.635cm"/></text:list-level-style-number></text:list-style><text:list-style style:name="L4"><text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="●"><style:list-level-properties text:space-before="0.635cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="○"><style:list-level-properties text:space-before="1.27cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="■"><style:list-level-properties text:space-before="1.905cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="●"><style:list-level-properties text:space-before="2.54cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="○"><style:list-level-properties text:space-before="3.175cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="■"><style:list-level-properties text:space-before="3.81cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="●"><style:list-level-properties text:space-before="4.445cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="○"><style:list-level-properties text:space-before="5.08cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="■"><style:list-level-properties text:space-before="5.715cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet><text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char="●"><style:list-level-properties text:space-before="6.35cm" text:min-label-width="0.635cm"/><style:text-properties style:font-name="StarSymbol"/></text:list-level-style-bullet></text:list-style><style:style style:name="gr1" style:family="graphic"><style:graphic-properties draw:stroke="solid" draw:stroke-dash="Ultrafine_20_Dashed" svg:stroke-width="0cm" svg:stroke-color="#ff0000" draw:marker-end="Extrémité_20_de_20_ligne_20_1" draw:textarea-horizontal-align="center" draw:textarea-vertical-align="middle" fo:padding-top="0.002cm" fo:padding-bottom="0.002cm" fo:padding-left="0.002cm" fo:padding-right="0.002cm" style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" draw:wrap-influence-on-position="once-concurrent" style:flow-with-text="false"/></style:style></office:automatic-styles><office:body><office:text text:use-soft-page-breaks="true"><office:forms form:automatic-focus="false" form:apply-design-mode="false"/><text:sequence-decls><text:sequence-decl text:display-outline-level="0" text:name="Illustration"/><text:sequence-decl text:display-outline-level="0" text:name="Table"/><text:sequence-decl text:display-outline-level="0" text:name="Text"/><text:sequence-decl text:display-outline-level="0" text:name="Drawing"/></text:sequence-decls><text:h text:style-name="Heading_20_1" text:outline-level="1">Titre du document (niveau 1)</text:h><text:h text:style-name="Heading_20_2" text:outline-level="2">Insertion d&apos;images dans le texte (titre niveau 2)</text:h><text:p text:style-name="Standard"><draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="paragraph" svg:x="9.888cm" svg:y="0.101cm" svg:width="6.8cm" svg:height="3.133cm" draw:z-index="0"><draw:image xlink:href="Pictures/100000000000032300000172DDDFE9EE.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame><draw:line text:anchor-type="paragraph" draw:z-index="3" draw:style-name="gr1" draw:text-style-name="P19" svg:x1="8.604cm" svg:y1="3.085cm" svg:x2="10.483cm" svg:y2="1.603cm"><text:p/></draw:line>texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte </text:p><text:p text:style-name="Standard">Ici une flêche pour légender un élément de l&apos;image mais pour l&apos;instant ça n&apos;est pas géré...</text:p><text:p text:style-name="Standard"><draw:frame draw:style-name="fr2" draw:name="images1" text:anchor-type="paragraph" svg:x="-1.33cm" svg:y="0.161cm" svg:width="6.147cm" svg:height="2.404cm" draw:z-index="1"><draw:image xlink:href="Pictures/100000000000016B0000008E692AFB42.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame>texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte</text:p><text:p text:style-name="Standard"/><text:p text:style-name="Standard"/><text:p text:style-name="Standard"/><text:p text:style-name="Standard"><draw:frame draw:style-name="fr3" draw:name="Image3" text:anchor-type="paragraph" svg:width="16.147cm" svg:height="9.019cm" draw:z-index="2"><draw:image xlink:href="Pictures/1000000000000320000001FC9D74D342.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame></text:p><text:h text:style-name="Heading_20_3" text:outline-level="3">Formules de math:</text:h><text:p text:style-name="Standard"><text:span text:style-name="T11">une formule de maths:</text:span></text:p><text:p text:style-name="P13"><draw:frame draw:style-name="fr4" draw:name="Objet2" text:anchor-type="as-char" svg:width="2.775cm" svg:height="1.046cm" draw:z-index="4"><draw:object xlink:href="./Object 1" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/><draw:image xlink:href="./ObjectReplacements/Object 1" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame></text:p><text:p text:style-name="P14"/><text:p text:style-name="P14">une formule de chimie:</text:p><text:p text:style-name="P15"><draw:frame draw:style-name="fr4" draw:name="Objet5" text:anchor-type="as-char" svg:width="5.669cm" svg:height="0.473cm" draw:z-index="5"><draw:object xlink:href="./Object 2" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/><draw:image xlink:href="./ObjectReplacements/Object 2" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame></text:p><text:p text:style-name="P16"/><text:p text:style-name="P17">une autre formule de maths:</text:p><text:p text:style-name="Standard"><text:span text:style-name="T12"><draw:frame draw:style-name="fr4" draw:name="Objet4" text:anchor-type="as-char" svg:width="2.701cm" svg:height="1.009cm" draw:z-index="6"><draw:object xlink:href="./Object 3" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/><draw:image xlink:href="./ObjectReplacements/Object 3" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame></text:span></text:p><text:h text:style-name="P18" text:outline-level="2">Les tableaux (Titre niveau 2)</text:h><text:h text:style-name="Heading_20_3" text:outline-level="3">Tableaux simples (titre 3)</text:h><table:table table:name="Tableau1" table:style-name="Tableau1"><table:table-column table:style-name="Tableau1.A" table:number-columns-repeated="3"/><table:table-row><table:table-cell table:style-name="Tableau1.A1" office:value-type="string"><text:p text:style-name="P4">Tableau avec </text:p></table:table-cell><table:table-cell table:style-name="Tableau1.A1" office:value-type="string"><text:p text:style-name="P4">format automatique</text:p></table:table-cell><table:table-cell table:style-name="Tableau1.C1" office:value-type="string"><text:p text:style-name="P4">« Standard »</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau1.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 4</text:p></table:table-cell><table:table-cell table:style-name="Tableau1.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 5</text:p></table:table-cell><table:table-cell table:style-name="Tableau1.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 6</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau1.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 7</text:p></table:table-cell><table:table-cell table:style-name="Tableau1.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 8</text:p></table:table-cell><table:table-cell table:style-name="Tableau1.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 9</text:p></table:table-cell></table:table-row></table:table><text:p text:style-name="Standard"/><text:p text:style-name="Standard"/><table:table table:name="Tableau2" table:style-name="Tableau2"><table:table-column table:style-name="Tableau2.A" table:number-columns-repeated="3"/><table:table-row><table:table-cell table:style-name="Tableau2.A1" table:number-columns-spanned="3" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule avec 3 colonnes fusionnées </text:p></table:table-cell><table:covered-table-cell/><table:covered-table-cell/></table:table-row><table:table-row><table:table-cell table:style-name="Tableau2.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 4</text:p></table:table-cell><table:table-cell table:style-name="Tableau2.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 5</text:p></table:table-cell><table:table-cell table:style-name="Tableau2.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 6</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau2.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 7</text:p></table:table-cell><table:table-cell table:style-name="Tableau2.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 8</text:p></table:table-cell><table:table-cell table:style-name="Tableau2.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 9</text:p></table:table-cell></table:table-row></table:table><text:p text:style-name="Standard"/><text:p text:style-name="Standard"/><table:table table:name="Tableau3" table:style-name="Tableau3"><table:table-column table:style-name="Tableau3.A" table:number-columns-repeated="3"/><table:table-row><table:table-cell table:style-name="Tableau3.A1" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 1</text:p></table:table-cell><table:table-cell table:style-name="Tableau3.A1" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 2</text:p></table:table-cell><table:table-cell table:style-name="Tableau3.C1" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule 3</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau3.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule A</text:p></table:table-cell><table:table-cell table:style-name="Tableau3.A2" table:number-rows-spanned="2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule avec 2 lignes fusionnées</text:p></table:table-cell><table:table-cell table:style-name="Tableau3.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule C</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau3.A2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule D</text:p></table:table-cell><table:covered-table-cell/><table:table-cell table:style-name="Tableau3.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">cellule F</text:p></table:table-cell></table:table-row></table:table><text:h text:style-name="Heading_20_3" text:outline-level="3">Tableau complexe:(titre 3)</text:h><table:table table:name="Tableau4" table:style-name="Tableau4"><table:table-column table:style-name="Tableau4.A" table:number-columns-repeated="3"/><table:table-column table:style-name="Tableau4.D"/><table:table-row><table:table-cell table:style-name="Tableau4.A1" table:number-rows-spanned="2" office:value-type="string"><text:p text:style-name="Table_20_Heading">From</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.A1" table:number-rows-spanned="2" office:value-type="string"><text:p text:style-name="Table_20_Heading">To</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.C1" table:number-columns-spanned="2" office:value-type="string"><text:p text:style-name="Table_20_Heading">Special Fares</text:p></table:table-cell><table:covered-table-cell/></table:table-row><table:table-row><table:covered-table-cell/><table:covered-table-cell/><table:table-cell table:style-name="Tableau4.C2" office:value-type="string"><text:p text:style-name="Table_20_Heading">One-way</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.D2" office:value-type="string"><text:p text:style-name="Table_20_Heading">Round Trip</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau4.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">San Jose</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">Peoria</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.C2" office:value-type="string"><text:p text:style-name="P3">$150.00</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.D2" office:value-type="string"><text:p text:style-name="P3">$295.00</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau4.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">Chicago Midway</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.C2" table:number-rows-spanned="2" office:value-type="string"><text:p text:style-name="Table_20_Contents">Los Angeles</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.C2" table:number-rows-spanned="2" office:value-type="string"><text:p text:style-name="P3">$200.00</text:p></table:table-cell><table:table-cell table:style-name="Tableau4.D2" table:number-rows-spanned="2" office:value-type="string"><text:p text:style-name="P3">$350.00</text:p></table:table-cell></table:table-row><table:table-row><table:table-cell table:style-name="Tableau4.C2" office:value-type="string"><text:p text:style-name="Table_20_Contents">Chicago O&apos;Hare</text:p></table:table-cell><table:covered-table-cell/><table:covered-table-cell/><table:covered-table-cell/></table:table-row></table:table><text:p text:style-name="Standard"/><text:h text:style-name="Heading_20_2" text:outline-level="2">Divers trucs (Titre 2)</text:h><text:p text:style-name="Standard">un lien sur <text:a xlink:type="simple" xlink:href="http://spip-contrib.net/">http://spip-contrib.net</text:a> </text:p><text:p text:style-name="Standard">et ici un <text:a xlink:type="simple" xlink:href="#ancre">lien vers l&apos;ancre</text:a> ci-dessous</text:p><text:p text:style-name="Standard">Une première note de bas de page<text:note text:id="ftn1" text:note-class="footnote"><text:note-citation>1</text:note-citation><text:note-body><text:p text:style-name="Footnote">le texte de la note de bas de page</text:p></text:note-body></text:note> texte texte </text:p><text:p text:style-name="Standard">texte <text:span text:style-name="T1">du gras</text:span> texte texte </text:p><text:p text:style-name="Standard">texte <text:span text:style-name="T2">de l&apos;italique</text:span> texte <text:s/>texte texte <text:s/>texte<text:note text:id="ftn2" text:note-class="footnote"><text:note-citation>2</text:note-citation><text:note-body><text:p text:style-name="Footnote">le texte de la 2eme note</text:p></text:note-body></text:note> texte texte texte texte texte texte texte texte texte </text:p><text:p text:style-name="Standard">3 paragraphes vides</text:p><text:p text:style-name="Standard"/><text:p text:style-name="Standard"/><text:p text:style-name="Standard"/><text:p text:style-name="Standard">3 retours à la ligne<text:line-break/><text:line-break/><text:line-break/><text:line-break/><text:bookmark text:name="ancre"/>Ici une ancre dans le texte (= repère de texte)</text:p><text:p text:style-name="Standard">Et un saut de page</text:p><text:h text:style-name="P18" text:outline-level="2">Les listes</text:h><text:h text:style-name="Heading_20_3" text:outline-level="3">listes simples</text:h><text:p text:style-name="Standard">une liste ordonnée simple:</text:p><text:list xml:id="list24299239" text:style-name="L1"><text:list-item><text:p text:style-name="P9">item 1</text:p></text:list-item><text:list-item><text:p text:style-name="P9">item 2 </text:p></text:list-item><text:list-item><text:p text:style-name="P9">item 3</text:p></text:list-item></text:list><text:p text:style-name="Standard"/><text:p text:style-name="Standard">une liste à puce simple:</text:p><text:list xml:id="list24322367" text:style-name="L2"><text:list-item><text:p text:style-name="P10">item 1</text:p></text:list-item><text:list-item><text:p text:style-name="P10">item 2 </text:p></text:list-item><text:list-item><text:p text:style-name="P10">item 3</text:p></text:list-item></text:list><text:p text:style-name="Standard"/><text:h text:style-name="Heading_20_3" text:outline-level="3">listes complexes</text:h><text:p text:style-name="Standard">Une liste ordonnée imbriquée:</text:p><text:list xml:id="list24323865" text:style-name="L3"><text:list-item><text:p text:style-name="P11">item 1</text:p><text:list><text:list-item><text:p text:style-name="P11">item 1.1</text:p></text:list-item><text:list-item><text:p text:style-name="P11">item 1.2</text:p></text:list-item></text:list></text:list-item><text:list-item><text:p text:style-name="P11">item 2</text:p></text:list-item><text:list-item><text:p text:style-name="P11">item 3</text:p></text:list-item></text:list><text:p text:style-name="Standard"/><text:p text:style-name="Standard">Une liste à puces imbriquée:</text:p><text:list xml:id="list24296668" text:style-name="L4"><text:list-item><text:p text:style-name="P12">item 1</text:p><text:list><text:list-item><text:p text:style-name="P12">item 1.1</text:p><text:list><text:list-item><text:p text:style-name="P12">item 1.1.1</text:p></text:list-item><text:list-item><text:p text:style-name="P12">item 1.1.2</text:p></text:list-item></text:list></text:list-item><text:list-item><text:p text:style-name="P12">item 1.2</text:p></text:list-item><text:list-item><text:p text:style-name="P12">item 1.3</text:p></text:list-item></text:list></text:list-item><text:list-item><text:p text:style-name="P12">item 2</text:p><text:list><text:list-item><text:p text:style-name="P12">item 2.1</text:p></text:list-item><text:list-item><text:p text:style-name="P12">item 2.2</text:p></text:list-item></text:list></text:list-item><text:list-item><text:p text:style-name="P12">item 3</text:p></text:list-item></text:list><text:p text:style-name="Standard"/><text:p text:style-name="Standard">encore un saut de page</text:p><text:h text:style-name="P18" text:outline-level="2">Eléments non gérés</text:h><text:h text:style-name="Heading_20_3" text:outline-level="3">Elements ignorés:</text:h><text:p text:style-name="Standard">Tous les éléments suivant ne sont pas gérés par le plugin puisque le code SPIP ne permet pas de le générer: ils restent sous la forme de texte « standard ».</text:p><text:p text:style-name="P8">Du texte <text:span text:style-name="T3">en couleur</text:span> ou sur fond coloré.</text:p><text:p text:style-name="Standard">Des variations de police: ici <text:span text:style-name="T4">de l&apos;arial</text:span> et là <text:span text:style-name="T5">du comic</text:span> </text:p><text:p text:style-name="Standard">Des <text:span text:style-name="T6">variation</text:span> de <text:span text:style-name="T7">taille</text:span> de <text:span text:style-name="T8">caractères</text:span> </text:p><text:p text:style-name="Standard">Du texte <text:span text:style-name="T9">souligné</text:span> ou <text:span text:style-name="T10">barré</text:span> </text:p><text:h text:style-name="Heading_20_3" text:outline-level="3">Les niveaux de titres supplémentaires:</text:h><text:p text:style-name="Standard">Tous les titres de niveau inférieur au titres de niveau 2 sont formatés à l&apos;identique: en italique</text:p><text:h text:style-name="Heading_20_4" text:outline-level="4">Titre niveau 4</text:h><text:h text:style-name="Heading_20_5" text:outline-level="5">Titre niveau 5</text:h><text:h text:style-name="Heading_20_3" text:outline-level="3">Eléments supprimés: </text:h><text:p text:style-name="Standard">Les en-têtes et pieds de page ne seront pas repris dans la version SPIP</text:p><text:p text:style-name="Standard"/><text:p text:style-name="Standard">Une table des matières automatique ne sera <text:span text:style-name="T1">pas</text:span> reproduite dans la version SPIP (idem pour un <text:s/>index automatique) </text:p><text:table-of-content text:style-name="Sect1" text:protected="true" text:name="Table des matières1"><text:table-of-content-source text:outline-level="10"><text:index-title-template text:style-name="Contents_20_Heading">Table des matières générée automatiquement</text:index-title-template><text:table-of-content-entry-template text:outline-level="1" text:style-name="Contents_20_1"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="2" text:style-name="Contents_20_2"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="3" text:style-name="Contents_20_3"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="4" text:style-name="Contents_20_4"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="5" text:style-name="Contents_20_5"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="6" text:style-name="Contents_20_6"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="7" text:style-name="Contents_20_7"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="8" text:style-name="Contents_20_8"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="9" text:style-name="Contents_20_9"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template><text:table-of-content-entry-template text:outline-level="10" text:style-name="Contents_20_10"><text:index-entry-chapter/><text:index-entry-text/><text:index-entry-tab-stop style:type="right" style:leader-char="."/><text:index-entry-page-number/></text:table-of-content-entry-template></text:table-of-content-source><text:index-body><text:index-title text:style-name="Sect1" text:name="Table des matières1_Head"><text:p text:style-name="Contents_20_Heading">Table des matières générée automatiquement</text:p></text:index-title><text:p text:style-name="P5">Titre du document (niveau 1)<text:tab/>1</text:p><text:p text:style-name="P7">Insertion d&apos;images dans le texte (titre niveau 2)<text:tab/>1</text:p><text:p text:style-name="P7">Les tableaux (Titre niveau 2)<text:tab/>1</text:p><text:p text:style-name="P6">Tableaux simples (titre 3)<text:tab/>1</text:p><text:p text:style-name="P6">Tableau complexe:<text:tab/>2</text:p><text:p text:style-name="P7">Divers trucs (Titre 2)<text:tab/>2</text:p><text:p text:style-name="P7">Les listes<text:tab/>3</text:p><text:p text:style-name="P6">listes simples<text:tab/>3</text:p><text:p text:style-name="P6">listes complexes<text:tab/>3</text:p></text:index-body></text:table-of-content><text:p text:style-name="Standard"/></office:text></office:body></office:document-content>
\ No newline at end of file
diff --git a/www/plugins/odt2spip_30/tests/content_test_complet_indente.xml b/www/plugins/odt2spip_30/tests/content_test_complet_indente.xml
new file mode 100644 (file)
index 0000000..7be28d0
--- /dev/null
@@ -0,0 +1,874 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<office:document-content \r
+  xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" \r
+  xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" \r
+  xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" \r
+  xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" \r
+  xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" \r
+  xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" \r
+  xmlns:xlink="http://www.w3.org/1999/xlink" \r
+  xmlns:dc="http://purl.org/dc/elements/1.1/" \r
+  xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" \r
+  xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" \r
+  xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" \r
+  xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" \r
+  xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" \r
+  xmlns:math="http://www.w3.org/1998/Math/MathML" \r
+  xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" \r
+  xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" \r
+  xmlns:ooo="http://openoffice.org/2004/office" \r
+  xmlns:ooow="http://openoffice.org/2004/writer" \r
+  xmlns:oooc="http://openoffice.org/2004/calc" \r
+  xmlns:dom="http://www.w3.org/2001/xml-events" \r
+  xmlns:xforms="http://www.w3.org/2002/xforms" \r
+  xmlns:xsd="http://www.w3.org/2001/XMLSchema" \r
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" \r
+  xmlns:rpt="http://openoffice.org/2005/report" \r
+  xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" \r
+  xmlns:rdfa="http://docs.oasis-open.org/opendocument/meta/rdfa#" \r
+  office:version="1.2">\r
+  <office:scripts/>\r
+  <office:font-face-decls>\r
+    <style:font-face style:name="OpenSymbol" svg:font-family="OpenSymbol"/>\r
+    <style:font-face style:name="StarSymbol" svg:font-family="StarSymbol"/>\r
+    <style:font-face style:name="Tahoma1" svg:font-family="Tahoma"/>\r
+    <style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="roman" style:font-pitch="variable"/>\r
+    <style:font-face style:name="Arial" svg:font-family="Arial" style:font-adornments="Gras" style:font-family-generic="swiss" style:font-pitch="variable"/>\r
+    <style:font-face style:name="Arial Black" svg:font-family="&apos;Arial Black&apos;" style:font-adornments="Normal" style:font-family-generic="swiss" style:font-pitch="variable"/>\r
+    <style:font-face style:name="Lucida Sans Unicode" svg:font-family="&apos;Lucida Sans Unicode&apos;" style:font-family-generic="system" style:font-pitch="variable"/>\r
+    <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" style:font-pitch="variable"/>\r
+  </office:font-face-decls>\r
+  <office:automatic-styles>\r
+    <style:style style:name="Tableau1" style:family="table">\r
+      <style:table-properties style:width="16.999cm" table:align="margins"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau1.A" style:family="table-column">\r
+      <style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau1.A1" style:family="table-cell">\r
+      <style:table-cell-properties fo:background-color="#000080" fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000">\r
+        <style:background-image/>\r
+      </style:table-cell-properties>\r
+    </style:style>\r
+    <style:style style:name="Tableau1.C1" style:family="table-cell">\r
+      <style:table-cell-properties fo:background-color="#000080" fo:padding="0.097cm" fo:border="0.002cm solid #000000">\r
+        <style:background-image/>\r
+      </style:table-cell-properties>\r
+    </style:style>\r
+    <style:style style:name="Tableau1.A2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau1.C2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau2" style:family="table">\r
+      <style:table-properties style:width="16.999cm" table:align="margins"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau2.A" style:family="table-column">\r
+      <style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau2.A1" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau2.A2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau2.C2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau3" style:family="table">\r
+      <style:table-properties style:width="16.999cm" table:align="margins"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau3.A" style:family="table-column">\r
+      <style:table-column-properties style:column-width="5.666cm" style:rel-column-width="21845*"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau3.A1" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau3.C1" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau3.A2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau3.C2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau4" style:family="table">\r
+      <style:table-properties style:width="16.999cm" table:align="margins"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau4.A" style:family="table-column">\r
+      <style:table-column-properties style:column-width="4.249cm" style:rel-column-width="16383*"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau4.D" style:family="table-column">\r
+      <style:table-column-properties style:column-width="4.251cm" style:rel-column-width="16386*"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau4.A1" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="0.002cm solid #000000" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau4.C1" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau4.C2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="none" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="Tableau4.D2" style:family="table-cell">\r
+      <style:table-cell-properties fo:padding="0.097cm" fo:border-left="0.002cm solid #000000" fo:border-right="0.002cm solid #000000" fo:border-top="none" fo:border-bottom="0.002cm solid #000000"/>\r
+    </style:style>\r
+    <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Header">\r
+      <style:paragraph-properties fo:text-align="end" style:justify-single-word="false">\r
+        <style:tab-stops>\r
+          <style:tab-stop style:position="16.999cm" style:type="right"/>\r
+        </style:tab-stops>\r
+      </style:paragraph-properties>\r
+    </style:style>\r
+    <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Footer">\r
+      <style:paragraph-properties fo:text-align="end" style:justify-single-word="false"/>\r
+    </style:style>\r
+    <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Table_20_Contents">\r
+      <style:paragraph-properties fo:text-align="end" style:justify-single-word="false"/>\r
+    </style:style>\r
+    <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Table_20_Contents">\r
+      <style:paragraph-properties fo:text-align="start" style:justify-single-word="false"/>\r
+      <style:text-properties fo:color="#ffffff" style:text-outline="false" style:text-line-through-style="none" style:font-name="Times New Roman" fo:font-size="12pt" fo:font-style="normal" fo:text-shadow="none" style:text-underline-style="none" fo:font-weight="normal" style:font-size-asian="12pt" style:font-style-asian="normal" style:font-weight-asian="normal" style:font-size-complex="12pt" style:font-style-complex="normal" style:font-weight-complex="normal"/>\r
+    </style:style>\r
+    <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Contents_20_1">\r
+      <style:paragraph-properties>\r
+        <style:tab-stops>\r
+          <style:tab-stop style:position="16.999cm" style:type="right" style:leader-style="dotted" style:leader-text="."/>\r
+        </style:tab-stops>\r
+      </style:paragraph-properties>\r
+    </style:style>\r
+    <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Contents_20_3">\r
+      <style:paragraph-properties>\r
+        <style:tab-stops>\r
+          <style:tab-stop style:position="16cm" style:type="right" style:leader-style="dotted" style:leader-text="."/>\r
+        </style:tab-stops>\r
+      </style:paragraph-properties>\r
+    </style:style>\r
+    <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Contents_20_2">\r
+      <style:paragraph-properties>\r
+        <style:tab-stops>\r
+          <style:tab-stop style:position="16.499cm" style:type="right" style:leader-style="dotted" style:leader-text="."/>\r
+        </style:tab-stops>\r
+      </style:paragraph-properties>\r
+    </style:style>\r
+    <style:style style:name="P8" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L1"/>\r
+    <style:style style:name="P9" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L2"/>\r
+    <style:style style:name="P10" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L3"/>\r
+    <style:style style:name="P11" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L4"/>\r
+    <style:style style:name="P12" style:family="paragraph" style:parent-style-name="Heading_20_2">\r
+      <style:paragraph-properties fo:break-before="page"/>\r
+    </style:style>\r
+    <style:style style:name="P13" style:family="paragraph">\r
+      <style:paragraph-properties fo:text-align="center"/>\r
+    </style:style>\r
+    <style:style style:name="T1" style:family="text">\r
+      <style:text-properties fo:font-weight="bold" style:font-weight-asian="bold" style:font-weight-complex="bold"/>\r
+    </style:style>\r
+    <style:style style:name="T2" style:family="text">\r
+      <style:text-properties fo:font-style="italic" style:font-style-asian="italic" style:font-style-complex="italic"/>\r
+    </style:style>\r
+    <style:style style:name="fr1" style:family="graphic" style:parent-style-name="Graphics">\r
+      <style:graphic-properties style:run-through="foreground" style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/>\r
+    </style:style>\r
+    <style:style style:name="fr2" style:family="graphic" style:parent-style-name="Graphics">\r
+      <style:graphic-properties style:run-through="foreground" style:wrap="dynamic" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/>\r
+    </style:style>\r
+    <style:style style:name="fr3" style:family="graphic" style:parent-style-name="Graphics">\r
+      <style:graphic-properties style:vertical-pos="top" style:vertical-rel="paragraph" style:mirror="none" fo:clip="rect(0cm, 0cm, 0cm, 0cm)" draw:luminance="0%" draw:contrast="0%" draw:red="0%" draw:green="0%" draw:blue="0%" draw:gamma="100%" draw:color-inversion="false" draw:image-opacity="100%" draw:color-mode="standard"/>\r
+    </style:style>\r
+    <style:style style:name="fr4" style:family="graphic" style:parent-style-name="Formula">\r
+      <style:graphic-properties fo:margin-left="0cm" fo:margin-right="0cm" style:vertical-pos="middle" style:vertical-rel="text" draw:ole-draw-aspect="1"/>\r
+    </style:style>\r
+    <style:style style:name="Sect1" style:family="section">\r
+      <style:section-properties style:editable="false">\r
+        <style:columns fo:column-count="1" fo:column-gap="0cm"/>\r
+      </style:section-properties>\r
+    </style:style>\r
+    <text:list-style style:name="L1">\r
+      <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+        <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+          <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.27cm" fo:text-indent="-0.635cm" fo:margin-left="1.27cm"/>\r
+        </style:list-level-properties>\r
+      </text:list-level-style-number>\r
+      <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+        <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+          <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.905cm" fo:text-indent="-0.635cm" fo:margin-left="1.905cm"/>\r
+        </style:list-level-properties>\r
+      </text:list-level-style-number>\r
+      <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+        <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+          <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.54cm" fo:text-indent="-0.635cm" fo:margin-left="2.54cm"/>\r
+        </style:list-level-properties>\r
+      </text:list-level-style-number>\r
+      <text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+        <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.175cm" fo:text-indent="-0.635cm" fo:margin-left="3.175cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.81cm" fo:text-indent="-0.635cm" fo:margin-left="3.81cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.445cm" fo:text-indent="-0.635cm" fo:margin-left="4.445cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.08cm" fo:text-indent="-0.635cm" fo:margin-left="5.08cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.715cm" fo:text-indent="-0.635cm" fo:margin-left="5.715cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.35cm" fo:text-indent="-0.635cm" fo:margin-left="6.35cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.985cm" fo:text-indent="-0.635cm" fo:margin-left="6.985cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-number>\r
+  </text:list-style>\r
+  <text:list-style style:name="L2">\r
+    <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \80¢">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.27cm" fo:text-indent="-0.635cm" fo:margin-left="1.27cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97¦">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.905cm" fo:text-indent="-0.635cm" fo:margin-left="1.905cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \96ª">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="2.54cm" fo:text-indent="-0.635cm" fo:margin-left="2.54cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \80¢">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.175cm" fo:text-indent="-0.635cm" fo:margin-left="3.175cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97¦">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="3.81cm" fo:text-indent="-0.635cm" fo:margin-left="3.81cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \96ª">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="4.445cm" fo:text-indent="-0.635cm" fo:margin-left="4.445cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \80¢">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.08cm" fo:text-indent="-0.635cm" fo:margin-left="5.08cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97¦">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="5.715cm" fo:text-indent="-0.635cm" fo:margin-left="5.715cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \96ª">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.35cm" fo:text-indent="-0.635cm" fo:margin-left="6.35cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \80¢">\r
+      <style:list-level-properties text:list-level-position-and-space-mode="label-alignment">\r
+        <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="6.985cm" fo:text-indent="-0.635cm" fo:margin-left="6.985cm"/>\r
+      </style:list-level-properties>\r
+    </text:list-level-style-bullet>\r
+  </text:list-style>\r
+  <text:list-style style:name="L3">\r
+    <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="0.635cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="2" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="1.27cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="3" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="1.905cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="4" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="2.54cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="5" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="3.175cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="6" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="3.81cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="7" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="4.445cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="8" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="5.08cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="9" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="5.715cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+    <text:list-level-style-number text:level="10" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1">\r
+      <style:list-level-properties text:space-before="6.35cm" text:min-label-width="0.635cm"/>\r
+    </text:list-level-style-number>\r
+  </text:list-style>\r
+  <text:list-style style:name="L4">\r
+    <text:list-level-style-bullet text:level="1" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97\8f">\r
+      <style:list-level-properties text:space-before="0.635cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="2" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97\8b">\r
+      <style:list-level-properties text:space-before="1.27cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="3" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \96 ">\r
+      <style:list-level-properties text:space-before="1.905cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="4" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97\8f">\r
+      <style:list-level-properties text:space-before="2.54cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="5" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97\8b">\r
+      <style:list-level-properties text:space-before="3.175cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="6" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \96 ">\r
+      <style:list-level-properties text:space-before="3.81cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="7" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97\8f">\r
+      <style:list-level-properties text:space-before="4.445cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="8" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97\8b">\r
+      <style:list-level-properties text:space-before="5.08cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="9" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \96 ">\r
+      <style:list-level-properties text:space-before="5.715cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+    <text:list-level-style-bullet text:level="10" text:style-name="Bullet_20_Symbols" style:num-suffix="." text:bullet-char=" \97\8f">\r
+      <style:list-level-properties text:space-before="6.35cm" text:min-label-width="0.635cm"/>\r
+      <style:text-properties style:font-name="StarSymbol"/>\r
+    </text:list-level-style-bullet>\r
+  </text:list-style>\r
+  <style:style style:name="gr1" style:family="graphic">\r
+    <style:graphic-properties draw:stroke="solid" draw:stroke-dash="Ultrafine_20_Dashed" svg:stroke-width="0cm" svg:stroke-color="#ff0000" draw:marker-end="Extr ©mit ©_20_de_20_ligne_20_1" draw:textarea-horizontal-align="center" draw:textarea-vertical-align="middle" fo:padding-top="0.002cm" fo:padding-bottom="0.002cm" fo:padding-left="0.002cm" fo:padding-right="0.002cm" style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph"/></style:style>\r
+  </office:automatic-styles>\r
+  <office:body>\r
+    <office:text text:use-soft-page-breaks="true">\r
+      <office:forms form:automatic-focus="false" form:apply-design-mode="false"/>\r
+      <text:sequence-decls>\r
+        <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>\r
+        <text:sequence-decl text:display-outline-level="0" text:name="Table"/>\r
+        <text:sequence-decl text:display-outline-level="0" text:name="Text"/>\r
+        <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>\r
+      </text:sequence-decls>\r
+      <text:h text:style-name="Heading_20_1" text:outline-level="1">Titre du document (niveau 1)</text:h>\r
+      <text:h text:style-name="Heading_20_2" text:outline-level="2">Insertion d&apos;images dans le texte (titre niveau 2)</text:h>\r
+      <text:p text:style-name="Standard">\r
+        <draw:frame draw:style-name="fr1" draw:name="Image1" text:anchor-type="paragraph" svg:x="9.888cm" svg:y="0.101cm" svg:width="6.8cm" svg:height="3.133cm" draw:z-index="0">\r
+          <draw:image xlink:href="Pictures/100000000000032300000172DDDFE9EE.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+        </draw:frame>\r
+        <draw:line text:anchor-type="paragraph" draw:z-index="4" draw:style-name="gr1" draw:text-style-name="P13" svg:x1="8.604cm" svg:y1="3.085cm" svg:x2="10.483cm" svg:y2="1.603cm">\r
+          <text:p/>\r
+        </draw:line>\r
+        texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte \r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        Ici une fl ªche pour l ©gender un  ©l ©ment de l&apos;image mais pour l&apos;instant  §a n&apos;est pas g ©r ©...\r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        <text:bookmark text:name="une ancre"/>\r
+        texte texte texte textetexte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte\r
+      </text:p>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard">\r
+        <draw:frame draw:style-name="fr2" draw:name="images1" text:anchor-type="paragraph" svg:x="-1.33cm" svg:y="0.161cm" svg:width="6.147cm" svg:height="2.404cm" draw:z-index="1">\r
+          <draw:image xlink:href="Pictures/100000000000016B0000008E692AFB42.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+        </draw:frame>\r
+        texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte texte\r
+      </text:p>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard">\r
+        <draw:frame draw:style-name="fr3" draw:name="Image3" text:anchor-type="paragraph" svg:width="16.999cm" svg:height="10.793cm" draw:z-index="2">\r
+          <draw:image xlink:href="Pictures/1000000000000320000001FC9D74D342.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+        </draw:frame>\r
+      </text:p>\r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">Formules de math:</text:h>\r
+      <text:p text:style-name="Standard">\r
+        <text:span text:style-name="T11">une formule de maths:</text:span>\r
+      </text:p>\r
+      <text:p text:style-name="P13">\r
+        <draw:frame draw:style-name="fr4" draw:name="Objet2" text:anchor-type="as-char" svg:width="2.775cm" svg:height="1.046cm" draw:z-index="4">\r
+          <draw:object xlink:href="./Object 1" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+          <draw:image xlink:href="./ObjectReplacements/Object 1" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+        </draw:frame>\r
+      </text:p>\r
+      <text:p text:style-name="P14"/>\r
+      <text:p text:style-name="P14">une formule de chimie:</text:p>\r
+      <text:p text:style-name="P15">\r
+        <draw:frame draw:style-name="fr4" draw:name="Objet5" text:anchor-type="as-char" svg:width="5.669cm" svg:height="0.473cm" draw:z-index="5">\r
+          <draw:object xlink:href="./Object 2" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+          <draw:image xlink:href="./ObjectReplacements/Object 2" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+        </draw:frame>\r
+      </text:p>\r
+      <text:p text:style-name="P16"/>\r
+      <text:p text:style-name="P17">une autre formule de maths:</text:p>\r
+      <text:p text:style-name="Standard">\r
+        <text:span text:style-name="T12">\r
+          <draw:frame draw:style-name="fr4" draw:name="Objet4" text:anchor-type="as-char" svg:width="2.701cm" svg:height="1.009cm" draw:z-index="6">\r
+            <draw:object xlink:href="./Object 3" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+            <draw:image xlink:href="./ObjectReplacements/Object 3" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+          </draw:frame>\r
+        </text:span>\r
+      </text:p>\r
+      <text:h text:style-name="P12" text:outline-level="2">Les tableaux (Titre niveau 2)</text:h>\r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">Tableaux simples (titre 3)</text:h>\r
+      <table:table table:name="Tableau1" table:style-name="Tableau1">\r
+        <table:table-column table:style-name="Tableau1.A" table:number-columns-repeated="3"/>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau1.A1" office:value-type="string">\r
+            <text:p text:style-name="P4">Tableau avec </text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau1.A1" office:value-type="string">\r
+            <text:p text:style-name="P4">format automatique</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau1.C1" office:value-type="string">\r
+            <text:p text:style-name="P4">    Standard    </text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau1.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 4</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau1.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 5</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau1.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 6</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau1.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 7</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau1.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 8</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau1.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 9</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+      </table:table>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard"/>\r
+      <table:table table:name="Tableau2" table:style-name="Tableau2">\r
+        <table:table-column table:style-name="Tableau2.A" table:number-columns-repeated="3"/>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau2.A1" table:number-columns-spanned="3" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule avec 3 colonnes fusionn ©es </text:p>\r
+          </table:table-cell>\r
+          <table:covered-table-cell/>\r
+          <table:covered-table-cell/>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau2.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 4</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau2.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 5</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau2.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 6</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau2.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 7</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau2.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 8</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau2.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 9</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+      </table:table>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard"/>\r
+      <table:table table:name="Tableau3" table:style-name="Tableau3">\r
+        <table:table-column table:style-name="Tableau3.A" table:number-columns-repeated="3"/>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau3.A1" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 1</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau3.A1" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 2</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau3.C1" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule 3</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau3.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule A</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau3.A2" table:number-rows-spanned="2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule avec 2 lignes fusionn ©es</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau3.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule C</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau3.A2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule D</text:p>\r
+          </table:table-cell>\r
+          <table:covered-table-cell/>\r
+          <table:table-cell table:style-name="Tableau3.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">cellule F</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+      </table:table>\r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">Tableau complexe:(titre 3)</text:h>\r
+      <table:table table:name="Tableau4" table:style-name="Tableau4">\r
+        <table:table-column table:style-name="Tableau4.A" table:number-columns-repeated="3"/>\r
+        <table:table-column table:style-name="Tableau4.D"/>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau4.A1" table:number-rows-spanned="2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Heading">From</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.A1" table:number-rows-spanned="2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Heading">To</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.C1" table:number-columns-spanned="2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Heading">Special Fares</text:p>\r
+          </table:table-cell>\r
+          <table:covered-table-cell/>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:covered-table-cell/>\r
+          <table:covered-table-cell/>\r
+          <table:table-cell table:style-name="Tableau4.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Heading">One-way</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.D2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Heading">Round Trip</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau4.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">San Jose</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">Peoria</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.C2" office:value-type="string">\r
+            <text:p text:style-name="P3">$150.00</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.D2" office:value-type="string">\r
+            <text:p text:style-name="P3">$295.00</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau4.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">Chicago Midway</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.C2" table:number-rows-spanned="2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">Los Angeles</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.C2" table:number-rows-spanned="2" office:value-type="string">\r
+            <text:p text:style-name="P3">$200.00</text:p>\r
+          </table:table-cell>\r
+          <table:table-cell table:style-name="Tableau4.D2" table:number-rows-spanned="2" office:value-type="string">\r
+            <text:p text:style-name="P3">$350.00</text:p>\r
+          </table:table-cell>\r
+        </table:table-row>\r
+        <table:table-row>\r
+          <table:table-cell table:style-name="Tableau4.C2" office:value-type="string">\r
+            <text:p text:style-name="Table_20_Contents">Chicago O&apos;Hare</text:p>\r
+          </table:table-cell>\r
+          <table:covered-table-cell/>\r
+          <table:covered-table-cell/>\r
+          <table:covered-table-cell/>\r
+        </table:table-row>\r
+      </table:table>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:h text:style-name="Heading_20_2" text:outline-level="2">Divers trucs (Titre 2)</text:h>\r
+      <text:p text:style-name="Standard">\r
+        un lien sur \r
+        <text:a xlink:type="simple" xlink:href="http://spip-contrib.net/">http://spip-contrib.net</text:a> \r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        et ici un \r
+        <text:a xlink:type="simple" xlink:href="#ancre">lien vers l&apos;ancre</text:a> \r
+        ci-dessous\r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        Une premi ¨re note de bas de page\r
+        <text:note text:id="ftn1" text:note-class="footnote">\r
+          <text:note-citation>1</text:note-citation>\r
+          <text:note-body>\r
+            <text:p text:style-name="Footnote">le texte de la note de bas de page</text:p>\r
+          </text:note-body>\r
+        </text:note> \r
+        texte texte \r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        texte <text:span text:style-name="T1">du gras</text:span> texte texte \r
+      </text:p>\r
+      <text:p text:style-name="Standard">texte <text:span text:style-name="T2">de l&apos;italique</text:span> texte <text:s/>texte texte <text:s/>texte\r
+        <text:note text:id="ftn2" text:note-class="footnote">\r
+          <text:note-citation>2</text:note-citation>\r
+          <text:note-body>\r
+            <text:p text:style-name="Footnote">le texte de la 2eme note</text:p>\r
+          </text:note-body>\r
+        </text:note> \r
+        texte texte texte texte texte texte texte texte texte \r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        3 paragraphes vides\r
+      </text:p>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard">\r
+        3 retours    la ligne\r
+        <text:line-break/>\r
+        <text:line-break/>\r
+        <text:line-break/>\r
+        <text:line-break/>\r
+        <text:bookmark text:name="ancre"/>Ici une ancre dans le texte (= rep ¨re de texte)\r
+      </text:p>\r
+      <text:p text:style-name="Standard">Et un saut de page</text:p>\r
+      <text:h text:style-name="P12" text:outline-level="2">Les listes</text:h>\r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">listes simples</text:h>\r
+      <text:p text:style-name="Standard">une liste ordonn ©e simple:</text:p>\r
+      <text:list xml:id="list21238630" text:style-name="L1">\r
+        <text:list-item>\r
+          <text:p text:style-name="P8">item 1</text:p>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P8">item 2 </text:p>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P8">item 3</text:p>\r
+        </text:list-item>\r
+      </text:list>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard">une liste    puce simple:</text:p>\r
+      <text:list xml:id="list21234022" text:style-name="L2">\r
+        <text:list-item>\r
+          <text:p text:style-name="P9">item 1</text:p>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P9">item 2 </text:p>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P9">item 3</text:p>\r
+        </text:list-item>\r
+      </text:list>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">listes complexes</text:h>\r
+      <text:p text:style-name="Standard">Une liste ordonn ©e imbriqu ©e:</text:p>\r
+      <text:list xml:id="list21237977" text:style-name="L3">\r
+        <text:list-item>\r
+          <text:p text:style-name="P10">item 1</text:p>\r
+          <text:list>\r
+            <text:list-item>\r
+              <text:p text:style-name="P10">item 1.1</text:p>\r
+            </text:list-item>\r
+            <text:list-item>\r
+              <text:p text:style-name="P10">item 1.2</text:p>\r
+            </text:list-item>\r
+          </text:list>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P10">item 2</text:p>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P10">item 3</text:p>\r
+        </text:list-item>\r
+      </text:list>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard">Une liste    puces imbriqu ©e:</text:p>\r
+      <text:list xml:id="list21239331" text:style-name="L4">\r
+        <text:list-item>\r
+          <text:p text:style-name="P11">item 1</text:p>\r
+          <text:list>\r
+            <text:list-item>\r
+              <text:p text:style-name="P11">item 1.1</text:p>\r
+              <text:list>\r
+                <text:list-item>\r
+                  <text:p text:style-name="P11">item 1.1.1</text:p>\r
+                </text:list-item>\r
+                <text:list-item>\r
+                  <text:p text:style-name="P11">item 1.1.2</text:p>\r
+                </text:list-item>\r
+              </text:list>\r
+            </text:list-item>\r
+            <text:list-item>\r
+              <text:p text:style-name="P11">item 1.2</text:p>\r
+            </text:list-item>\r
+            <text:list-item>\r
+              <text:p text:style-name="P11">item 1.3</text:p>\r
+            </text:list-item>\r
+          </text:list>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P11">item 2</text:p>\r
+          <text:list>\r
+            <text:list-item>\r
+              <text:p text:style-name="P11">item 2.1</text:p>\r
+            </text:list-item>\r
+            <text:list-item>\r
+              <text:p text:style-name="P11">item 2.2</text:p>\r
+            </text:list-item>\r
+          </text:list>\r
+        </text:list-item>\r
+        <text:list-item>\r
+          <text:p text:style-name="P11">item 3</text:p>\r
+        </text:list-item>\r
+      </text:list>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard">encore un saut de page</text:p>\r
+      <text:h text:style-name="P13" text:outline-level="2">El ©ments non g ©r ©s</text:h>\r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">Elements ignor ©s:</text:h>\r
+      <text:p text:style-name="Standard">\r
+        Tous les  ©l ©ments suivant ne sont pas g ©r ©s par le plugin puisque le code SPIP ne permet pas de le g ©n ©rer: ils restent sous la forme de texte     standard    .\r
+      </text:p>\r
+      <text:p text:style-name="P12">\r
+        Du texte <text:span text:style-name="T3">en couleur</text:span> ou sur fond color ©.\r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        Des variations de police: ici <text:span text:style-name="T4">de l&apos;arial</text:span> et l   <text:span text:style-name="T5">du comic</text:span> \r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        Des <text:span text:style-name="T6">variation</text:span> de <text:span text:style-name="T7">taille</text:span> de <text:span text:style-name="T8">caract ¨res</text:span> \r
+      </text:p>\r
+      <text:p text:style-name="Standard">\r
+        Du texte <text:span text:style-name="T9">soulign ©</text:span> ou <text:span text:style-name="T10">barr ©</text:span> \r
+      </text:p>\r
+         <text:h text:style-name="Heading_20_3" text:outline-level="3">\r
+               <text:span text:style-name="T11">Les images pas JPG / GIF / PNG : </text:span>\r
+         </text:h>\r
+         <text:p text:style-name="P21">\r
+               <text:span text:style-name="T11">par exemple une image copiée / collée directement depuis un éditeur d&apos;image</text:span>\r
+         </text:p>\r
+         <text:p text:style-name="P20">\r
+               <draw:frame draw:style-name="fr3" draw:name="images2" text:anchor-type="paragraph" svg:width="15.178cm" svg:height="11.384cm" draw:z-index="7">\r
+                       <draw:image xlink:href="Pictures/2000000900003B4A00002C78E023E93C.svm" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>\r
+               </draw:frame>\r
+         </text:p>      \r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">Les niveaux de titres suppl ©mentaires:</text:h>\r
+      <text:p text:style-name="Standard">\r
+        Tous les titres de niveau inf ©rieur au titres de niveau 2 sont format ©s    l&apos;identique: en italique\r
+      </text:p>\r
+      <text:h text:style-name="Heading_20_4" text:outline-level="4">Titre niveau 4</text:h>\r
+      <text:h text:style-name="Heading_20_5" text:outline-level="5">Titre niveau 5</text:h>\r
+      <text:h text:style-name="Heading_20_3" text:outline-level="3">El ©ments supprim ©s: </text:h>\r
+      <text:p text:style-name="Standard">\r
+        Les en-t ªtes et pieds de page ne seront pas repris dans la version SPIP\r
+      </text:p>\r
+      <text:p text:style-name="Standard"/>\r
+      <text:p text:style-name="Standard">\r
+        Une table des mati ¨res automatique ne sera <text:span text:style-name="T1">pas</text:span> reproduite dans la version SPIP (idem pour un <text:s/>index automatique) \r
+      </text:p>\r
+      <text:table-of-content text:style-name="Sect1" text:protected="true" text:name="Table des mati ¨res1">\r
+        <text:table-of-content-source text:outline-level="10">\r
+          <text:index-title-template text:style-name="Contents_20_Heading">Table des mati ¨res g ©n ©r ©e automatiquement</text:index-title-template>\r
+          <text:table-of-content-entry-template text:outline-level="1" text:style-name="Contents_20_1">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="2" text:style-name="Contents_20_2">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="3" text:style-name="Contents_20_3">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="4" text:style-name="Contents_20_4">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="5" text:style-name="Contents_20_5">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="6" text:style-name="Contents_20_6">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="7" text:style-name="Contents_20_7">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="8" text:style-name="Contents_20_8">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="9" text:style-name="Contents_20_9">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+          <text:table-of-content-entry-template text:outline-level="10" text:style-name="Contents_20_10">\r
+            <text:index-entry-chapter/>\r
+            <text:index-entry-text/>\r
+            <text:index-entry-tab-stop style:type="right" style:leader-char="."/>\r
+            <text:index-entry-page-number/>\r
+          </text:table-of-content-entry-template>\r
+        </text:table-of-content-source>\r
+        <text:index-body>\r
+          <text:index-title text:style-name="Sect1" text:name="Table des mati ¨res1_Head">\r
+            <text:p text:style-name="Contents_20_Heading">Table des mati ¨res g ©n ©r ©e automatiquement</text:p>\r
+          </text:index-title>\r
+          <text:p text:style-name="P5">Titre du document (niveau 1)<text:tab/>1</text:p>\r
+          <text:p text:style-name="P7">Insertion d&apos;images dans le texte (titre niveau 2)<text:tab/>1</text:p>\r
+          <text:p text:style-name="P7">Les tableaux (Titre niveau 2)<text:tab/>1</text:p>\r
+          <text:p text:style-name="P6">Tableaux simples (titre 3)<text:tab/>1</text:p>\r
+          <text:p text:style-name="P6">Tableau complexe:<text:tab/>2</text:p>\r
+          <text:p text:style-name="P7">Divers trucs (Titre 2)<text:tab/>2</text:p>\r
+          <text:p text:style-name="P7">Les listes<text:tab/>3</text:p>\r
+          <text:p text:style-name="P6">listes simples<text:tab/>3</text:p>\r
+          <text:p text:style-name="P6">listes complexes<text:tab/>3</text:p>\r
+        </text:index-body>\r
+      </text:table-of-content>\r
+      <text:p text:style-name="Standard"/>\r
+    </office:text>\r
+  </office:body>\r
+</office:document-content>\r
diff --git a/www/plugins/odt2spip_30/tests/test_complet.odt b/www/plugins/odt2spip_30/tests/test_complet.odt
new file mode 100644 (file)
index 0000000..17e3ded
Binary files /dev/null and b/www/plugins/odt2spip_30/tests/test_complet.odt differ
diff --git a/www/plugins/rss_article_3_0/base/rssarticle.php b/www/plugins/rss_article_3_0/base/rssarticle.php
new file mode 100644 (file)
index 0000000..c74ba2b
--- /dev/null
@@ -0,0 +1,57 @@
+<?php
+
+/**
+ * Ajouter la table spip_articles_syndic
+ * @param array $tables_auxiliaires
+ * @return array
+ */
+function rssarticle_declarer_tables_auxiliaires($tables_auxiliaires){
+
+       $spip_rssarticle = array(
+                       "id_article"  => "bigint(21) NOT NULL",
+                       "id_syndic"     => "bigint(21) NOT NULL");
+         
+       $spip_rssarticle_key = array(
+                       "INDEX"         => "id_article");
+       
+       $tables_auxiliaires['spip_articles_syndic'] = array(
+                       'field' => &$spip_rssarticle,
+                       'key' => &$spip_rssarticle_key);
+               
+       return $tables_auxiliaires;
+}
+
+/**
+ * Declarer la table spip_articles_syndic dans les jointures
+ * @param array $interface
+ * @return array
+ */
+function rssarticle_declarer_tables_interfaces($interface){
+       
+       $interface['table_des_tables']['articles_syndic']='articles_syndic';
+       
+       // permet au compilateur de determiner explicitement les jointures possibles
+       // lorsqu\92une boucle sur une table demande un champ inconnu
+       $interface['tables_jointures']['spip_articles'][] = 'articles_syndic';
+
+       return $interface;
+}
+
+
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Ajouter des champs a la table syndic
+ * @param array $tables_principales
+ * @return array
+ */
+function rssarticle_declarer_tables_principales($tables_principales){
+       // Extension de la table syndic
+       $tables_principales['spip_syndic']['field']['rssarticle'] = "varchar(3) DEFAULT 'non' NOT NULL"; 
+               
+       return $tables_principales;
+}
+
+
+?>
diff --git a/www/plugins/rss_article_3_0/exec/rss_article.php b/www/plugins/rss_article_3_0/exec/rss_article.php
new file mode 100644 (file)
index 0000000..12d5536
--- /dev/null
@@ -0,0 +1,47 @@
+<?php\r
+/*    plugin rss en article\r
+*\r
+*     page cachée pour les gens préssés ne pouvant pas attendre le genie\r
+*     permet de relancer manuellement la recopie  du flux en article\r
+*/\r
+\r
+\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+include_spip("inc/presentation");\r
+\r
+function exec_rss_article_dist()\r
+{\r
+  // si pas autorise : message d'erreur  ... admin ... a affiner\r
+  if (!autoriser('editer', 'article')) {\r
+        include_spip('inc/minipres');\r
+        echo minipres();\r
+        exit;\r
+  }\r
+  \r
+  include_spip("genie/rssarticle_copie");\r
+    \r
+       //\r
+       // affichages\r
+       // \r
+\r
+       $commencer_page = charger_fonction('commencer_page', 'inc');\r
+       echo $commencer_page(_T('rssarticle:activer_recopie_intro'), 'editer', 'editer');\r
+  // titre\r
+  echo "<br /><br /><br />\n"; // outch ! aie aie aie ! au secours !\r
+  echo gros_titre(_T('rssarticle:activer_recopie_intro'),'', false);\r
+\r
+       // colonne gauche\r
+       echo debut_gauche('', true);\r
+  echo debut_droite('', true);\r
+       \r
+       // centre de la page    \r
+       genie_rssarticle_copie_dist("manuel");\r
+  echo '<div><small>'.date('Y/m/d H:i:s').'</small><br />'._T('rssarticle:maj_manuelle').'</div>';\r
+  echo '<div style="margin:2em 0;"><a href="?exec=rss_article" style="border:1px solid;padding:0.5em;background:#fff;">'._T('rssarticle:maj_recharge').'</a></div>';\r
+  \r
+\r
+       // pied\r
+       echo fin_gauche() . fin_page();\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/rss_article_3_0/formulaires/configurer_rssarticle.html b/www/plugins/rss_article_3_0/formulaires/configurer_rssarticle.html
new file mode 100644 (file)
index 0000000..238861f
--- /dev/null
@@ -0,0 +1,68 @@
+<div class="ajax formulaire_spip formulaire_configurer formulaire_#FORM formulaire_#FORM-#ENV{id,nouveau}">\r
+       <h3 class="titrem"><:rssarticle:activer_recopie_intro:></h3>\r
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]\r
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV**{message_erreur})</p>]\r
+       [(#ENV{editable})\r
+       <form method='post' action='#ENV{action}'><div>\r
+               [(#REM) declarer les hidden qui declencheront le service du formulaire\r
+               parametre : url d'action ]\r
+               #ACTION_FORMULAIRE{#ENV{action}}\r
+\r
+               <ul>\r
+            <li class="editer">\r
+              <h3 class="legend"><:rssarticle:statut_article_importe:></h3>\r
+                        <ul>\r
+                            <select name="import_statut">\r
+                                <option value="prop"[(#ENV{import_statut}|=={prop}|?{' selected="selected"'})]><:sites:info_statut_site_3:></option>\r
+                                <option value="publie"[(#ENV{import_statut}|=={publie}|?{' selected="selected"'})]><:sites:info_statut_site_2:></option>\r
+                            </select>\r
+                        </ul>\r
+                \r
+            </li>\r
+            <li class="editer">\r
+                    <h3 class="legend"><:rssarticle:mode:></h3>\r
+                        <ul>\r
+                            <div class="choix">\r
+                                <input class="radio" type="radio" name="mode" value="auto" [(#ENV{mode}|=={auto}?{checked='checked',''})] id="mode_auto"/>\r
+                                <label for="mode_auto"><:rssarticle:mode_auto:></label>\r
+                            </div>\r
+                            <div class="choix">\r
+                                <input type="radio" name="mode" value="manuel" [(#ENV{mode}|=={manuel}?{checked='checked',''})] id="mode_manuel"/>\r
+                                <label for="mode_manuel"><:rssarticle:mode_manuel:></label>\r
+                            </div>\r
+                        </ul>                \r
+            </li>\r
+            <li class="editer">\r
+                    <h3 class="legend"><:rssarticle:cron_interval:></h3>\r
+                    <input type="text" name="cron_interval_value" value="[(#ENV{cron_interval_value}|!={''}|?{#ENV{cron_interval_value},600})]" size="6" class="fondl" id="cron_interval_value"/>\r
+                    <label for="cron_interval_value"><:rssarticle:cron_interval_timer:></label>\r
+                \r
+            </li>\r
+            <li class="editer">\r
+                    <h3 class="legend"><:rssarticle:suivi_syndic:></h3>\r
+                    <ul>\r
+                        <li class="editer_email_alerte">\r
+                            <input type="checkbox" name="email_alerte"[ checked="(#ENV{email_alerte}|!={''}|?{'checked'})"] class="fondl" id="email_alerte"/>\r
+                            <label for="email_alerte"><:rssarticle:email_alerte:></label>\r
+                        </li>\r
+                        <li class="editer_email_suivi">\r
+                            <input type="text" name="email_suivi" value="[(#ENV{email_suivi})]" size="20" class="fondl" id="email_suivi"/>\r
+                            <label for="email_suivi"><:rssarticle:email_alerte_email:></label>\r
+                        </li>\r
+                    </ul>              \r
+            </li>\r
+            <li class="editer">\r
+                 <h3 class="legend"><:rssarticle:copie_logo:></h3>\r
+                 <input type="checkbox" name="copie_logo"[ checked="(#ENV{copie_logo}|!={''}|?{'checked'})"] class="fondl" id="copie_logo" />\r
+                 <label for="copie_logo"><:rssarticle:copie_logo:></label>\r
+                \r
+            </li>\r
+               </ul>\r
+\r
+         [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]\r
+         <!--extra-->\r
+         <p class='boutons'><span class='image_loading'>&nbsp;</span>\r
+                       <input type='submit' class='submit' value='<:bouton_enregistrer:>' /></p>\r
+       </div></form>\r
+       ]\r
+</div>
\ No newline at end of file
diff --git a/www/plugins/rss_article_3_0/formulaires/editer_rssarticle.html b/www/plugins/rss_article_3_0/formulaires/editer_rssarticle.html
new file mode 100644 (file)
index 0000000..d523609
--- /dev/null
@@ -0,0 +1,22 @@
+
+<div class="formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_syndic,nouveau}">      
+  
+  [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       
+  <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       #SET{erreurs,#ENV**{erreurs}|table_valeur{#GET{name}}}#SET{obli,'obligatoire'}
+                  <li class="editer_rssarticle[ (#ENV**{erreurs}|table_valeur{rssarticle}|oui)erreur]">
+                    <div class="choix" style="margin-left:-130px">
+                      [(#CHEMIN_IMAGE{rssarticle-32.png}|balise_img{RSS})]
+                      <input type='checkbox' class="checkbox" name='rssarticle' value='oui' id='rssarticle'[ (#ENV{rssarticle}|=={oui}|?{'checked="checked"'})] />                                                     
+                      <label for="rssarticle"><:rssarticle:activer_recopie:></label>
+                    </div>
+                        [<span class='rssarticle'>(#ENV*{erreurs}|table_valeur{rssarticle})</span>]
+                  </li>
+               </ul>
+         [(#ENV{editable}|oui) <p class='boutons'><input type='submit' name="save" class='submit' value='<:bouton_enregistrer:>' /></p>]
+       </div></form>
+</div>
\ No newline at end of file
diff --git a/www/plugins/rss_article_3_0/formulaires/editer_rssarticle.php b/www/plugins/rss_article_3_0/formulaires/editer_rssarticle.php
new file mode 100644 (file)
index 0000000..1c7fcf2
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+include_spip('inc/autoriser');
+
+/**
+* CVT: charger
+*
+*/
+function formulaires_editer_rssarticle_charger_dist($id_syndic='new', $retour=''){
+
+       $rssarticle = sql_getfetsel('rssarticle','spip_syndic','id_syndic='.intval($id_syndic));
+       $valeurs['rssarticle'] = $rssarticle;
+       $valeurs['id_syndic'] = $id_syndic;
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('modifier', 'syndic', $id_syndic))
+               $valeurs['editable'] = false;
+
+       return $valeurs;
+}
+
+/**
+* CVT: verifer
+*
+*/
+function formulaires_editer_rssarticle_verifier_dist($id_syndic='new', $retour=''){
+       $erreurs = array();
+       return $erreurs;
+}
+
+/**
+* CVT: traiter
+*
+*/
+function formulaires_editer_rssarticle_traiter_dist($id_syndic='new', $retour=''){
+       
+  $message = array('editable'=>true, 'message_ok'=>'');
+  
+  if (_request('rssarticle')=='oui') {
+       sql_updateq('spip_syndic',array(
+        'rssarticle'=> 'oui',
+        'resume'=>'non',
+        'oubli'=>'oui'
+       ),'id_syndic='.intval($id_syndic)); 
+       
+       // on force le site en mode oubli et pas resume 
+       // on rensynchronise la syndic pour passer les anciens articles (qui etaient ss doute en mode resume) en mode complet HTML
+       //sql_delete("spip_syndic_articles", "id_syndic=".sql_quote($id_syndic)); // alternative ;)
+       include_spip('genie/syndic');        
+            $t = syndic_a_jour($id_syndic); 
+  } else {
+       sql_updateq('spip_syndic',array('rssarticle'=> 'non'),'id_syndic='.intval($id_syndic)); 
+  }
+       
+  $message = _T("rssarticle:site_maj");
+
+       return $message;
+       
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/rss_article_3_0/genie/rssarticle_copie.php b/www/plugins/rss_article_3_0/genie/rssarticle_copie.php
new file mode 100644 (file)
index 0000000..f4dc256
--- /dev/null
@@ -0,0 +1,197 @@
+<?php\r
+/**\r
+ * Plugin RSS article pour Spip 3.0\r
+ * Licence GPL\r
+ * \r
+ *\r
+ */\r
+\r
+// TODO\r
+// - gerer les mots-clés hors enclosure ?\r
+include_spip("inc/mail");\r
+include_spip('inc/filtres'); \r
+include_spip('inc/distant');\r
+include_spip('inc/chercher_logo');\r
+include_spip('inc/rubriques');\r
+include_spip('inc/config');\r
+\r
+function genie_rssarticle_copie_dist($t){  \r
+\r
+  // configuration (ou valeurs par defaut)    \r
+  if (lire_config('rssarticle/import_statut')=="publie")       $import_statut="publie"; else  $import_statut="prop";     \r
+  if (lire_config('rssarticle/mode')=="auto")       $mode_auto=true; else  $mode_auto=false;  \r
+  if (lire_config('rssarticle/email_alerte')=="on") $email_alerte=true; else  $email_alerte=false;\r
+  if (lire_config('rssarticle/copie_logo')=="on")   $copie_logo=true; else  $copie_logo=false;        \r
+  $email_suivi = lire_config('rssarticle/email_suivi'); \r
+  \r
+  // autres valeurs\r
+  $accepter_forum =    substr($GLOBALS['meta']['forums_publics'],0,3);\r
+  \r
+  // principe de pile:\r
+  // on boucle sur les derniers articles syndiques pour les retirer ensuite\r
+  // bourrin voir les requetes avec jointure du Miroir ou du site Rezo \r
+  $log = "";\r
+  $log_c = 0;\r
+  \r
+  // boucle sur les sites publies \r
+  if ($mode_auto) $u = sql_select("id_syndic,id_rubrique,id_secteur","spip_syndic","statut='publie'");   // tous \r
+          else    $u = sql_select("id_syndic,id_rubrique,id_secteur","spip_syndic","statut='publie' AND rssarticle='oui'");\r
+  \r
+  while ($b = sql_fetch($u)) {\r
+       $id_syndic = (int) $b['id_syndic'];\r
+       $id_rubrique = (int) $b['id_rubrique'];\r
+       $id_secteur = (int) $b['id_secteur'];\r
+  \r
+       // sur chaque site copie les derniers syndication\r
+       $s = sql_select("*", "spip_syndic_articles", "statut='publie' AND id_syndic='$id_syndic'","","maj DESC","10");  // par flot de 10 articles / site pour limiter la charge\r
+       while ($a = sql_fetch($s)) {\r
+                       $titre =  $a['titre'];\r
+          $id_syndic_article = $a['id_syndic_article']; \r
+                    \r
+          // article avec mm titre existe ? (test doublons)\r
+               if (!$row = sql_fetsel("id_article","spip_articles","titre=".sql_quote($titre))) {        \r
+            \r
+            $texte = $a['descriptif'];\r
+            $lang  = $a['lang'];\r
+            $url   = $a['url'];\r
+            $tags =  $a['tags'];\r
+            $lsDate = $a['date'];\r
+            \r
+          \r
+            if ($lang=="")     \r
+                $lang = $GLOBALS['spip_lang'];  \r
+                \r
+            // cas particulier: \r
+            // site multilingue avec la configuration: 1 lang par rubrique  \r
+            // on force l'article a avoir la langue de la rubrique ds lequel il est importee(pour omaidi)            \r
+            if ($GLOBALS['meta']['multi_rubriques']=='oui') {\r
+                  $s_lang = sql_select("lang", "spip_rubriques", "id_rubrique=$id_rubrique");\r
+                  while ($a_lang = sql_fetch($s_lang)) \r
+                      $lang = $a_lang['lang'];                   \r
+            }\r
+            \r
+            //$lsDate = date('Y-m-d H:i:s');            \r
+            // creation de l'article\r
+            $id_article = sql_insertq( 'spip_articles', array(\r
+                                'titre'=>$titre, 'id_rubrique'=>$id_rubrique,\r
+                                'texte'=>$texte, 'statut'=>$import_statut, 'id_secteur'=>$id_secteur,\r
+                                'date'=> $lsDate, 'accepter_forum'=>$accepter_forum, 'lang'=>$lang, 'url_site'=>$url));\r
+                                \r
+            // lier article et site\r
+            sql_insertq( 'spip_articles_syndic', array('id_article'=>$id_article, 'id_syndic'=>$id_syndic));\r
+                                \r
+            // gestion auteur            \r
+            $auteurs= explode(", ",$a['lesauteurs']);            \r
+            foreach ($auteurs as $k => $auteur) {                       \r
+                 if ($current_id_auteur = rssarticle_get_id_auteur($auteur))\r
+                      sql_insertq( 'spip_auteurs_liens', array('id_auteur'=>$current_id_auteur, 'id_objet'=>$id_article, 'objet'=>'article'));                \r
+            }\r
+            \r
+            // tags a convertir en documents distants \r
+            $doc_distants = extraire_enclosures($tags);\r
+                       foreach ($doc_distants as $k=>$doc_distant) {\r
+                $infos = recuperer_infos_distantes($doc_distant);\r
+                if ($infos['extension']) {\r
+                    $ext    = $infos['extension'];\r
+                    $taille = $infos['tailles']; \r
+                    $row = sql_fetsel("inclus", "spip_types_documents", "extension=" . sql_quote($ext) . " AND upload='oui'");  // extension autorisee ?\r
+                    if ($row) {\r
+                          $id_document = sql_insertq( 'spip_documents', array(\r
+                                'extension'=>$ext, \r
+                                'date'=> $lsDate,\r
+                                'fichier'=> $doc_distant,\r
+                                'taille'=> $taille,\r
+                                'mode' => 'document',\r
+                                'distant' => 'oui'));\r
+                          \r
+                         sql_insertq( 'spip_documents_liens', array(\r
+                                'id_document' =>$id_document, \r
+                                'id_objet'=> $id_article,\r
+                                'objet'=> 'article',\r
+                                'vu'=> 'non'));                                        \r
+                    }\r
+                }\r
+                \r
+            }\r
+            \r
+            // logo\r
+            if ($copie_logo) {             \r
+               if ($logo_site = inc_chercher_logo_dist($id_syndic,"id_syndic")) {\r
+                  $logo_article = "arton$id_article.".$logo_site[3];\r
+                  @copy($logo_site[0],_DIR_LOGOS."$logo_article");\r
+               }                 \r
+            }\r
+                                                                       \r
+                       $log_c++;\r
+                       $log .= "\n - $titre";  \r
+            \r
+             // on "depublie" l'article syndique qui vient d'etre copie\r
+            sql_update("spip_syndic_articles", array('statut' => '"refuse"'), "id_syndic_article=$id_syndic_article");\r
+\r
+            // Mise à jour des dates de rubriques après création d'un article dedans\r
+           if ($id_article) {\r
+               if (function_exists('calculer_rubriques'))\r
+                   calculer_rubriques();\r
+               if (function_exists('calculer_langues_rubriques'))\r
+                   calculer_langues_rubriques();\r
+               if (function_exists('propager_les_secteurs'))\r
+                   propager_les_secteurs();\r
+           }\r
+                  \r
+          }  // test doublons\r
+       }  \r
+  } // FIN PILE\r
+    \r
+       \r
+       // log et alerte email\r
+  $log .= "\n\n---------\nPlugin Copie RSS en Articles: $log_c articles copies\n";\r
+  spip_log($log);\r
+  $log .= $GLOBALS['meta']['adresse_site']."/ecrire/?exec=accueil";\r
+       \r
+  if ($email_alerte && $email_suivi !="" && $log_c > 0)                 \r
+                  envoyer_mail($email_suivi,"Copie RSS en Articles", $log);\r
+              \r
+       // maintenance generale\r
+  // mode auto: on efface les syndic_articles de plus de 2 mois pour soulager le systeme (cf genie/syndic) \r
+  // attention: on efface sur l'ensemble des sites syndiques ss tenir compte de l'option               \r
+       if ($mode_auto) sql_delete('spip_syndic_articles', "maj < DATE_SUB(NOW(), INTERVAL 2 MONTH) AND date < DATE_SUB(NOW(), INTERVAL 2 MONTH)");\r
\r
+       return 1;\r
+}\r
+\r
+\r
+//\r
+// recupere id d'un auteur selon son nom sinon le creer\r
+function rssarticle_get_id_auteur($nom) {  \r
+   if (trim($nom)=="") \r
+        return false;\r
+   \r
+   if ($row = sql_fetsel(array("id_auteur"),"spip_auteurs","nom=".sql_quote($nom)))  \r
+        return $row['id_auteur']; \r
+\r
+    // auteur inconnu, on le cree ... \r
+    return sql_insertq('spip_auteurs',array('nom'=>$nom,'statut'=>'1comite'));\r
+}\r
+\r
+//\r
+// extraire les documents taggues enclosure \r
+// voir http://doc.spip.org/@afficher_enclosures\r
+function extraire_enclosures($tags) {\r
+       $s = array();\r
+       foreach (extraire_balises($tags, 'a') as $tag) {\r
+               if (extraire_attribut($tag, 'rel') == 'enclosure'\r
+               AND $t = extraire_attribut($tag, 'href')) {\r
+                       $s[] = $t;\r
+               }\r
+       }\r
+       return $s;\r
+}\r
+\r
+/*\r
+UPDATE `spip_syndic_articles` SET statut="publie";\r
+TRUNCATE TABLE `spip_articles`;\r
+DELETE FROM `spip_auteurs_liens` WHERE id_auteur > 1;\r
+DELETE FROM `spip_auteurs` WHERE id_auteur > 1; \r
+*/\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/rss_article_3_0/lang/paquet-rssarticle_fr.php b/www/plugins/rss_article_3_0/lang/paquet-rssarticle_fr.php
new file mode 100644 (file)
index 0000000..b6c94da
--- /dev/null
@@ -0,0 +1,21 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // R
+       'rssarticle_description' => 'Ce plugin recopie les flux RSS (articles syndiqués) en articles\r
+\r
+-* reprise du contenu du flux;\r
+-* créé l\'auteur s\'il est mentionné dans le flux;\r
+-* ajoute les documents distants présents dans le flux;\r
+-* dans le champs URL de l\'article, on indique l\'adresse de l\'article d\'origine.\r
+\r
+Pour éviter les doublons et les imports successifs, une fois l\'article créé, l\'article syndiqué est rejeté (ce qui permet de suivre où en sont les recopiés).',
+       'rssarticle_nom' => 'Flux RSS en articles',
+       'rssarticle_slogan' => 'Recopie les flux RSS en articles',
+);
+
+?>
\ No newline at end of file
diff --git a/www/plugins/rss_article_3_0/lang/rssarticle_ar.php b/www/plugins/rss_article_3_0/lang/rssarticle_ar.php
new file mode 100644 (file)
index 0000000..726711c
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+  // A
+  'article_origine' => '&#1607;&#1584;&#1575; &#1575;&#1604;&#1605;&#1602;&#1575;&#1604; &#1605;&#1606;&#1602;&#1608;&#1604; &#1593;&#1606; &#1605;&#1608;&#1602;&#1593;',
+  'activer_recopie_intro' => '&#1578;&#1583;&#1601;&#1602; RSS &#1575;&#1604;&#1609; &#1575;&#1604;&#1605;&#1602;&#1575;&#1604;&#1575;&#1578;',
+  'activer_recopie' => '&#1606;&#1587;&#1582; &#1575;&#1604;&#1605;&#1602;&#1575;&#1604;&#1575;&#1578; &#1575;&#1604;&#1606;&#1575;&#1578;&#1581;&#1577; &#1593;&#1606; &#1578;&#1583;&#1601;&#1602; RSS &#1575;&#1604;&#1609; &#1605;&#1602;&#1575;&#1604;&#1575;&#1578; SPIP',
+
+  // C
+  'citer_source' => '&#1603;&#1585; &#1575;&#1604;&#1605;&#1589;&#1583;&#1585;',
+  'citer_source_oui' => '&#1584;&#1603;&#1585; &#1593;&#1606;&#1608;&#1575;&#1606; &#1575;&#1604;&#1605;&#1602;&#1575;&#1604; &#1575;&#1604;&#1605;&#1589;&#1583;&#1585; &#1601;&#1610; &#1575;&#1604;&#1605;&#1602;&#1575;&#1604; &#1575;&#1604;&#1605;&#1587;&#1578;&#1608;&#1585;&#1583;',
+  'copie_logo' => '&#1606;&#1587;&#1582; &#1588;&#1593;&#1575;&#1585; &#1575;&#1604;&#1605;&#1608;&#1602;&#1593; &#1608;&#1580;&#1593;&#1604;&#1607; &#1587;&#1593;&#1575;&#1585; &#1575;&#1604;&#1605;&#1602;&#1575;&#1604;',
+
+  // S
+  'statut_article_importe' => '&#1608;&#1590;&#1593;&#1610;&#1577; &#1575;&#1604;&#1605;&#1602;&#1575;&#1604;&#1575;&#1578; &#1575;&#1604;&#1605;&#1587;&#1578;&#1608;&#1585;&#1583;&#1577;',
+  'suivi_syndic' => '&#1605;&#1578;&#1575;&#1576;&#1593;&#1577; &#1575;&#1604;&#1578;&#1585;&#1582;&#1610;&#1589;',
+
+  // E
+  'email_alerte' => '&#1573;&#1606;&#1584;&#1575;&#1585; &#1576;&#1575;&#1604;&#1576;&#1585;&#1610;&#1583; &#1575;&#1604;&#1573;&#1604;&#1603;&#1578;&#1585;&#1608;&#1606;&#1610; &#1593;&#1606;&#1583; &#1603;&#1604; &#1578;&#1585;&#1582;&#1610;&#1589; &#1601;&#1610; &#1605;&#1602;&#1575;&#1604;&#1567;',
+  'email_alerte_email' => '&#1601;&#1610; &#1581;&#1575;&#1604; &#1575;&#1604;&#1605;&#1608;&#1575;&#1601;&#1602;&#1577;&#1548; &#1593;&#1604;&#1609; &#1571;&#1610; &#1593;&#1606;&#1608;&#1575;&#1606; &#1610;&#1578;&#1605; &#1573;&#1585;&#1587;&#1575;&#1604; &#1575;&#1604;&#1573;&#1606;&#1584;&#1575;&#1585;&#1567;',
+
+  // I
+  'install_rssarticle' => '&#1573;&#1606;&#1588;&#1575;&#1569; &#1580;&#1583;&#1608;&#1604; spip_articles_syndic',
+
+  // M
+  'mode' => '&#1608;&#1590;&#1593;&#1610;&#1577; &#1575;&#1604;&#1578;&#1588;&#1594;&#1610;&#1604;',
+  'mode_auto' => '&#1575;&#1604;&#1608;&#1590;&#1593;&#1610;&#1577; &#1575;&#1604;&#1570;&#1604;&#1610;&#1577;: &#1606;&#1587;&#1582; &#1603;&#1604; &#1575;&#1604;&#1605;&#1608;&#1575;&#1602;&#1593; &#1575;&#1604;&#1605;&#1576;&#1608;&#1576;&#1577; &#1603;&#1605;&#1602;&#1575;&#1604;&#1575;&#1578;',
+  'mode_manuel' => '&#1575;&#1604;&#1608;&#1590;&#1593;&#1610;&#1577; &#1575;&#1604;&#1610;&#1583;&#1608;&#1610;&#1577;: &#1578;&#1581;&#1583;&#1583; &#1610;&#1583;&#1608;&#1610;&#1575;&#1611; &#1575;&#1604;&#1605;&#1608;&#1575;&#1602;&#1593; &#1575;&#1604;&#1605;&#1576;&#1608;&#1576;&#1577; &#1575;&#1604;&#1578;&#1610; &#1578;&#1585;&#1610;&#1583; &#1606;&#1587;&#1582;&#1607;&#1575; &#1603;&#1605;&#1602;&#1575;&#1604;&#1575;&#1578;'
+
+);
+
+
+?>
diff --git a/www/plugins/rss_article_3_0/lang/rssarticle_fr.php b/www/plugins/rss_article_3_0/lang/rssarticle_fr.php
new file mode 100644 (file)
index 0000000..cc84966
--- /dev/null
@@ -0,0 +1,46 @@
+<?php\r
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+\r
+$GLOBALS[$GLOBALS['idx_lang']] = array(\r
+\r
+  // A\r
+  'article_origine' => 'Cet article est repris du site', \r
+  'activer_recopie_intro' => 'Flux RSS en Articles',\r
+  'activer_recopie' => 'Copier les articles issus de ce flux RSS en articles SPIP',\r
+\r
+  // C\r
+  'citer_source' => 'Citer la source',\r
+  'citer_source_oui' => 'Citer l\'URL de l\'article d\'origine dans l\'article import&eacute;',\r
+  'configuration_rssarticle' => 'Flux RSS en articles',\r
+  'copie_logo' => 'Recopier le logo du site comme logo d\'article',\r
+  'cron_interval' => 'Fréquence de la copie des flux RSS en articles',\r
+  'cron_interval_timer' => 'Intervalle en seconde ',\r
+\r
+  // S\r
+  'statut_article_importe' => 'Statut des articles import&eacute;s',\r
+  'suivi_syndic' => 'Suivi de la syndication',\r
+  'site_maj' => 'Option enregistrée',\r
+  \r
+  // E\r
+  'email_alerte' => 'Pr&eacute;venir par email &agrave; chaque nouvelle syndication en articles ?',\r
+  'email_alerte_email' => 'Si oui, sur quel email ? ',\r
+  \r
+  // I\r
+  'install_rssarticle' => 'Cr&eacute;ation de la table spip_articles_syndic',\r
+  \r
+  // M\r
+  'maj_manuelle' => 'La copie manuelle des derniers flux RSS en articles a été effectuée',\r
+  'maj_recharge' => 'Relancer la copie manuelle',\r
+  'mode' => 'Mode de fonctionnement',\r
+  'mode_auto' => 'Mode automatique: tous les sites r&eacute;f&eacute;renc&eacute;s sont recopi&eacute;s en articles',\r
+  'mode_manuel' => 'Mode manuel: vous selectionnez manuellement les sites r&eacute;f&eacute;renc&eacute;s qui doivent être recopi&eacute;s en articles',\r
+  \r
+  // T\r
+  'titre_page_configurer_rssarticle' => 'Copie RSS en articles'\r
+  \r
+);\r
+\r
+\r
+?>\r
diff --git a/www/plugins/rss_article_3_0/paquet.xml b/www/plugins/rss_article_3_0/paquet.xml
new file mode 100644 (file)
index 0000000..96a765a
--- /dev/null
@@ -0,0 +1,21 @@
+<paquet\r
+       prefix="rssarticle"\r
+       categorie="edition"\r
+       version="1.1.0"\r
+       etat="dev"\r
+       compatibilite="[3.0.2;3.0.*]"\r
+       logo="prive/themes/spip/images/rssarticle-64.png"\r
+       documentation="http://www.spip-contrib.net/Plugin-Flux-RSS-en-articles"\r
+       schema="1.0.0" \r
+>\r
+       <nom>Flux RSS en articles</nom>\r
+       <auteur lien='http://www.erational.org'>erational</auteur>\r
+  <auteur>LudoRA</auteur>\r
+       <licence>GNU/GPL v3</licence>\r
+        <pipeline nom="declarer_tables_principales" inclure="base/rssarticle.php"/>\r
+        <pipeline nom="declarer_tables_interfaces" inclure="base/rssarticle.php"/>\r
+        <pipeline nom="declarer_tables_auxiliaires" inclure="base/rssarticle.php"/>\r
+        <pipeline nom="taches_generales_cron" inclure="rssarticle_pipelines.php"/>\r
+        <pipeline nom="affiche_milieu" inclure="rssarticle_pipelines.php"/>\r
+       <menu nom="configurer_rssarticle" titre="rssarticle:configuration_rssarticle" parent="menu_configuration" icone="images/rssarticle-16.png" />\r
+</paquet>\r
diff --git a/www/plugins/rss_article_3_0/prive/contenu/rssarticle.html b/www/plugins/rss_article_3_0/prive/contenu/rssarticle.html
new file mode 100644 (file)
index 0000000..6de5685
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="ajax">
+  #FORMULAIRE_EDITER_RSSARTICLE{#ID_SYNDIC}
+</div>
\ No newline at end of file
diff --git a/www/plugins/rss_article_3_0/prive/squelettes/contenu/configurer_rssarticle.html b/www/plugins/rss_article_3_0/prive/squelettes/contenu/configurer_rssarticle.html
new file mode 100644 (file)
index 0000000..970c186
--- /dev/null
@@ -0,0 +1,7 @@
+[(#AUTORISER{configurer,_rssarticle}|sinon_interdire_acces)]
+
+<h1 class="grostitre"><:rssarticle:titre_page_configurer_rssarticle:></h1>
+
+<div class="ajax">
+       #FORMULAIRE_CONFIGURER_RSSARTICLE
+</div>
\ No newline at end of file
diff --git a/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-128.png b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-128.png
new file mode 100644 (file)
index 0000000..edf8166
Binary files /dev/null and b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-128.png differ
diff --git a/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-16.png b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-16.png
new file mode 100644 (file)
index 0000000..ce22674
Binary files /dev/null and b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-16.png differ
diff --git a/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-32.png b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-32.png
new file mode 100644 (file)
index 0000000..391ac79
Binary files /dev/null and b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-32.png differ
diff --git a/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-64.png b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-64.png
new file mode 100644 (file)
index 0000000..edf8166
Binary files /dev/null and b/www/plugins/rss_article_3_0/prive/themes/spip/images/rssarticle-64.png differ
diff --git a/www/plugins/rss_article_3_0/rssarticle_administrations.php b/www/plugins/rss_article_3_0/rssarticle_administrations.php
new file mode 100644 (file)
index 0000000..5548c82
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+$GLOBALS['rssarticle_base_version'] = 0.3;
+    
+function rssarticle_upgrade(){
+
+               $version_base = $GLOBALS['rssarticle_base_version'];
+               $current_version = 0.0;
+               if ((!isset($GLOBALS['meta']['rssarticle_base_version']) )
+                               || (($current_version = $GLOBALS['meta']['rssarticle_base_version'])!=$version_base)){
+                       include_spip('base/rssarticle');
+                       if ($current_version==0.0){
+                               include_spip('base/create');
+                               include_spip('base/abstract_sql');
+                               creer_base();   
+                               maj_tables('spip_syndic');
+        echo "<p>"._T('rssarticle:install_rssarticle')."</p>"; 
+                         ecrire_meta('rssarticle_base_version',$current_version=$version_base,'non');                          
+                       }
+                       
+                       if (version_compare($current_version,"0.3","<")){
+                         include_spip('base/create');
+                         maj_tables('spip_syndic');
+                         echo "<p>"._T('rssarticle:mise_a_jour_v03')."</p>"; 
+                         ecrire_meta('rssarticle_base_version',$current_version="0.3",'non');
+                 }
+               
+                       ecrire_metas();
+               }
+}
+
+
+       
+function rssarticle_install($action){
+               $version_base = $GLOBALS['rssarticle_base_version'];
+               switch ($action){
+                       case 'test':
+                               return (isset($GLOBALS['meta']['rssarticle_base_version']) AND ($GLOBALS['meta']['rssarticle_base_version']>=$version_base));
+                               break;
+                       case 'install':
+                               rssarticle_upgrade();
+                               break;
+                       case 'uninstall':
+                               rssarticle_vider_tables();                                                              
+                               break;
+               }
+}
+
+/**
+ * Desinstallation du plugin
+ *
+ * @param string $nom_meta_base_version
+ */
+       
+function rssarticle_vider_tables() {
+    sql_alter("TABLE spip_syndic DROP rssarticle");
+               spip_query("DROP TABLE spip_articles_syndic");
+               effacer_meta('rssarticle_base_version');
+               ecrire_metas();
+}
+?>
diff --git a/www/plugins/rss_article_3_0/rssarticle_pipelines.php b/www/plugins/rss_article_3_0/rssarticle_pipelines.php
new file mode 100644 (file)
index 0000000..491da0c
--- /dev/null
@@ -0,0 +1,51 @@
+<?php\r
+/**\r
+ * genie / cron\r
+ *\r
+ */\r
+function rssarticle_taches_generales_cron($taches_generales){\r
+  $delai =  60*10; // valeur defaut: ts les 10 min \r
+  \r
+  // si cfg dispo, on charge les valeurs\r
+  if (function_exists(lire_config))  {\r
+        if (lire_config('rssarticle/cron_interval_value')!="") {    // verifier si champs CFG a ete renseigne sur ce plugin (retro-compat)       \r
+            $delai = intval(lire_config('rssarticle/cron_interval_value')); \r
+            if ($delai<10)    \r
+                      $delai=10;        // securite pour les valeurs absurdes             \r
+        }      \r
+  } \r
+       $taches_generales['rssarticle_copie'] = $delai;\r
+  \r
+       return $taches_generales;\r
+}\r
+\r
+/**\r
+ * Insertion au centre des pages d'articles dans le privé\r
+ * Affiche un formulaire d'édition de la licence de l'article\r
+ *\r
+ * @param array $flux Le contexte du pipeline\r
+ */\r
+function rssarticle_affiche_milieu($flux) {\r
+    if ($flux['args']['exec'] == 'site'){\r
+        include_spip('inc/config');\r
+        if (lire_config('rssarticle/mode')=="auto") $mode_auto=true; else  $mode_auto=false;\r
+        \r
+        if (!$mode_auto) {\r
+            $contexte['id_syndic'] = $flux["args"]["id_syndic"];\r
+            //$out = debut_cadre_relief(_DIR_PLUGIN_RSSARTICLE."prive/themes/spip/images/rssarticle-32.png", true, '',_T("rssarticle:activer_recopie_intro"));\r
+            $out .= "\n<div id='bloc_rssarticle'>";\r
+            $out .= "\n". recuperer_fond('prive/contenu/rssarticle',$contexte,array('ajax'=>false));\r
+            $out .= "\n</div>";\r
+            //$out .= "\n". fin_cadre_relief(true);\r
+            if ($p=strpos($flux['data'],'<!--affiche_milieu-->'))\r
+                $flux['data'] = substr_replace($flux['data'],$out,$p,0);\r
+                \r
+               \r
+        }\r
+    }\r
+    return $flux;\r
+}\r
+\r
+\r
+\r
+?>\r
diff --git a/www/plugins/rss_article_3_0/svn.revision b/www/plugins/rss_article_3_0/svn.revision
new file mode 100644 (file)
index 0000000..bf7defe
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/rss_article/trunk
+Revision: 64302
+Dernier commit: 2012-08-01 10:00:12 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/rss_article/trunk</origine>
+<revision>64302</revision>
+<commit>2012-08-01 10:00:12 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/saisies/action/deplacer_saisie.php b/www/plugins/saisies/action/deplacer_saisie.php
new file mode 100644 (file)
index 0000000..a28e532
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_deplacer_saisie_dist() {
+       include_spip('inc/session');
+       
+       $session         = _request('session');
+       $identifiant = _request('saisie');
+       $ou          = _request('ou');
+
+       // On récupère le formulaire à son état actuel
+       $formulaire_actuel = session_get($session);
+
+       if (!$formulaire_actuel) {
+               return "";
+       }
+
+       include_spip('inc/saisies');
+       
+       $saisies_actuelles = saisies_lister_par_identifiant($formulaire_actuel);
+       if (!isset($saisies_actuelles[$identifiant])) {
+               return "";
+       }
+
+       // tester @id et [@id] (fieldset)
+       if ($ou and !isset($saisies_actuelles[$ou]) and !isset($saisies_actuelles[ substr($ou,1,-1) ])) {
+               return "";
+       }
+
+       // on deplace ou c'est demande...
+       $formulaire_actuel = saisies_deplacer($formulaire_actuel, $identifiant, $ou);
+
+       // On sauve tout ca
+       $formulaire_actuel = session_set($session, $formulaire_actuel);
+}
+
+?>
diff --git a/www/plugins/saisies/aide/saisies.html b/www/plugins/saisies/aide/saisies.html
new file mode 100644 (file)
index 0000000..9b07f38
--- /dev/null
@@ -0,0 +1,5 @@
+<h1>Références complètes des saisies</h1>
+
+[(#ENV{format}|=={brut}|oui)<textarea style="width:100%; height:100%;">]
+[(#VAL|saisies_generer_aide)]
+[(#ENV{format}|=={brut}|oui)</textarea>]
diff --git a/www/plugins/saisies/balise/configurer_saisie.php b/www/plugins/saisies/balise/configurer_saisie.php
new file mode 100644 (file)
index 0000000..33902c1
--- /dev/null
@@ -0,0 +1,28 @@
+<?php 
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function balise_CONFIGURER_SAISIE_dist($p){
+
+       // On recupere le premier argument : le nom de la saisie
+       $saisie = Pile::recuperer_et_supprimer_argument_balise(1, $p);
+       
+       // On ajoute le squelette a inclure dans les parametres
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'fond', 'inclure/configurer_saisie');
+       
+       // On ajoute l'environnement
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'env');
+       
+       // On ajoute le nom recupere
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'saisie', $saisie);
+       
+       // On redirige vers la balise INCLURE
+       if(function_exists('balise_INCLURE'))
+               return balise_INCLURE($p);
+       else
+               return balise_INCLURE_dist($p); 
+
+}
+
+?>
diff --git a/www/plugins/saisies/balise/generer_saisies.php b/www/plugins/saisies/balise/generer_saisies.php
new file mode 100644 (file)
index 0000000..83e4401
--- /dev/null
@@ -0,0 +1,49 @@
+<?php 
+
+/**
+ * Gestion de la balise GENERER_SAISIES
+ *
+ * @package SPIP\Saisies\Balises
+ */
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Compile la balise GENERER_SAISIES
+ *
+ * La balise accepte 1 paramètre qui est une liste de descriptions de saisies
+ * dont on veut générer le HTML affichant les champs du formulaires
+ *
+ * Cette balise est un raccourcis :
+ * - #GENERER_SAISIES{#TABLEAU_DE_SAISIES} est équivalent à
+ * - #INCLURE{fond=generer_saisies,env,saisies=#TABLEAU_DE_SAISIES}
+ *
+ * @param Champ $p
+ *     Pile au niveau de la balise
+ * @return Champ
+ *     Pile complété du code à générer
+**/
+function balise_GENERER_SAISIES_dist($p){
+
+       // On recupere le premier (et seul) argument : le tableau decrivant ce qu'on veut generer
+       $config = Pile::recuperer_et_supprimer_argument_balise(1, $p);
+       
+       // On ajoute le squelette a inclure dans les parametres
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'fond', 'inclure/generer_saisies');
+       
+       // On ajoute l'environnement
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'env');
+       
+       // On ajoute le tableau recupere
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'saisies', $config);
+       
+       // On redirige vers la balise INCLURE
+       if(function_exists('balise_INCLURE'))
+               return balise_INCLURE($p);
+       else
+               return balise_INCLURE_dist($p); 
+
+}
+
+?>
diff --git a/www/plugins/saisies/balise/saisie.php b/www/plugins/saisies/balise/saisie.php
new file mode 100644 (file)
index 0000000..c891e55
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// pour ne pas interferer avec d'eventuelles futures fonctions du core
+// on met le tout dans un namespace ; les fonctions sont autonomes.
+
+class Pile {
+
+
+       // les arguments sont dans l'entree 0 du tableau param.
+       // param[0][0] vaut toujours '' (ou presque ?)
+       static function recuperer_argument_balise($pos, $p) {
+               if (!isset($p->param[0])) {
+                       return null;
+               }
+               if (!isset($p->param[0][$pos])) {
+                       return null;
+               }       
+               return $p->param[0][$pos];
+       }
+       
+       
+       
+       // les arguments sont dans l'entree 0 du tableau param.
+       // param[0][0] vaut toujours '' (ou presque ?)
+       static function supprimer_argument_balise($pos, $p) {
+               if (!isset($p->param[0])) {
+                       return null;
+               }
+               if (!isset($p->param[0][$pos])) {
+                       return null;
+               }       
+               if ($pos == 0) {
+                       array_shift($p->param[0]);
+               } else {
+                       $debut = array_slice($p->param[0], 0, $pos);
+                       $fin   = array_slice($p->param[0], $pos+1);
+                       $p->param[0] = array_merge($debut, $fin);
+               }               
+               return $p;
+       }       
+       
+       
+       
+       static function recuperer_et_supprimer_argument_balise($pos, &$p) {
+               $arg = Pile::recuperer_argument_balise($pos, $p);
+               $p   = Pile::supprimer_argument_balise($pos, $p);
+               return $arg;
+       }
+       
+       
+       
+       
+       // les arguments sont dans l'entree 0 du tableau param.
+       // param[0][0] vaut toujours '' (ou presque ?)
+       static function ajouter_argument_balise($element, $p) {
+               if (isset($p->param[0][0])) {
+                       $zero = array_shift($p->param[0]);
+                       array_unshift($p->param[0], $element);
+                       array_unshift($p->param[0], $zero);
+               } else {
+                       if (!is_array($p->param[0])) {
+                               $p->param[0] = array();
+                       }
+                       array_unshift($p->param[0], $element);
+               }
+               return $p;
+       }
+       
+       
+       
+       // creer_argument_balise(nom) = {nom}
+       // creer_argument_balise(nom, 'coucou') = {nom=coucou}
+       // creer_argument_balise(nom, $balise) = {nom=#BALISE}
+       static function creer_argument_balise($nom, $valeur = null) {
+               include_spip('public/interfaces');
+               $s = new Texte;
+               $s->texte = $nom;
+               $s->ligne=0;
+               
+               // si #BALISE cree avec Pile::creer_balise(), le mettre en array, comme les autres
+               if (is_object($valeur)) {
+                       $valeur = array($valeur);
+               }
+               
+               $res = null;
+               
+               // {nom}
+               if (is_null($valeur)) {
+                       $res = array($s);
+               } 
+               // {nom=coucou}
+               elseif (is_string($valeur)) {                   
+                       $s->texte .= "=$valeur";
+                       $res = array($s);
+               }
+               // {nom=#BALISE}
+               elseif (is_array($valeur)) {
+                       $s->texte .= "="; // /!\ sans cette toute petite chose, ça ne fait pas d'egalite :)
+                       $res = array_merge(array($s), $valeur);
+               }
+
+               return $res;
+       }
+       
+       
+       
+       static function creer_et_ajouter_argument_balise($p, $nom, $valeur = null) {
+               $new = Pile::creer_argument_balise($nom, $valeur); 
+               return Pile::ajouter_argument_balise($new, $p);
+       }
+
+
+
+       // creer une balise
+       static function creer_balise($nom, $opt) {
+               include_spip('public/interfaces');
+               $b = new Champ;
+               $b->nom_champ = strtoupper($nom);
+               $vars = get_class_vars('Champ'); // property_exists($b, $o); est en php 5
+               foreach ($opt as $o=>$val) {
+                       #if (property_exists($b,$o)) {
+                       if (array_key_exists($o, $vars)) {
+                               if ($o == 'param') {
+                                       array_unshift($val, '');
+                                       $b->$o = array($val);
+                               } else {
+                                       $b->$o = $val;
+                               }
+                       }
+               }
+               return $b;
+       }
+}
+
+
+
+/* 
+ * #saisie{type,nom} : champs obligatoires
+ * 
+ * collecte des arguments en fonctions du parametre "nom"
+ * ajoute des arguments
+ * appelle #INCLURE avec les arguments collectes en plus
+ * 
+ * il faudrait en faire une balise dynamique (?)
+ * pour avoir un code plus propre
+ * mais je n'ai pas reussi a trouver comment recuperer "valeur=#ENV{$nom}"
+ * 
+ */
+function balise_SAISIE_dist ($p) {
+
+       // on recupere les parametres sans les traduire en code d'execution php
+       $type_saisie = Pile::recuperer_et_supprimer_argument_balise(1, $p); // $type
+       $titre       = Pile::recuperer_et_supprimer_argument_balise(1, $p); // $titre
+
+       // creer #ENV*{$titre} (* pour les cas de tableau serialises par exemple, que l'on veut reutiliser)
+       $env_titre   = Pile::creer_balise('ENV', array('param' => array($titre), 'etoile' => '*')); // #ENV*{titre}
+
+       // on modifie $p pour ajouter des arguments
+       // {nom=$titre, valeur=#ENV{$titre}, erreurs, type_saisie=$type, fond=saisies/_base}
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'nom', $titre);
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'valeur', $env_titre);
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'type_saisie', $type_saisie);
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'erreurs');
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'fond', 'saisies/_base');
+
+       // on appelle la balise #INCLURE
+       // avec les arguments ajoutes
+       if(function_exists('balise_INCLURE'))
+               return balise_INCLURE($p);
+       else
+               return balise_INCLURE_dist($p); 
+               
+}
+
+
+
+
+?>
diff --git a/www/plugins/saisies/balise/voir_saisie.php b/www/plugins/saisies/balise/voir_saisie.php
new file mode 100644 (file)
index 0000000..3498901
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/* 
+ * #VOIR_SAISIE{type,nom} : champs obligatoires
+ * 
+ * collecte des arguments en fonctions du parametre "nom"
+ * ajoute des arguments
+ * appelle #INCLURE avec les arguments collectes en plus
+ * 
+ */
+function balise_VOIR_SAISIE_dist ($p) {
+
+       // on recupere les parametres sans les traduire en code d'execution php
+       $type_saisie = Pile::recuperer_et_supprimer_argument_balise(1, $p);
+       $nom       = Pile::recuperer_et_supprimer_argument_balise(1, $p);
+
+       // creer #ENV*{$titre} (* pour les cas de tableau serialises par exemple, que l'on veut reutiliser)
+       $env_nom   = Pile::creer_balise('ENV', array('param' => array($nom), 'etoile' => '*')); // #ENV*{nom}
+
+       // on modifie $p pour ajouter des arguments
+       // {nom=$nom, valeur=#ENV{$nom}, type_saisie=$type, fond=saisies/_base}
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'nom', $nom);
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'valeur', $env_nom);
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'type_saisie', $type_saisie);
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'fond', 'saisies-vues/_base');
+
+       // on appelle la balise #INCLURE
+       // avec les arguments ajoutes
+       if(function_exists('balise_INCLURE'))
+               return balise_INCLURE($p);
+       else
+               return balise_INCLURE_dist($p); 
+               
+}
+
+?>
diff --git a/www/plugins/saisies/balise/voir_saisies.php b/www/plugins/saisies/balise/voir_saisies.php
new file mode 100644 (file)
index 0000000..609742d
--- /dev/null
@@ -0,0 +1,30 @@
+<?php 
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function balise_VOIR_SAISIES_dist($p){
+
+       // On recupere les arguments : les tableaux decrivant ce qu'on veut generer + les reponses
+       $saisies = Pile::recuperer_et_supprimer_argument_balise(1, $p);
+       $valeurs = Pile::recuperer_et_supprimer_argument_balise(1, $p);
+       
+       // On ajoute le squelette a inclure dans les parametres
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'fond', 'inclure/voir_saisies');
+       
+       // On ajoute l'environnement
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'env');
+       
+       // On ajoute les tableaux recuperes
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'saisies', $saisies);
+       $p = Pile::creer_et_ajouter_argument_balise($p, 'valeurs', $valeurs);
+       
+       // On redirige vers la balise INCLURE
+       if(function_exists('balise_INCLURE'))
+               return balise_INCLURE($p);
+       else
+               return balise_INCLURE_dist($p); 
+
+}
+
+?>
diff --git a/www/plugins/saisies/contenu/page-saisies_cvt.html b/www/plugins/saisies/contenu/page-saisies_cvt.html
new file mode 100644 (file)
index 0000000..0d7a487
--- /dev/null
@@ -0,0 +1,4 @@
+<h1>CVT automatique avec Saisies</h1>
+<p>Démonstration d'un formulaire CVT généré uniquement à partir d'une déclaration de Saisies</p>
+
+#FORMULAIRE_SAISIES_CVT
diff --git a/www/plugins/saisies/css/formulaires_constructeur.css b/www/plugins/saisies/css/formulaires_constructeur.css
new file mode 100644 (file)
index 0000000..94415fa
--- /dev/null
@@ -0,0 +1,181 @@
+
+.formulaire_spip .formulaire_spip{
+       border:none;
+       background:transparent;
+}
+#deplacable .ui-state-highlight { height: 5em; line-height: 1.2em; }
+#deplacable .ui-sortable {min-height:3em;}
+/*
+.formulaire_construire_formulaire{
+       padding:1em;
+}
+.formulaire_construire_formulaire ul li label{
+       display:block;
+       margin:0;
+       width:auto;
+       float:none;
+       clear:both;
+       line-height:1.7em;
+}
+.formulaire_construire_formulaire input.text, .formulaire_construire_formulaire input.password, .formulaire_construire_formulaire textarea, .formulaire_construire_formulaire select{
+       width:auto;
+}
+*/
+.formulaire_construire_formulaire li.actions_formulaire{
+       margin:0;
+       padding:1em;
+       text-align:center;
+       border:0;
+}
+.formulaire_construire_formulaire li.actions_formulaire img{
+       vertical-align:middle;
+}
+/*
+.formulaire_construire_formulaire li.configurable{
+       position:relative;
+       padding:1em;
+       margin:0.5em 0;
+       background:transparent;
+       border:1px dashed transparent;
+       border-radius:5px;
+       -moz-border-radius:5px;
+       -webkit-border-radius:5px;
+}
+.formulaire_construire_formulaire li.configurable.hover{
+       border-color:#999;
+}
+*/
+.formulaire_construire_formulaire li.en_configuration{
+       border:5px solid #999;
+       border-radius:5px;
+       margin:.5em;
+}
+.formulaire_construire_formulaire li.fieldset.configurable>fieldset>ul {margin-left:30px;}
+/*
+.formulaire_construire_formulaire li.fieldset.configurable{
+       padding:0;
+}
+.formulaire_construire_formulaire li.fieldset h3.legend{
+       margin:0;
+}
+.formulaire_construire_formulaire li.fieldset.configurable > fieldset{
+       border:1px solid #ddd;
+       padding:0;
+}
+.formulaire_construire_formulaire li.fieldset.configurable > fieldset > ul{
+       padding:0 1em;
+}
+*/
+.formulaire_construire_formulaire .formulaire_configurer{
+       border-top:3px dashed #999;
+       margin: 1em -8px 0 -138px;
+    padding: 1em .5em .5em .5em;
+    background:white;
+}
+.formulaire_construire_formulaire .fieldset > .formulaire_configurer{
+       margin: 1em -8px 0;
+}
+
+/*
+.formulaire_construire_formulaire li.fieldset.configurable > .formulaire_configurer{
+       margin:1em 0 0 0;
+}
+.formulaire_construire_formulaire .formulaire_configurer fieldset{
+       border:0;
+       padding:0;
+}
+.formulaire_construire_formulaire .formulaire_configurer-contenus li.editer{
+       border:0;
+       margin:0.5em 0;
+       padding:0.5em 1em;
+}
+.formulaire_construire_formulaire .formulaire_configurer li.formulaire_configurer-contenu{
+       background:white;
+       border-top:1px solid #ddd;
+       border-radius:0 0 5px 5px;
+       -moz-border-radius:0 0 5px 5px;
+       -webkit-border-radius:0 0 5px 5px;
+}
+*/
+.formulaire_construire_formulaire .formulaire_configurer .formulaire_configurer-onglets {
+       overflow:auto;
+}
+.formulaire_construire_formulaire .formulaire_configurer .formulaire_configurer-onglets li{
+       float:left;
+       width:auto;
+       clear:none;
+       padding:0;
+       background:#eee;
+       border:1px solid #ddd;
+       margin-right:1px;
+       -moz-border-radius:5px 5px 0 0;
+       -webkit-border-radius:5px 5px 0 0;
+       -o-border-radius:5px 5px 0 0;
+       border-radius:5px 5px 0 0;
+}
+.formulaire_construire_formulaire .formulaire_configurer .formulaire_configurer-onglets li.actif{
+       background:white;
+       border-bottom:1px solid white;
+}
+.formulaire_construire_formulaire .formulaire_configurer .formulaire_configurer-onglets li.erreur a{
+       color:#CC3300;
+}
+.formulaire_construire_formulaire .formulaire_configurer .formulaire_configurer-onglets li a{
+       display:block;
+       padding:.5em;
+}
+.formulaire_construire_formulaire .formulaire_configurer .boutons { margin-bottom: -20px; }
+
+.formulaire_configurer-contenus > .fieldset > fieldset:first-child {border-top:0;}
+
+.formulaire_construire_formulaire li.editer,
+.formulaire_construire_formulaire li.explication,
+.formulaire_construire_formulaire li.fieldset {padding-top:30px; position:relative;}
+.formulaire_construire_formulaire li.explication { padding-left:140px; background:transparent; }
+.formulaire_construire_formulaire li.explication > p { margin-left:-130px; }
+.formulaire_construire_formulaire .formulaire_configurer li.fieldset {padding-top:0px;}
+.formulaire_construire_formulaire .formulaire_configurer fieldset fieldset>ul>li.editer:first-child {padding-top:0px;}
+
+.formulaire_construire_formulaire li.hover {background-color:transparent;}
+
+.formulaire_construire_formulaire .actions{
+       position:absolute;
+       right:5px;
+       top:5px;
+}
+
+.formulaire_construire_formulaire .actions button{
+       cursor:pointer;
+       background:none;
+       border:none;
+       opacity:0.7;
+}
+.formulaire_construire_formulaire .actions button:hover{
+       opacity:1;
+}
+.formulaire_construire_formulaire .actions .move {
+       cursor:move;
+}
+
+
+
+.formulaire_construire_formulaire li.saisies_disponibles {
+       /*padding:1em;*/
+}
+
+.formulaire_construire_formulaire .ajouter_saisie{
+       width:45%;
+       margin:5px;
+       padding:0.5em 8px 0.5em 36px;
+       font-size:1em;
+       text-align:left;
+       color:black;
+       cursor:pointer;
+       background:white url() 8px center no-repeat;
+       border:1px solid #ccc;
+}
+
+.formulaire_construire_formulaire .ajouter_saisie img{
+       vertical-align:middle;
+}
+
diff --git a/www/plugins/saisies/extra-vues/pays.html b/www/plugins/saisies/extra-vues/pays.html
new file mode 100644 (file)
index 0000000..f45fbd1
--- /dev/null
@@ -0,0 +1,8 @@
+<B_pays>
+<div class="#ENV{champ_extra}">
+       <strong>#ENV{label_extra}</strong>
+       <BOUCLE_pays(GEO_PAYS){id_pays=#ENV*{valeur_extra}}>
+               #NOM
+       </BOUCLE_pays>
+</div>
+</B_pays>
\ No newline at end of file
diff --git a/www/plugins/saisies/formulaires/construire_formulaire.html b/www/plugins/saisies/formulaires/construire_formulaire.html
new file mode 100644 (file)
index 0000000..9fda49d
--- /dev/null
@@ -0,0 +1,217 @@
+[(#ENV{erreurs}|table_valeur{positionner}|oui)
+       <a name="ajax_ancre" href="[(#ENV{erreurs}|table_valeur{positionner})]"></a>
+]
+<div class="formulaire_spip formulaire_editer formulaire_#ENV{form}">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       <p id="message_attention" class="reponse_formulaire reponse_formulaire_ok[ (#ENV{formulaire_modifie}|non) invisible]">#ENV*{_message_attention}</p>
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       
+       <BOUCLE_editable(CONDITION){si #ENV{editable}|oui}>
+       <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire 
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <input style="display:none;" type="submit" class="submit" name="enregistrer" value="<:bouton_enregistrer:>" />
+
+               <ul id="deplacable">
+                       
+                       <li id="reinitialiser" class="actions_formulaire[ (#ENV{formulaire_modifie}|non) invisible]">
+                               <button type="submit" class="submit" name="reinitialiser" value="oui" onclick="return confirm('<:saisies:construire_reinitialiser_confirmer:>')">
+                                       <img src="#CHEMIN{images/formulaire-reinitialiser-24.png}" alt="" />
+                                       <:saisies:construire_reinitialiser:>
+                               </button>
+                       </li>
+
+                       <BOUCLE_contenu(POUR){tableau #ENV{_contenu}}>
+                       [(#VAL{saisie}|array_key_exists{#VALEUR}|oui)
+                               [(#VALEUR**|formidable_generer_saisie_configurable{#ENV**|unserialize})]
+                       ]
+                       </BOUCLE_contenu>
+                       <li class="aucun"><em class="attention"><:saisies:construire_aucun_champs:></em></li>
+                       <//B_contenu>
+                       
+                       <B_saisies_disponibles>
+                       <li class="editer haut saisies_disponibles" id="attrapable">
+                               <label><:saisies:construire_ajouter_champ:></label>
+                               <BOUCLE_saisies_disponibles(POUR){tableau #ENV{_saisies_disponibles}}>
+                               <button type="submit" name="ajouter_saisie" value="#CLE" class="submit ajouter_saisie"[ title="(#VALEUR|table_valeur{description})"] [style="background-image:url((#VALEUR|table_valeur{icone}|sinon{#CHEMIN{images/formulaire-saisie-defaut.png}}))"]>
+                                       <span>[(#VALEUR|table_valeur{titre})]</span>
+                               </button>
+                               </BOUCLE_saisies_disponibles>
+                       </li>
+                       </B_saisies_disponibles>
+               </ul>
+
+               
+               [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
+               <!--extra-->
+               
+               <span class='image_loading'></span>
+       </div></form>
+
+       <script type="text/javascript">
+               jQuery(function(){
+                       jQuery('.formulaire_construire_formulaire li.configurable')
+                               .hover(
+                                       function(){
+                                               jQuery(this)
+                                                       .addClass('hover')
+                                                       .find('> .actions')
+                                                               .show()
+                                                       .end()
+                                                       .parents('li.configurable:not(.en_configuration)')
+                                                               .mouseout();
+                                       },
+                                       function(){
+                                               if (!jQuery(this).is('.en_configuration'))
+                                                       jQuery(this)
+                                                               .removeClass('hover')
+                                                               .find('> .actions')
+                                                                       .hide()
+                                                               .end()
+                                                               .parents('li.configurable').eq('0')
+                                                                       .mouseover();
+                                       }
+                               )
+                               .filter(':not(.en_configuration)')
+                                       .find('> .actions')
+                                               .hide()
+                                       .end()
+                               .end();
+                       
+                       // On lance la création des onglets
+                       formulaire_configurer_onglets();
+                       
+                       // Gérer la liste des vérifications
+                       jQuery('.liste_verifications')
+                               .each(function(){
+                                       var options = jQuery(this).siblings('.options_verifier').hide();
+                                       var select = jQuery(this).find('select');
+                                       
+                                       select
+                                               .change(function(){
+                                                       var montrer = jQuery(this).val() ? jQuery(this).val() : 'soigfeg';
+                                                       options.hide().filter('.'+montrer).show();
+                                               })
+                                               .change();
+                               });
+                       
+                       // On déplie toujours les fieldsets plés par défaut
+                       jQuery('li.fieldset.plie')
+                               .each(function(){
+                                       jQuery(this)
+                                               .removeClass('plie')
+                                               .find('> fieldset > ul').show();
+                               });
+                               
+                       [(#ENV{erreurs}|non|et{#ENV{_chemin_ui}})
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.core.js}", function(){
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.widget.js}", function(){
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.mouse.js}", function(){
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.sortable.js}", function(){
+                                       if ($.fn.sortable) {
+                                               jQuery( "#deplacable, #deplacable ul" ).sortable({
+                                                       revert: true,
+                                                       containment: '#deplacable',
+                                                       connectWith: "#deplacable, #deplacable ul",
+                                                       placeholder: "ui-state-highlight",
+                                                       handle: '>.actions .deplacer_saisie',
+                                                       start: function(event, ui) {
+                                                               jQuery('.ui-state-highlight')
+                                                                       .css('height', ui.item.css('height'))
+                                                                       .css('height', '+=20px');
+                                                       },
+                                                       update: function(event, ui) {
+                                                               id = ui.item.data('id');
+                                                               ou = ui.item.next().data('id');
+                                                               // avant le suivant
+                                                               if (!ou) {
+                                                                       // sinon dans le parent
+                                                                       ou = ui.item.closest('.fieldset').data('id');
+                                                                       if (ou) {
+                                                                               ou = '[(#VAL{91}|chr)]' + ou + '[(#VAL{93}|chr)]';
+                                                                       }
+                                                               }
+                                                               url = "#URL_ECRIRE";
+                                                               $.get(url, {
+                                                                       session: '#ENV{_identifiant_session}',
+                                                                       action: 'deplacer_saisie',
+                                                                       saisie: id,
+                                                                       ou: ou
+                                                               }, function() {
+                                                                       //jQuery('input.vide').submit();
+                                                                       jQuery('#reinitialiser').removeClass('invisible');
+                                                                       jQuery('#message_attention').removeClass('invisible');
+                                                               });
+                                                       }
+                                               });
+                                       }
+                               });});});});
+                               
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.core.js}", function(){
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.widget.js}", function(){
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.mouse.js}", function(){
+                               $.getScript("#CHEMIN{#ENV{_chemin_ui}jquery.ui.draggable.js}", function(){
+                                       if ($.fn.draggable) {
+                                               jQuery( "#attrapable" ).draggable({
+                                                       connectToSortable: "#deplacable, #deplacable ul",
+                                                       helper: "clone"
+                                               });
+                                       }
+                               });});});});
+                       ]
+               });
+               
+               function formulaire_configurer_onglets(){
+                       var formulaire_configurer = jQuery('.formulaire_configurer');
+                       var onglets = jQuery('<ul class="formulaire_configurer-onglets"></ul>');
+                       var contenus = formulaire_configurer.find('> ul > li.fieldset');
+                       
+                       // On ajoute le conteneur des onglets
+                       formulaire_configurer
+                               .prepend(onglets);
+                       
+                       // On parcourt les contenus pour générer les onglets
+                       contenus
+                               .each(function(i){
+                                       // On ajoute un identifiant et une classe
+                                       jQuery(this)
+                                               .attr('id', 'formulaire_configurer-contenu-'+i)
+                                               .addClass('formulaire_configurer-contenu');
+                                       // On récupère le titre (en le cachant au passage)
+                                       var titre = jQuery(this).find('h3').eq(0).hide().text();
+                                       // On crée un onglet
+                                       var onglet = jQuery('<li><a href="#formulaire_configurer-contenu-'+i+'">'+titre+'</a></li>');
+                                       onglet
+                                               .click(function(){
+                                                       contenus.hide();
+                                                       jQuery(
+                                                               jQuery(this)
+                                                                       .siblings()
+                                                                               .removeClass('actif')
+                                                                       .end()
+                                                                       .addClass('actif')
+                                                                       .find('a')
+                                                                               .attr('href')
+                                                       ).show();
+                                                       return false;
+                                               });
+                                       
+                                       // On active le premier onglet au démarrage
+                                       if (i == 0) onglet.addClass('actif');
+                                       
+                                       // S'il y a des erreurs dans cette partie du contenu, on met une classe "erreurs" à l'onglet aussi
+                                       if (jQuery(this).find('li.erreur').length > 0)
+                                               onglet.addClass('erreur');
+                                       
+                                       // On ajoute l'onglet
+                                       onglets
+                                               .append(onglet);
+                               })
+                               .hide()
+                               .eq(0)
+                                       .show();
+               }
+       </script>
+       </BOUCLE_editable>
+</div>
diff --git a/www/plugins/saisies/formulaires/construire_formulaire.php b/www/plugins/saisies/formulaires/construire_formulaire.php
new file mode 100644 (file)
index 0000000..6255abb
--- /dev/null
@@ -0,0 +1,533 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function formulaires_construire_formulaire_charger($identifiant, $formulaire_initial=array(), $options=array()){
+       include_spip('inc/saisies');
+       $contexte = array();
+       
+       // On ajoute un préfixe devant l'identifiant, pour être sûr
+       $identifiant = 'constructeur_formulaire_'.$identifiant;
+       $contexte['_identifiant_session'] = $identifiant;
+       
+       // On vérifie ce qui a été passé en paramètre 
+       if (!is_array($formulaire_initial)) $formulaire_initial = array();
+       
+       // On initialise la session si elle est vide
+       if (is_null($formulaire_actuel = session_get($identifiant))){
+               session_set($identifiant, $formulaire_initial);
+               $formulaire_actuel = $formulaire_initial;
+       }
+       
+       // Si le formulaire actuel est différent du formulaire initial on agite un drapeau pour le dire
+       if ($formulaire_actuel != $formulaire_initial){
+               $contexte['formulaire_modifie'] = true;
+       }
+       $contexte['_message_attention'] = _T('saisies:construire_attention_modifie');
+       
+       // On passe ça pour l'affichage
+       $contexte['_contenu'] = $formulaire_actuel;
+
+       // On passe ça pour la récup plus facile des champs
+       $contexte['_saisies_par_nom'] = saisies_lister_par_nom($formulaire_actuel);
+       // Pour déclarer les champs modifiables à CVT
+       foreach(array_keys($contexte['_saisies_par_nom']) as $nom){
+               $contexte["saisie_modifiee_$nom"] = array();
+       }
+       
+       // La liste des saisies
+       $saisies_disponibles = saisies_lister_disponibles();
+       $contexte['_saisies_disponibles'] = $saisies_disponibles;
+       
+       $contexte['fond_generer'] = 'formulaires/inc-generer_saisies_configurables';
+       
+       // On cherche jquery UI pour savoir si on pourra glisser-déplacer
+       // SPIP 3 - jquery_ui
+       if (find_in_path('javascript/ui/jquery.ui.sortable.js') and find_in_path('javascript/ui/jquery.ui.draggable.js')){
+               $contexte['_chemin_ui'] = 'javascript/ui/';
+       }
+       // plugin jquery_ui >= 1.8
+       elseif (find_in_path('javascript/jquery-ui/ui/jquery.ui.sortable.js') and find_in_path('javascript/jquery-ui/ui/jquery.ui.draggable.js')){
+               $contexte['_chemin_ui'] = 'javascript/jquery-ui/ui/';
+       }
+       // plugin jquery_ui < 1.8
+       elseif (find_in_path('javascript/jquery-ui-1.8.16/ui/jquery.ui.sortable.js') and find_in_path('javascript/jquery-ui-1.8.16/ui/jquery.ui.draggable.js')){
+               $contexte['_chemin_ui'] = 'javascript/jquery-ui-1.8.16/ui/';
+       }
+       else{
+               $contexte['_chemin_ui'] = false;
+       }
+       
+       return $contexte;
+}
+
+function formulaires_construire_formulaire_verifier($identifiant, $formulaire_initial=array(), $options=array()){
+       include_spip('inc/saisies');
+       $erreurs = array();
+       // l'une ou l'autre sera presente
+       $configurer_saisie = $enregistrer_saisie = '';
+
+       // Pas d'erreur si l'on ne demande rien
+       if (!($nom_ou_id = $configurer_saisie  = _request('configurer_saisie')
+       OR    $nom_ou_id = $enregistrer_saisie = _request('enregistrer_saisie'))) {
+               return $erreurs;
+       }
+
+       // On ajoute un préfixe devant l'identifiant
+       $identifiant = 'constructeur_formulaire_'.$identifiant;
+       // On récupère le formulaire à son état actuel
+       $formulaire_actuel = session_get($identifiant);
+
+       // On récupère les saisies actuelles, par identifiant ou par nom
+       if ($nom_ou_id[0] == '@') {
+               $saisies_actuelles = saisies_lister_par_identifiant($formulaire_actuel);
+               $nom = $saisies_actuelles[$nom_ou_id]['options']['nom'];
+       } else {
+               $saisies_actuelles = saisies_lister_par_nom($formulaire_actuel);
+               $nom = $nom_ou_id;
+       }
+       $noms_autorises = array_keys($saisies_actuelles);
+
+       // le nom (ou identifiant) doit exister
+       if (!in_array($nom_ou_id, $noms_autorises)) {
+               return $erreurs;
+       }
+       
+       // La liste des saisies
+       $saisies_disponibles = saisies_lister_disponibles();
+       
+       $saisie = $saisies_actuelles[$nom_ou_id];
+       $formulaire_config = $saisies_disponibles[$saisie['saisie']]['options'];
+       array_walk_recursive($formulaire_config, 'formidable_transformer_nom', "saisie_modifiee_${nom}[options][@valeur@]");
+       $formulaire_config = saisie_identifier(array('saisies'=>$formulaire_config));
+       $formulaire_config = $formulaire_config['saisies'];
+       
+       // Si la saisie possede un identifiant, on l'ajoute
+       // au formulaire de configuration pour ne pas le perdre en route
+       if (isset($saisie['identifiant']) and $saisie['identifiant']) {
+               $formulaire_config = saisies_inserer(
+                       $formulaire_config,
+                       array(
+                               'saisie' => 'hidden',
+                               'options' => array(
+                                       'nom' => "saisie_modifiee_${nom}[identifiant]",
+                                       'defaut' => $saisie['identifiant']
+                               ),
+                       )
+               );
+       }
+       
+       // S'il y a l'option adéquat, on ajoute le champ pour modifier le nom
+       if (isset($options['modifier_nom']) and $options['modifier_nom']
+         and $chemin_nom = saisies_chercher($formulaire_config, "saisie_modifiee_${nom}[options][description]", true))
+       {
+               $chemin_nom[] = 'saisies';
+               $chemin_nom[] = '0';
+
+               $formulaire_config = saisies_inserer(
+                       $formulaire_config,
+                       array(
+                               'saisie' => 'input',
+                               'options' => array(
+                                       'nom' => "saisie_modifiee_${nom}[options][nom]",
+                                       'label' => _T('saisies:option_nom_label'),
+                                       'explication' => _T('saisies:option_nom_explication'),
+                                       'obligatoire' => 'oui',
+                                       'size' => 50
+                               ),
+                               'verifier' => array(
+                                       'type' => 'regex',
+                                       'options' => array(
+                                               'modele' => '/^[\w]+$/'
+                                       )
+                               )
+                       ),
+                       $chemin_nom
+               );
+       }
+
+       // liste des options de vérification
+       $verif_options = array();
+
+       // S'il y a un groupe "validation" alors on va construire le formulaire des vérifications
+       if ($chemin_validation = saisies_chercher($formulaire_config, "saisie_modifiee_${nom}[options][validation]", true)){
+               include_spip('inc/verifier');
+               $liste_verifications = verifier_lister_disponibles();
+               $chemin_validation[] = 'saisies';
+               $chemin_validation[] = 1000000; // à la fin
+               
+               // On construit la saisie à insérer et les fieldset des options
+               $saisie_liste_verif = array(
+                       'saisie' => 'selection',
+                       'options' => array(
+                               'nom' => "saisie_modifiee_${nom}[verifier][type]",
+                               'label' => _T('saisies:construire_verifications_label'),
+                               'option_intro' => _T('saisies:construire_verifications_aucune'),
+                               'li_class' => 'liste_verifications',
+                               'datas' => array()
+                       )
+               );
+
+               foreach ($liste_verifications as $type_verif => $verif){
+                       $saisie_liste_verif['options']['datas'][$type_verif] = $verif['titre'];
+                       // Si le type de vérif a des options, on ajoute un fieldset
+                       if (isset($verif['options']) and $verif['options'] and is_array($verif['options'])){
+                               $groupe = array(
+                                       'saisie' => 'fieldset',
+                                       'options' => array(
+                                               'nom' => 'options',
+                                               'label' => $verif['titre'],
+                                               'li_class' => "$type_verif options_verifier"
+                                       ),
+                                       'saisies' => $verif['options']
+                               );
+                               array_walk_recursive($groupe, 'formidable_transformer_nom', "saisie_modifiee_${nom}[verifier][$type_verif][@valeur@]");
+                               $verif_options[$type_verif] = $groupe;
+                       }
+               }
+               $verif_options = array_merge(array($saisie_liste_verif), $verif_options);
+       }
+       
+       
+       if ($enregistrer_saisie){
+               // La saisie modifié
+               $saisie_modifiee = _request("saisie_modifiee_${nom}");
+               // On cherche les erreurs de la configuration
+               $vraies_erreurs = saisies_verifier($formulaire_config);
+               // Si on autorise à modifier le nom ET qu'il doit être unique : on vérifie
+               if (isset($options['modifier_nom']) and $options['modifier_nom']
+                 and isset($options['nom_unique']) and $options['nom_unique'])
+               {
+                       $nom_modifie = $saisie_modifiee['options']['nom'];
+                       if ($nom_modifie != $enregistrer_saisie and saisies_chercher($formulaire_actuel, $nom_modifie))
+                               $vraies_erreurs["saisie_modifiee_${nom}[options][nom]"] = _T('saisies:erreur_option_nom_unique');
+               }
+               // On regarde s'il a été demandé un type de vérif
+               if (isset($saisie_modifiee['verifier']['type'])
+                 and (($type_verif = $saisie_modifiee['verifier']['type']) != '')
+                 and $verif_options[$type_verif])
+               {
+                       // On ne vérifie que les options du type demandé
+                       $vraies_erreurs = array_merge($vraies_erreurs, saisies_verifier($verif_options[$type_verif]['saisies']));
+               }
+       }
+       
+       // On insère chaque saisie des options de verification
+       if ($verif_options){
+               foreach ($verif_options as $saisie_verif){
+                       $formulaire_config = saisies_inserer($formulaire_config, $saisie_verif, $chemin_validation);
+               }
+       }
+       $erreurs['configurer_'.$nom] = $formulaire_config;
+       $erreurs['positionner'] = '#configurer_'.$nom;
+       
+       if ($enregistrer_saisie) {
+               if ($vraies_erreurs)
+                       $erreurs = array_merge($erreurs, $vraies_erreurs);
+               else
+                       $erreurs = array();
+       }
+       
+       return $erreurs;
+}
+
+function formulaires_construire_formulaire_traiter($identifiant, $formulaire_initial=array(), $options=array()){
+       include_spip('inc/saisies');
+       $retours = array();
+       $saisies_disponibles = saisies_lister_disponibles();
+       
+       // On ajoute un préfixe devant l'identifiant
+       $identifiant = 'constructeur_formulaire_'.$identifiant;
+       // On récupère le formulaire à son état actuel
+       $formulaire_actuel = session_get($identifiant);
+       
+       // Si on demande à ajouter une saisie
+       if ($ajouter_saisie = _request('ajouter_saisie')){
+               $nom = saisies_generer_nom($formulaire_actuel, $ajouter_saisie);
+               $saisie = array(
+                       'saisie' => $ajouter_saisie,
+                       'options' => array(
+                               'nom' => $nom
+                       )
+               );
+               // S'il y a des valeurs par défaut pour ce type de saisie, on les ajoute
+               if (($defaut = $saisies_disponibles[$ajouter_saisie]['defaut']) and is_array($defaut)){
+                       $defaut = _T_ou_typo($defaut, 'multi');
+
+                       //Compatibilite PHP<5.3.0 
+                       //source : http://www.php.net/manual/en/function.array-replace-recursive.php#92574
+                       if (!function_exists('array_replace_recursive'))
+                       {
+                               function array_replace_recursive($array, $array1)
+                               {
+                                       function recurse($array, $array1)
+                                       {
+                                               foreach ($array1 as $key => $value)
+                                               {
+                                                       // create new key in $array, if it is empty or not an array
+                                                       if (!isset($array[$key]) || (isset($array[$key]) && !is_array($array[$key])))
+                                                       {
+                                                               $array[$key] = array();
+                                                       }
+                                                       // overwrite the value in the base array
+                                                       if (is_array($value))
+                                                       {
+                                                               $value = recurse($array[$key], $value);
+                                                       }
+                                                       $array[$key] = $value;
+                                               }
+                                               return $array;
+                                       }
+                                       // handle the arguments, merge one by one
+                                       $args = func_get_args();
+                                       $array = $args[0];
+                                       if (!is_array($array))
+                                       {
+                                               return $array;
+                                       }
+                                       for ($i = 1; $i < count($args); $i++)
+                                       {
+                                               if (is_array($args[$i]))
+                                               {
+                                                       $array = recurse($array, $args[$i]);
+                                               }
+                                       }
+                               return $array;
+                               }
+                       }
+                       $saisie = array_replace_recursive($saisie, $defaut);
+               }
+               $formulaire_actuel = saisies_inserer($formulaire_actuel, $saisie);
+       }
+
+       // Si on demande à dupliquer une saisie
+       if ($dupliquer_saisie = _request('dupliquer_saisie')) {
+               $formulaire_actuel = saisies_dupliquer($formulaire_actuel, $dupliquer_saisie);  
+       }
+       
+       // Si on demande à supprimer une saisie
+       if ($supprimer_saisie = _request('supprimer_saisie')){
+               $formulaire_actuel = saisies_supprimer($formulaire_actuel, $supprimer_saisie);
+       }
+       
+       // Si on enregistre la conf d'une saisie
+       if ($nom = _request('enregistrer_saisie')){
+               // On récupère ce qui a été modifié
+               $saisie_modifiee = _request("saisie_modifiee_$nom");
+               
+               // On regarde s'il y a une position à modifier
+               if (isset($saisie_modifiee['position'])){
+                       $position = $saisie_modifiee['position'];
+                       unset($saisie_modifiee['position']);
+                       // On ne déplace que si ce n'est pas la même chose
+                       if ($position != $nom)
+                               $formulaire_actuel = saisies_deplacer($formulaire_actuel, $nom, $position);
+               }
+               
+               // On regarde s'il y a des options de vérification à modifier
+               if (isset($saisie_modifiee['verifier']['type'])
+                 and ($type_verif = $saisie_modifiee['verifier']['type']) != '')
+               {
+                       $saisie_modifiee['verifier'] = array(
+                               'type' => $type_verif,
+                               'options' => $saisie_modifiee['verifier'][$type_verif]
+                       );
+               }
+               else {
+                       unset($saisie_modifiee['verifier']);
+               }
+
+               // On récupère les options postées en enlevant les chaines vides
+               $saisie_modifiee['options'] = array_filter($saisie_modifiee['options'], 'saisie_option_contenu_vide');
+               if (isset($saisie_modifiee['verifier']['options']) and $saisie_modifiee['verifier']['options']) {
+                       $saisie_modifiee['verifier']['options'] = array_filter($saisie_modifiee['verifier']['options'], 'saisie_option_contenu_vide');
+               }
+               
+               // On désinfecte à la main
+               if (is_array($saisie_modifiee['options']))
+                       spip_desinfecte($saisie_modifiee['options']);
+               
+               // On modifie enfin
+               $formulaire_actuel = saisies_modifier($formulaire_actuel, $nom, $saisie_modifiee);
+       }
+       
+       // Si on demande à réinitialiser
+       if (_request('reinitialiser') == 'oui'){
+               $formulaire_actuel = $formulaire_initial;
+       }
+       
+       // On enregistre en session la nouvelle version du formulaire
+       session_set($identifiant, $formulaire_actuel);
+       
+       // Le formulaire reste éditable
+       $retours['editable'] = true;
+       
+       return $retours;
+}
+
+// À utiliser avec un array_walk_recursive()
+// Applique une transformation à la @valeur@ de tous les champs "nom" d'un formulaire, y compris loin dans l'arbo
+function formidable_transformer_nom(&$valeur, $cle, $transformation){
+       if ($cle == 'nom' and is_string($valeur)){
+               $valeur = str_replace('@valeur@', $valeur, $transformation);
+       }
+}
+
+// Préparer une saisie pour la transformer en truc configurable
+function formidable_generer_saisie_configurable($saisie, $env){
+       // On récupère le nom
+       $nom = $saisie['options']['nom'];
+       $identifiant = $saisie['identifiant'];
+       // On cherche si ya un formulaire de config
+       $formulaire_config = isset($env['erreurs']['configurer_'.$nom]) ? $env['erreurs']['configurer_'.$nom] : "";
+       // On ajoute une classe
+       if (!isset($saisie['options']['li_class'])) {
+               $saisie['options']['li_class'] = ''; // initialisation
+       }
+       $saisie['options']['li_class'] .= ' configurable';
+       // On ajoute l'option "tout_afficher"
+       $saisie['options']['tout_afficher'] = 'oui';
+       
+       // On ajoute les boutons d'actions, mais seulement s'il n'y a pas de configuration de lancée
+       if (!$env['erreurs']) {
+               $saisie = saisies_inserer_html(
+                       $saisie,
+                       recuperer_fond(
+                               'formulaires/inc-construire_formulaire-actions',
+                               array(
+                                       'nom' => $nom,
+                                       'identifiant' => $identifiant, 
+                                       'formulaire_config' => $formulaire_config,
+                                       'deplacable' => $env['_chemin_ui']
+                               )
+                       ),
+                       'debut'
+               );
+       }
+       
+       // On ajoute une ancre pour s'y déplacer
+       $saisie = saisies_inserer_html(
+               $saisie,
+               "\n<a id=\"configurer_$nom\"></a>\n",
+               'debut'
+       );
+       
+       // Si ya un form de config on l'ajoute à la fin
+       if (is_array($formulaire_config)){
+               // On double l'environnement
+               $env2 = $env;
+               // On ajoute une classe
+               $saisie['options']['li_class'] .= ' en_configuration';
+               
+               // Si possible on met en readonly
+               $saisie['options']['readonly'] = 'oui';
+               
+               // On vire les sous-saisies s'il y en a
+               if (isset($saisie['saisies']) and $saisie['saisies'] and is_array($saisie['saisies'])){
+                       $nb_champs_masques = count(saisies_lister_champs($saisie['saisies']));
+                       $saisie['saisies'] = array(
+                               array(
+                                       'saisie' => 'explication',
+                                       'options' => array(
+                                               'nom' => 'truc',
+                                               'texte' => _T('saisies:construire_info_nb_champs_masques', array('nb'=>$nb_champs_masques)),
+                                       )
+                               )
+                       );
+               }
+               
+               // On va ajouter le champ pour la position
+               if (!($chemin_description = saisies_chercher($formulaire_config, "saisie_modifiee_${nom}[options][description]", true))){
+                       $chemin_description = array(0);
+                       $formulaire_config = saisies_inserer(
+                               $formulaire_config,
+                               array(
+                                       'saisie' => 'fieldset',
+                                       'options' => array(
+                                               'nom' => "saisie_modifiee_${nom}[options][description]",
+                                               'label' => _T('saisies:option_groupe_description')
+                                       ),
+                                       'saisies' => array()
+                               ),
+                               0
+                       );
+               }
+               $chemin_description[] = 'saisies';
+               $chemin_description[] = '0'; // tout au début
+               $formulaire_config = saisies_inserer(
+                       $formulaire_config,
+                       array(
+                               'saisie' => 'position_construire_formulaire',
+                               'options' => array(
+                                       'nom' => "saisie_modifiee_${nom}[position]",
+                                       'label' => _T('saisies:construire_position_label'),
+                                       'explication' => _T('saisies:construire_position_explication'),
+                                       'formulaire' => $env['_contenu'],
+                                       'saisie_a_positionner' => $nom
+                               )
+                       ),
+                       $chemin_description
+               );
+               
+               $env2['saisies'] = $formulaire_config;
+               
+               // Un test pour savoir si on prend le _request ou bien
+               $erreurs_test = $env['erreurs'];
+               unset($erreurs_test['configurer_'.$nom]);
+               unset($erreurs_test['positionner']);
+               if ($erreurs_test){
+                       // Là aussi on désinfecte à la main
+                       if (is_array($env2["saisie_modifiee_$nom"]['options']))
+                               spip_desinfecte($env2["saisie_modifiee_$nom"]['options']);
+               }
+               else{
+                       $env2["saisie_modifiee_$nom"] = $env2['_saisies_par_nom'][$nom];
+                       // il n'y a pas toujours de verification...
+                       if (isset($env2["saisie_modifiee_$nom"]['verifier'])) {
+                               $env2["saisie_modifiee_$nom"]['verifier'][ $env2["saisie_modifiee_$nom"]['verifier']['type'] ]
+                                       = $env2["saisie_modifiee_$nom"]['verifier']['options'];
+                       }
+               }
+               
+               $env2['fond_generer'] = 'inclure/generer_saisies';
+               $saisie = saisies_inserer_html(
+                       $saisie,
+                       '<div class="formulaire_configurer"><ul class="formulaire_configurer-contenus">'
+                       .recuperer_fond(
+                               'inclure/generer_saisies',
+                               $env2
+                       )
+                       .'<li class="boutons">
+                               <input type="hidden" name="enregistrer_saisie" value="'.$nom.'" />
+                               <button type="submit" class="submit link" name="enregistrer_saisie" value="">'._T('bouton_annuler').'</button>
+                               <input type="submit" class="submit" name="enregistrer" value="'._T('bouton_valider').'" />
+                       </li>'
+                       .'</ul></div>',
+                       'fin'
+               );
+       }
+       // On génère le HTML de la saisie
+       $html = saisies_generer_html($saisie, $env);
+       return $html;
+}
+
+/**
+ * Callback d'array_filter()
+ * Permet de retourner tout ce qui n'est pas un contenu vide.
+ * La valeur '0' est par contre retournée.
+ *
+ * @param $var La variable a tester
+ * @return bool L'accepte-t-on ?
+**/
+function saisie_option_contenu_vide($var) {
+       if (!$var) {
+               if (is_string($var) AND strlen($var)) {
+                       return true;
+               }
+               return false;
+       }
+       return true;
+}
+?>
diff --git a/www/plugins/saisies/formulaires/inc-construire_formulaire-actions.html b/www/plugins/saisies/formulaires/inc-construire_formulaire-actions.html
new file mode 100644 (file)
index 0000000..faaedc4
--- /dev/null
@@ -0,0 +1,27 @@
+<div class="actions">
+       #SET{nom,#ENV{identifiant,#ENV{nom}}}
+       [(#ENV{formulaire_config}|is_array|non)
+       [(#ENV{deplacable}|oui)
+       <span class="move deplacer_saisie" title="<:saisies:construire_action_deplacer:>">
+               <img src="[(#CHEMIN{images/formulaire-deplacer-16.png})]" alt="<:saisies:construire_action_deplacer:>"/>
+       </span>
+       ]
+       <button type="submit" class="submit configurer_saisie" name="configurer_saisie" value="#GET{nom}" title="<:saisies:construire_action_configurer:>">
+               <img src="[(#CHEMIN{images/formulaire-configurer-16.png})]" alt="<:saisies:construire_action_configurer:>"/>
+       </button>
+       <button type="submit" class="submit dupliquer_saisie" name="dupliquer_saisie" value="#GET{nom}" title="<:saisies:construire_action_dupliquer:>">
+               <img src="[(#CHEMIN{images/formulaire-dupliquer-16.png})]" alt="<:saisies:construire_action_dupliquer:>"/>
+       </button>
+       <button type="submit" class="submit supprimer_saisie" name="supprimer_saisie" value="#GET{nom}" title="<:saisies:construire_action_supprimer:>" onclick="javascript:return confirm('<:saisies:construire_confirmer_supprimer_champ:>');">
+               <img src="[(#CHEMIN{images/formulaire-supprimer-16.png})]" alt="<:saisies:construire_action_supprimer:>"/>
+       </button>
+       ]
+       [(#ENV{formulaire_config}|is_array|oui)
+       <button type="submit" class="submit enregistrer_saisie" name="enregistrer_saisie" value="#GET{nom}" title="<:bouton_enregistrer:>">
+               <img src="[(#CHEMIN{images/formulaire-enregistrer-16.png})]" alt="<:bouton_enregistrer:>"/>
+       </button>
+       <button type="submit" class="submit annuler" name="enregistrer_saisie" value="" title="<:saisies:construire_action_annuler:>">
+               <img src="[(#CHEMIN{images/formulaire-annuler-16.png})]" alt="<:saisies:construire_action_annuler:>"/>
+       </button>
+       ]
+</div>
diff --git a/www/plugins/saisies/formulaires/inc-generer_saisies_configurables.html b/www/plugins/saisies/formulaires/inc-generer_saisies_configurables.html
new file mode 100644 (file)
index 0000000..fbb0c00
--- /dev/null
@@ -0,0 +1,9 @@
+[(#REM) 
+  Exemple d'appel :
+    #INCLURE{fond=formulaires/inc-generer_saisies_configurables, env, fond_generer=formulaires/inc-generer_saisies_configurables, saisies=#ENV{tableau}}
+]
+<BOUCLE_contenu(POUR){tableau #ENV{saisies}}>
+[(#VAL{saisie}|array_key_exists{#VALEUR}|oui)
+       [(#VALEUR**|formidable_generer_saisie_configurable{#ENV{_env}|sinon{#ENV**|unserialize}})]
+]
+</BOUCLE_contenu>
diff --git a/www/plugins/saisies/formulaires/inc-saisies-cvt.html b/www/plugins/saisies/formulaires/inc-saisies-cvt.html
new file mode 100644 (file)
index 0000000..b87cb54
--- /dev/null
@@ -0,0 +1,24 @@
+<div class="formulaire_spip formulaire_#ENV{form}">\r
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]\r
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV**{message_erreur})</p>]\r
+       \r
+       [(#ENV{editable}|oui)\r
+       <form method="post" action="#ENV{action}" enctype="multipart/form-data"><div>\r
+               [(#REM) declarer les hidden qui declencheront le service du formulaire \r
+               parametre : url d'action ]\r
+               #ACTION_FORMULAIRE{#ENV{action}}\r
+               \r
+               <ul>\r
+                       #GENERER_SAISIES{#ENV{_saisies}}\r
+               </ul>\r
+               \r
+               [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]\r
+               <!--extra-->\r
+               \r
+               <p class="boutons">\r
+                       <span class="image_loading"></span>\r
+                       <input type="submit" class="submit" value="[(#ENV{saisies_texte_submit}|sinon{<:bouton_enregistrer:>})]" />\r
+               </p>\r
+       </div></form>\r
+       ]\r
+</div>\r
diff --git a/www/plugins/saisies/formulaires/saisies_cvt.html b/www/plugins/saisies/formulaires/saisies_cvt.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/www/plugins/saisies/formulaires/saisies_cvt.php b/www/plugins/saisies/formulaires/saisies_cvt.php
new file mode 100644 (file)
index 0000000..582fa56
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+function formulaires_saisies_cvt_saisies_dist(){
+       return array(
+               array(
+                       'saisie' => 'input',
+                       'options' => array(
+                               'nom' => 'nom',
+                               'label' => 'Nom'
+                       )
+               ),
+               array(
+                       'saisie' => 'input',
+                       'options' => array(
+                               'nom' => 'email',
+                               'obligatoire' => 'oui',
+                               'label' => 'E-mail'
+                       ),
+                       'verifier' => array(
+                               'type' => 'email'
+                       )
+               ),
+               array(
+                       'saisie' => 'textarea',
+                       'options' => array(
+                               'nom' => 'message',
+                               'obligatoire' => 'oui',
+                               'label' => 'Un message'
+                       ),
+                       'verifier' => array(
+                               'type' => 'taille',
+                               'options' => array('min' => 10)
+                       )
+               )
+       );
+}
+
+?>
diff --git a/www/plugins/saisies/images/formulaire-annuler-16.png b/www/plugins/saisies/images/formulaire-annuler-16.png
new file mode 100644 (file)
index 0000000..1af591c
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-annuler-16.png differ
diff --git a/www/plugins/saisies/images/formulaire-configurer-16.png b/www/plugins/saisies/images/formulaire-configurer-16.png
new file mode 100644 (file)
index 0000000..36a909b
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-configurer-16.png differ
diff --git a/www/plugins/saisies/images/formulaire-deplacer-16.png b/www/plugins/saisies/images/formulaire-deplacer-16.png
new file mode 100644 (file)
index 0000000..6e13dd3
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-deplacer-16.png differ
diff --git a/www/plugins/saisies/images/formulaire-dupliquer-16.png b/www/plugins/saisies/images/formulaire-dupliquer-16.png
new file mode 100644 (file)
index 0000000..f9f4e9b
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-dupliquer-16.png differ
diff --git a/www/plugins/saisies/images/formulaire-enregistrer-16.png b/www/plugins/saisies/images/formulaire-enregistrer-16.png
new file mode 100644 (file)
index 0000000..06b2491
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-enregistrer-16.png differ
diff --git a/www/plugins/saisies/images/formulaire-reinitialiser-24.png b/www/plugins/saisies/images/formulaire-reinitialiser-24.png
new file mode 100644 (file)
index 0000000..5dce298
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-reinitialiser-24.png differ
diff --git a/www/plugins/saisies/images/formulaire-saisie-defaut.png b/www/plugins/saisies/images/formulaire-saisie-defaut.png
new file mode 100644 (file)
index 0000000..6a0e70a
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-saisie-defaut.png differ
diff --git a/www/plugins/saisies/images/formulaire-supprimer-16.png b/www/plugins/saisies/images/formulaire-supprimer-16.png
new file mode 100644 (file)
index 0000000..6f4a6a6
Binary files /dev/null and b/www/plugins/saisies/images/formulaire-supprimer-16.png differ
diff --git a/www/plugins/saisies/images/logo_saisie_48.png b/www/plugins/saisies/images/logo_saisie_48.png
new file mode 100644 (file)
index 0000000..e1e6f37
Binary files /dev/null and b/www/plugins/saisies/images/logo_saisie_48.png differ
diff --git a/www/plugins/saisies/images/saisies_auteurs.png b/www/plugins/saisies/images/saisies_auteurs.png
new file mode 100644 (file)
index 0000000..6fdf70d
Binary files /dev/null and b/www/plugins/saisies/images/saisies_auteurs.png differ
diff --git a/www/plugins/saisies/images/saisies_case.png b/www/plugins/saisies/images/saisies_case.png
new file mode 100644 (file)
index 0000000..71565b0
Binary files /dev/null and b/www/plugins/saisies/images/saisies_case.png differ
diff --git a/www/plugins/saisies/images/saisies_checkbox.png b/www/plugins/saisies/images/saisies_checkbox.png
new file mode 100644 (file)
index 0000000..8f0a9bf
Binary files /dev/null and b/www/plugins/saisies/images/saisies_checkbox.png differ
diff --git a/www/plugins/saisies/images/saisies_date.png b/www/plugins/saisies/images/saisies_date.png
new file mode 100644 (file)
index 0000000..96ef9a4
Binary files /dev/null and b/www/plugins/saisies/images/saisies_date.png differ
diff --git a/www/plugins/saisies/images/saisies_explication.png b/www/plugins/saisies/images/saisies_explication.png
new file mode 100644 (file)
index 0000000..be5c134
Binary files /dev/null and b/www/plugins/saisies/images/saisies_explication.png differ
diff --git a/www/plugins/saisies/images/saisies_fieldset.png b/www/plugins/saisies/images/saisies_fieldset.png
new file mode 100644 (file)
index 0000000..f9efaca
Binary files /dev/null and b/www/plugins/saisies/images/saisies_fieldset.png differ
diff --git a/www/plugins/saisies/images/saisies_hidden.png b/www/plugins/saisies/images/saisies_hidden.png
new file mode 100644 (file)
index 0000000..cb552bf
Binary files /dev/null and b/www/plugins/saisies/images/saisies_hidden.png differ
diff --git a/www/plugins/saisies/images/saisies_input.png b/www/plugins/saisies/images/saisies_input.png
new file mode 100644 (file)
index 0000000..ccaa722
Binary files /dev/null and b/www/plugins/saisies/images/saisies_input.png differ
diff --git a/www/plugins/saisies/images/saisies_oui_non.png b/www/plugins/saisies/images/saisies_oui_non.png
new file mode 100644 (file)
index 0000000..a32b607
Binary files /dev/null and b/www/plugins/saisies/images/saisies_oui_non.png differ
diff --git a/www/plugins/saisies/images/saisies_radio.png b/www/plugins/saisies/images/saisies_radio.png
new file mode 100644 (file)
index 0000000..c85d949
Binary files /dev/null and b/www/plugins/saisies/images/saisies_radio.png differ
diff --git a/www/plugins/saisies/images/saisies_selecteur_article.png b/www/plugins/saisies/images/saisies_selecteur_article.png
new file mode 100644 (file)
index 0000000..24eece2
Binary files /dev/null and b/www/plugins/saisies/images/saisies_selecteur_article.png differ
diff --git a/www/plugins/saisies/images/saisies_selecteur_rubrique.png b/www/plugins/saisies/images/saisies_selecteur_rubrique.png
new file mode 100644 (file)
index 0000000..026a114
Binary files /dev/null and b/www/plugins/saisies/images/saisies_selecteur_rubrique.png differ
diff --git a/www/plugins/saisies/images/saisies_selecteur_rubrique_article.png b/www/plugins/saisies/images/saisies_selecteur_rubrique_article.png
new file mode 100644 (file)
index 0000000..77acfe3
Binary files /dev/null and b/www/plugins/saisies/images/saisies_selecteur_rubrique_article.png differ
diff --git a/www/plugins/saisies/images/saisies_selection.png b/www/plugins/saisies/images/saisies_selection.png
new file mode 100644 (file)
index 0000000..dab25d3
Binary files /dev/null and b/www/plugins/saisies/images/saisies_selection.png differ
diff --git a/www/plugins/saisies/images/saisies_selection_multiple.png b/www/plugins/saisies/images/saisies_selection_multiple.png
new file mode 100644 (file)
index 0000000..d682108
Binary files /dev/null and b/www/plugins/saisies/images/saisies_selection_multiple.png differ
diff --git a/www/plugins/saisies/images/saisies_textarea.png b/www/plugins/saisies/images/saisies_textarea.png
new file mode 100644 (file)
index 0000000..84277b8
Binary files /dev/null and b/www/plugins/saisies/images/saisies_textarea.png differ
diff --git a/www/plugins/saisies/inc/saisies.php b/www/plugins/saisies/inc/saisies.php
new file mode 100644 (file)
index 0000000..4a713a5
--- /dev/null
@@ -0,0 +1,406 @@
+<?php\r
+\r
+/**\r
+ * Gestion de l'affichage des saisies\r
+ *\r
+ * @return SPIP\Saisies\Saisies\r
+**/\r
+\r
+// Sécurité\r
+if (!defined('_ECRIRE_INC_VERSION')) return;\r
+\r
+/*\r
+ * Une librairie pour manipuler ou obtenir des infos sur un tableau de saisies\r
+ *\r
+ * saisies_lister_par_nom()\r
+ * saisies_lister_champs()\r
+ * saisies_lister_valeurs_defaut()\r
+ * saisies_charger_champs()\r
+ * saisies_chercher()\r
+ * saisies_supprimer()\r
+ * saisies_inserer()\r
+ * saisies_deplacer()\r
+ * saisies_modifier()\r
+ * saisies_verifier()\r
+ * saisies_comparer()\r
+ * saisies_generer_html()\r
+ * saisies_generer_vue()\r
+ * saisies_generer_nom()\r
+ * saisies_inserer_html()\r
+ * saisies_lister_disponibles()\r
+ * saisies_autonomes()\r
+ */\r
+\r
+// Différentes méthodes pour trouver les saisies\r
+include_spip('inc/saisies_lister');\r
+\r
+// Différentes méthodes pour manipuler une liste de saisies\r
+include_spip('inc/saisies_manipuler');\r
+\r
+// Les outils pour afficher les saisies et leur vue\r
+include_spip('inc/saisies_afficher');\r
+\r
+/*\r
+ * Cherche la description des saisies d'un formulaire CVT dont on donne le nom\r
+ *\r
+ * @param string $form Nom du formulaire dont on cherche les saisies\r
+ * @return array Retourne les saisies du formulaire sinon false\r
+ */\r
+function saisies_chercher_formulaire($form, $args){\r
+       if ($fonction_saisies = charger_fonction('saisies', 'formulaires/'.$form, true)\r
+               and $saisies = call_user_func_array($fonction_saisies, $args)\r
+               and is_array($saisies)\r
+               // On passe les saisies dans un pipeline normé comme pour CVT\r
+               and $saisies = pipeline(\r
+                       'formulaire_saisies',\r
+                       array(\r
+                               'args' => array('form' => $form, 'args' => $args),\r
+                               'data' => $saisies\r
+                       )\r
+               )\r
+               // Si c'est toujours un tableau après le pipeline\r
+               and is_array($saisies)\r
+       ){\r
+               return $saisies;\r
+       }\r
+       else{\r
+               return false;\r
+       }\r
+}\r
+\r
+/*\r
+ * Cherche une saisie par son id, son nom ou son chemin et renvoie soit la saisie, soit son chemin\r
+ *\r
+ * @param array $saisies Un tableau décrivant les saisies\r
+ * @param unknown_type $id_ou_nom_ou_chemin L'identifiant ou le nom de la saisie à chercher ou le chemin sous forme d'une liste de clés\r
+ * @param bool $retourner_chemin Indique si on retourne non pas la saisie mais son chemin\r
+ * @return array Retourne soit la saisie, soit son chemin, soit null\r
+ */\r
+function saisies_chercher($saisies, $id_ou_nom_ou_chemin, $retourner_chemin=false){\r
+\r
+       if (is_array($saisies) and $id_ou_nom_ou_chemin){\r
+               if (is_string($id_ou_nom_ou_chemin)){\r
+                       $nom = $id_ou_nom_ou_chemin;\r
+                       // identifiant ? premier caractere @\r
+                       $id = ($nom[0] == '@');\r
+\r
+                       foreach($saisies as $cle => $saisie){\r
+                               $chemin = array($cle);\r
+                               // notre saisie est la bonne ?\r
+                               if ($nom == ($id ? $saisie['identifiant'] : $saisie['options']['nom'])) {\r
+                                       return $retourner_chemin ? $chemin : $saisie;\r
+                               // sinon a telle des enfants ? et si c'est le cas, cherchons dedans\r
+                               } elseif (isset($saisie['saisies']) and is_array($saisie['saisies']) and $saisie['saisies']\r
+                                       and ($retour = saisies_chercher($saisie['saisies'], $nom, $retourner_chemin))) {\r
+                                               return $retourner_chemin ? array_merge($chemin, array('saisies'), $retour) : $retour;\r
+                               }\r
+\r
+                       }\r
+               }\r
+               elseif (is_array($id_ou_nom_ou_chemin)){\r
+                       $chemin = $id_ou_nom_ou_chemin;\r
+                       $saisie = $saisies;\r
+                       // On vérifie l'existence quand même\r
+                       foreach ($chemin as $cle){\r
+                               if (isset($saisie[$cle])) $saisie = $saisie[$cle];\r
+                               else return null;\r
+                       }\r
+                       // Si c'est une vraie saisie\r
+                       if ($saisie['saisie'] and $saisie['options']['nom'])\r
+                               return $retourner_chemin ? $chemin : $saisie;\r
+               }\r
+       }\r
+       \r
+       return null;\r
+}\r
+\r
+/**\r
+ * Génère un nom unique pour un champ d'un formulaire donné\r
+ *\r
+ * @param array $formulaire\r
+ *     Le formulaire à analyser \r
+ * @param string $type_saisie\r
+ *     Le type de champ dont on veut un identifiant \r
+ * @return string\r
+ *     Un nom unique par rapport aux autres champs du formulaire\r
+ */\r
+function saisies_generer_nom($formulaire, $type_saisie){\r
+       $champs = saisies_lister_champs($formulaire);\r
+       \r
+       // Tant que type_numero existe, on incrémente le compteur\r
+       $compteur = 1;\r
+       while (array_search($type_saisie.'_'.$compteur, $champs) !== false)\r
+               $compteur++;\r
+       \r
+       // On a alors un compteur unique pour ce formulaire\r
+       return $type_saisie.'_'.$compteur;\r
+}\r
+\r
+/*\r
+ * Crée un identifiant Unique\r
+ * pour toutes les saisies donnees qui n'en ont pas \r
+ *\r
+ * @param Array $saisies Tableau de saisies\r
+ * @param Bool $regenerer_id Régénère un nouvel identifiant pour toutes les saisies ?\r
+ * @return Array Tableau de saisies complété des identifiants\r
+ */\r
+function saisies_identifier($saisies, $regenerer = false) {\r
+       if (!is_array($saisies)) {\r
+               return array();\r
+       }\r
+       foreach ($saisies as $k => $saisie) {\r
+               $saisies[$k] = saisie_identifier($saisie, $regenerer);\r
+       }\r
+       return $saisies;\r
+}\r
+\r
+/**\r
+ * Crée un identifiant Unique\r
+ * pour la saisie donnee si elle n'en a pas\r
+ * (et pour ses sous saisies éventuels)\r
+ *\r
+ * @param Array $saisie Tableau d'une saisie\r
+ * @param Bool $regenerer_id Régénère un nouvel identifiant pour la saisie ?\r
+ * @return Array Tableau de la saisie complété de l'identifiant\r
+**/\r
+function saisie_identifier($saisie, $regenerer = false) {\r
+       if (!isset($saisie['identifiant']) OR !$saisie['identifiant']) {\r
+               $saisie['identifiant'] = uniqid('@');\r
+       } elseif ($regenerer) {\r
+               $saisie['identifiant'] = uniqid('@');\r
+       }\r
+       if (isset($saisie['saisies']) AND is_array($saisie['saisies'])) {\r
+               $saisie['saisies'] = saisies_identifier($saisie['saisies'], $regenerer);\r
+       }\r
+       return $saisie;\r
+}\r
+\r
+/*\r
+ * Vérifier tout un formulaire tel que décrit avec les Saisies\r
+ *\r
+ * @param array $formulaire Le contenu d'un formulaire décrit dans un tableau de Saisies\r
+ * @param bool $saisies_masquees_nulles Si TRUE, les saisies masquées selon afficher_si ne seront pas verifiées, leur valeur étant forcée a NULL. Cette valeur NULL est transmise à traiter (via set_request).\r
+ * @return array Retourne un tableau d'erreurs\r
+ */\r
+function saisies_verifier($formulaire, $saisies_masquees_nulles=true){\r
+       include_spip('inc/verifier');\r
+       $erreurs = array();\r
+       $verif_fonction = charger_fonction('verifier','inc',true);\r
+\r
+       if ($saisies_masquees_nulles)\r
+               $formulaire = saisies_verifier_afficher_si($formulaire);\r
+       \r
+       $saisies = saisies_lister_par_nom($formulaire);\r
+       foreach ($saisies as $saisie){\r
+               $obligatoire = isset($saisie['options']['obligatoire']) ? $saisie['options']['obligatoire'] : '';\r
+               $champ = $saisie['options']['nom'];\r
+               $file = ($saisie['saisie'] == 'input' and isset($saisie['options']['type']) and $saisie['options']['type'] == 'file');\r
+               $verifier = isset($saisie['verifier']) ? $saisie['verifier'] : false;\r
+\r
+               // Si le nom du champ est un tableau indexé, il faut parser !\r
+               if (preg_match('/([\w]+)((\[[\w]+\])+)/', $champ, $separe)){\r
+                       $valeur = _request($separe[1]);\r
+                       preg_match_all('/\[([\w]+)\]/', $separe[2], $index);\r
+                       // On va chercher au fond du tableau\r
+                       foreach($index[1] as $cle){\r
+                               $valeur = isset($valeur[$cle]) ? $valeur[$cle] : null;\r
+                       }\r
+               }\r
+               // Sinon la valeur est juste celle du nom\r
+               else\r
+                       $valeur = _request($champ);\r
+               \r
+               // On regarde d'abord si le champ est obligatoire\r
+               if ($obligatoire\r
+                       and $obligatoire != 'non'\r
+                       and (\r
+                               ($file and !$_FILES[$champ]['name'])\r
+                               or (!$file and (\r
+                                       is_null($valeur)\r
+                                       or (is_string($valeur) and trim($valeur) == '')\r
+                                       or (is_array($valeur) and count($valeur) == 0)\r
+                               ))\r
+                       )\r
+               ) {\r
+                       $erreurs[$champ] =\r
+                               (isset($saisie['options']['erreur_obligatoire']) and $saisie['options']['erreur_obligatoire'])\r
+                               ? $saisie['options']['erreur_obligatoire']\r
+                               : _T('info_obligatoire');\r
+               }\r
+\r
+               // On continue seulement si ya pas d'erreur d'obligation et qu'il y a une demande de verif\r
+               if ((!isset($erreurs[$champ]) or !$erreurs[$champ]) and is_array($verifier) and $verif_fonction){\r
+                       $normaliser = null;\r
+                       // Si le champ n'est pas valide par rapport au test demandé, on ajoute l'erreur\r
+                       $options = isset($verifier['options']) ? $verifier['options'] : array();\r
+                       if ($erreur_eventuelle = $verif_fonction($valeur, $verifier['type'], $options, $normaliser)) {\r
+                               $erreurs[$champ] = $erreur_eventuelle;\r
+                       // S'il n'y a pas d'erreur et que la variable de normalisation a été remplie, on l'injecte dans le POST\r
+                       } elseif (!is_null($normaliser)) {\r
+                               set_request($champ, $normaliser);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       return $erreurs;\r
+}\r
+\r
+/*\r
+ * Transforme une chaine en tableau avec comme principe :\r
+ * - une ligne devient une case\r
+ * - si la ligne est de la forme truc|bidule alors truc est la clé et bidule la valeur\r
+ *\r
+ * @param string $chaine Une chaine à transformer\r
+ * @return array Retourne un tableau PHP\r
+ */\r
+function saisies_chaine2tableau($chaine, $separateur="\n"){\r
+       if ($chaine and is_string($chaine)){\r
+               $tableau = array();\r
+               // On découpe d'abord en lignes\r
+               $lignes = explode($separateur, $chaine);\r
+               foreach ($lignes as $i=>$ligne){\r
+                       $ligne = trim(trim($ligne), '|');\r
+                       // Si ce n'est pas une ligne sans rien\r
+                       if ($ligne !== ''){\r
+                               // Si on trouve un découpage dans la ligne on fait cle|valeur\r
+                               if (strpos($ligne, '|') !== false){\r
+                                       list($cle,$valeur) = explode('|', $ligne, 2);\r
+                                       // permettre les traductions de valeurs au passage\r
+                                       $tableau[$cle] = _T_ou_typo($valeur, 'multi');\r
+                               }\r
+                               // Sinon on génère la clé\r
+                               else{\r
+                                       $tableau[$i] = $ligne;\r
+                               }\r
+                       }\r
+               }\r
+               return $tableau;\r
+       }\r
+       // Si c'est déjà un tableau on lui applique _T_ou_typo (qui fonctionne de manière récursive avant de le renvoyer\r
+       elseif (is_array($chaine)){\r
+               return _T_ou_typo($chaine, 'multi');\r
+       }\r
+       else{\r
+               return array();\r
+       }\r
+}\r
+\r
+/*\r
+ * Transforme un tableau en chaine de caractères avec comme principe :\r
+ * - une case de vient une ligne de la chaine\r
+ * - chaque ligne est générée avec la forme cle|valeur\r
+ */\r
+function saisies_tableau2chaine($tableau){\r
+       if ($tableau and is_array($tableau)){\r
+               $chaine = '';\r
+       \r
+               foreach($tableau as $cle=>$valeur){\r
+                       $ligne = trim("$cle|$valeur");\r
+                       $chaine .= "$ligne\n";\r
+               }\r
+               $chaine = trim($chaine);\r
+       \r
+               return $chaine;\r
+       }\r
+       // Si c'est déjà une chaine on la renvoie telle quelle\r
+       elseif (is_string($tableau)){\r
+               return $tableau;\r
+       }\r
+       else{\r
+               return '';\r
+       }\r
+}\r
+\r
+\r
+\r
+\r
+/**\r
+ * Passe une valeur en tableau d'élements si ce n'en est pas une\r
+ *\r
+ * entrée :\r
+ * cle|valeur\r
+ * cle|valeur\r
+ *\r
+ * Sinon :\r
+ * valeur,valeur\r
+ *\r
+ * @param mixed $valeur\r
+ * @return array Tableau de valeurs\r
+**/\r
+function saisies_valeur2tableau($valeur, $sinon_separateur="") {\r
+       if (is_array($valeur)) {\r
+               return $valeur;\r
+       }\r
+       \r
+       if (!strlen($valeur)) {\r
+               return array();\r
+       }\r
+       \r
+       $t = saisies_chaine2tableau($valeur);\r
+       if (count($t) > 1) {\r
+               return $t;\r
+       }\r
+\r
+       // qu'une seule valeur, c'est qu'elle a peut etre un separateur a virgule\r
+       // et a donc une cle est 0 dans ce cas la d'ailleurs\r
+       if (isset($t[0])) {\r
+               $t = saisies_chaine2tableau($t[0], ',');\r
+       }\r
+       \r
+       return $t;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+ * Génère une page d'aide listant toutes les saisies et leurs options\r
+ */\r
+function saisies_generer_aide(){\r
+       // On a déjà la liste par saisie\r
+       $saisies = saisies_lister_disponibles();\r
+       \r
+       // On construit une liste par options\r
+       $options = array();\r
+       foreach ($saisies as $type_saisie=>$saisie){\r
+               $options_saisie = saisies_lister_par_nom($saisie['options'], false);\r
+               foreach ($options_saisie as $nom=>$option){\r
+                       // Si l'option n'existe pas encore\r
+                       if (!isset($options[$nom])){\r
+                               $options[$nom] = _T_ou_typo($option['options']);\r
+                       }\r
+                       // On ajoute toujours par qui c'est utilisé\r
+                       $options[$nom]['utilisee_par'][] = $type_saisie;\r
+               }\r
+               ksort($options_saisie);\r
+               $saisies[$type_saisie]['options'] = $options_saisie;\r
+       }\r
+       ksort($options);\r
+       \r
+       return recuperer_fond(\r
+               'inclure/saisies_aide',\r
+               array(\r
+                       'saisies' => $saisies,\r
+                       'options' => $options\r
+               )\r
+       );\r
+}\r
+\r
+/*\r
+ * Le tableau de saisies a-t-il une option afficher_si ?\r
+ *\r
+ * @param array $saisies Un tableau de saisies\r
+ * @return boolean\r
+ */\r
+\r
+function saisies_afficher_si($saisies) {\r
+       $saisies = saisies_lister_par_nom($saisies,true);\r
+       // Dès qu'il y a au moins une option afficher_si, on l'active\r
+       foreach ($saisies as $saisie) {\r
+               if (isset($saisie['options']['afficher_si']))\r
+                       return true;\r
+       }\r
+       return false;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/saisies/inc/saisies_afficher.php b/www/plugins/saisies/inc/saisies_afficher.php
new file mode 100644 (file)
index 0000000..eb02b78
--- /dev/null
@@ -0,0 +1,421 @@
+<?php\r
+\r
+/**\r
+ * Gestion de l'affichage des saisies\r
+ *\r
+ * @return SPIP\Saisies\Afficher\r
+**/\r
+\r
+// Sécurité\r
+if (!defined('_ECRIRE_INC_VERSION')) return;\r
+\r
+/**\r
+ * Indique si une saisie peut être affichée.\r
+ * \r
+ * On s'appuie sur l'éventuelle clé "editable" du $champ.\r
+ * Si editable vaut :\r
+ *    - absent : le champ est éditable\r
+ *    - 1, le champ est éditable\r
+ *    - 0, le champ n'est pas éditable\r
+ *    - -1, le champ est éditable s'il y a du contenu dans le champ (l'environnement)\r
+ *         ou dans un de ses enfants (fieldsets)\r
+ *\r
+ * @param array $champ\r
+ *     Tableau de description de la saisie\r
+ * @param array $env\r
+ *     Environnement transmis à la saisie, certainement l'environnement du formulaire\r
+ * @param bool $utiliser_editable\r
+ *     - false pour juste tester le cas -1\r
+ * \r
+ * @return bool\r
+ *     Retourne un booléen indiquant l'état éditable ou pas :\r
+ *     - true si la saisie est éditable (peut être affichée)\r
+ *     - false sinon\r
+ */\r
+function saisie_editable($champ, $env, $utiliser_editable=true) {\r
+       if ($utiliser_editable) {\r
+               // si le champ n'est pas éditable, on sort.\r
+               if (!isset($champ['editable'])) {\r
+                       return true;\r
+               }\r
+               $editable = $champ['editable'];\r
+\r
+               if ($editable > 0) {\r
+                       return true;\r
+               }\r
+               if ($editable == 0) {\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       // cas -1\r
+       // name de la saisie\r
+       if (isset($champ['options']['nom'])) {\r
+               // si on a le name dans l'environnement, on le teste\r
+               $nom = $champ['options']['nom'];\r
+               if (isset($env[$nom])) {\r
+                       return $env[$nom] ? true : false ;\r
+               }\r
+       }\r
+       // sinon, si on a des sous saisies\r
+       if (isset($champ['saisies']) and is_array($champ['saisies'])) {\r
+               foreach($champ['saisies'] as $saisie) {\r
+                       if (saisie_editable($saisie, $env, false)) {\r
+                               return true;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       // aucun des paramètres demandés n'avait de contenu\r
+       return false;\r
+}\r
+\r
+/**\r
+ * Génère une saisie à partir d'un tableau la décrivant et de l'environnement\r
+ *\r
+ * @param array $champ\r
+ *     Description de la saisie.\r
+ *     Le tableau doit être de la forme suivante :\r
+ *     array(\r
+ *                     'saisie' => 'input',\r
+ *                     'options' => array(\r
+ *                             'nom' => 'le_name',\r
+ *                             'label' => 'Un titre plus joli',\r
+ *                             'obligatoire' => 'oui',\r
+ *                             'explication' => 'Remplissez ce champ en utilisant votre clavier.'\r
+ *                     )\r
+ *     )\r
+ * @param array $env\r
+ *     Environnement du formulaire\r
+ *     Permet de savoir les valeurs actuelles des contenus des saisies,\r
+ *     les erreurs eventuelles présentes...\r
+ * @return string\r
+ *     Code HTML des saisies de formulaire\r
+ */\r
+function saisies_generer_html($champ, $env=array()){\r
+       // Si le parametre n'est pas bon, on genere du vide\r
+       if (!is_array($champ))\r
+               return '';\r
+\r
+       // Si la saisie n'est pas editable, on sort aussi.\r
+       if (!saisie_editable($champ, $env)) {\r
+               return '';\r
+       }\r
+       \r
+       $contexte = array();\r
+       \r
+       // On sélectionne le type de saisie\r
+       $contexte['type_saisie'] = $champ['saisie'];\r
+       // Identifiant unique de saisie, si present\r
+       if (isset($champ['identifiant'])) {\r
+               $contexte['id_saisie'] = $champ['identifiant'];\r
+       }\r
+\r
+       // Peut-être des transformations à faire sur les options textuelles\r
+       $options = $champ['options'];\r
+       foreach ($options as $option => $valeur){\r
+               if ($option == 'datas') {\r
+                       // exploser une chaine datas en tableau (applique _T_ou_typo sur chaque valeur)\r
+                       $options[$option] = saisies_chaine2tableau($valeur);\r
+               } else {\r
+                       $options[$option] = _T_ou_typo($valeur, 'multi');\r
+               }\r
+       }\r
+       \r
+       // On ajoute les options propres à la saisie\r
+       $contexte = array_merge($contexte, $options);\r
+\r
+       // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement\r
+       if (isset($contexte['env']) or (isset($champ['saisies']) AND is_array($champ['saisies']))) {\r
+               unset($contexte['env']);\r
+\r
+               // on sauve l'ancien environnement\r
+               // car les sous-saisies ne doivent pas être affectees\r
+               // par les modification sur l'environnement servant à generer la saisie mère\r
+               $contexte['_env'] = $env;\r
+               \r
+               // À partir du moment où on passe tout l'environnement, il faut enlever certains éléments qui ne doivent absolument provenir que des options\r
+               unset($env['inserer_debut']);\r
+               unset($env['inserer_fin']);\r
+               $saisies_disponibles = saisies_lister_disponibles();\r
+               if (isset($saisies_disponibles[$contexte['type_saisie']]) and is_array($saisies_disponibles[$contexte['type_saisie']]['options'])) {\r
+                       $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);\r
+                       foreach ($options_a_supprimer as $option_a_supprimer){\r
+                               unset($env[$option_a_supprimer]);\r
+                       }\r
+               }\r
+               \r
+               $contexte = array_merge($env, $contexte);\r
+       }\r
+       // Sinon on ne sélectionne que quelques éléments importants\r
+       else{\r
+               // On récupère la liste des erreurs\r
+               $contexte['erreurs'] = $env['erreurs'];\r
+               // On ajoute toujours le bon self\r
+               $contexte['self'] = self();\r
+       }\r
+\r
+       // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ\r
+       // Si le nom du champ est un tableau indexé, il faut parser !\r
+       if (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){\r
+               $contexte['valeur'] = $env[$separe[1]];\r
+               preg_match_all('/\[([\w]+)\]/', $separe[2], $index);\r
+               // On va chercher au fond du tableau\r
+               foreach($index[1] as $cle){\r
+                       $contexte['valeur'] = isset($contexte['valeur'][$cle]) ? $contexte['valeur'][$cle] : null;\r
+               }\r
+       }\r
+       // Sinon la valeur est juste celle du nom\r
+       else {\r
+               $contexte['valeur'] = (isset($env[$contexte['nom']]) ? $env[$contexte['nom']] : null);\r
+       }\r
+\r
+       // Si ya des enfants on les remonte dans le contexte\r
+       if (isset($champ['saisies']) and is_array($champ['saisies']))\r
+               $contexte['saisies'] = $champ['saisies'];\r
+       \r
+       // On génère la saisie\r
+       return recuperer_fond(\r
+               'saisies/_base',\r
+               $contexte\r
+       );\r
+}\r
+\r
+/**\r
+ * Génère une vue d'une saisie à partir d'un tableau la décrivant\r
+ *\r
+ * @see saisies_generer_html()\r
+ * @param array $saisie\r
+ *     Tableau de description d'une saisie\r
+ * @param array $env\r
+ *     L'environnement, contenant normalement la réponse à la saisie\r
+ * @param array $env_obligatoire\r
+ *     ???\r
+ * @return string\r
+ *     Code HTML de la vue de la saisie\r
+ */\r
+function saisies_generer_vue($saisie, $env=array(), $env_obligatoire=array()){\r
+       // Si le paramètre n'est pas bon, on génère du vide\r
+       if (!is_array($saisie))\r
+               return '';\r
+\r
+       $contexte = array();\r
+               \r
+       // On sélectionne le type de saisie\r
+       $contexte['type_saisie'] = $saisie['saisie'];\r
+       \r
+       // Peut-être des transformations à faire sur les options textuelles\r
+       $options = $saisie['options'];\r
+       foreach ($options as $option => $valeur){\r
+               if ($option == 'datas') {\r
+                       // exploser une chaine datas en tableau (applique _T_ou_typo sur chaque valeur)\r
+                       $options[$option] = saisies_chaine2tableau($valeur);\r
+               } else {\r
+                       $options[$option] = _T_ou_typo($valeur, 'multi');\r
+               }\r
+       }\r
+       \r
+       // On ajoute les options propres à la saisie\r
+       $contexte = array_merge($contexte, $options);\r
+\r
+       // Si env est définie dans les options ou qu'il y a des enfants, on ajoute tout l'environnement\r
+       if (isset($contexte['env']) or (isset($saisie['saisies']) AND is_array($saisie['saisies']))){\r
+               unset($contexte['env']);\r
+\r
+               // on sauve l'ancien environnement\r
+               // car les sous-saisies ne doivent pas être affectees\r
+               // par les modification sur l'environnement servant à generer la saisie mère\r
+               $contexte['_env'] = $env;\r
+\r
+               // À partir du moment où on passe tout l'environnement, il faut enlever \r
+               // certains éléments qui ne doivent absolument provenir que des options\r
+               $saisies_disponibles = saisies_lister_disponibles();\r
+               if (is_array($saisies_disponibles[$contexte['type_saisie']]['options'])){\r
+                       $options_a_supprimer = saisies_lister_champs($saisies_disponibles[$contexte['type_saisie']]['options']);\r
+                       foreach ($options_a_supprimer as $option_a_supprimer){\r
+                               unset($env[$option_a_supprimer]);\r
+                       }\r
+               }\r
+               \r
+               $contexte = array_merge($env, $contexte);\r
+       }\r
+\r
+       // Dans tous les cas on récupère de l'environnement la valeur actuelle du champ\r
+       \r
+       // On regarde en priorité s'il y a un tableau listant toutes les valeurs\r
+       if ($env['valeurs'] and is_array($env['valeurs']) and isset($env['valeurs'][$contexte['nom']])){\r
+               $contexte['valeur'] = $env['valeurs'][$contexte['nom']];\r
+       }\r
+       // Si le nom du champ est un tableau indexé, il faut parser !\r
+       elseif (preg_match('/([\w]+)((\[[\w]+\])+)/', $contexte['nom'], $separe)){\r
+               $contexte['valeur'] = $env[$separe[1]];\r
+               preg_match_all('/\[([\w]+)\]/', $separe[2], $index);\r
+               // On va chercher au fond du tableau\r
+               foreach($index[1] as $cle){\r
+                       $contexte['valeur'] = $contexte['valeur'][$cle];\r
+               }\r
+       }\r
+       // Sinon la valeur est juste celle du nom\r
+       else {\r
+               // certains n'ont pas de nom (fieldset)\r
+               $contexte['valeur'] = isset($env[$contexte['nom']]) ? $env[$contexte['nom']] : '';\r
+       }\r
+\r
+       // Si ya des enfants on les remonte dans le contexte\r
+       if (isset($saisie['saisies']) AND is_array($saisie['saisies']))\r
+               $contexte['saisies'] = $saisie['saisies'];\r
+\r
+       if (is_array($env_obligatoire)) {\r
+               $contexte = array_merge($contexte, $env_obligatoire);\r
+       }\r
+\r
+       // On génère la saisie\r
+       return recuperer_fond(\r
+               'saisies-vues/_base',\r
+               $contexte\r
+       );\r
+}\r
+\r
+/**\r
+ * Génère, à partir d'un tableau de saisie le code javascript ajouté à la fin de #GENERER_SAISIES\r
+ * pour produire un affichage conditionnel des saisies ayant une option afficher_si.\r
+ *\r
+ * @param array $saisies\r
+ *     Tableau de descriptions des saisies\r
+ * @param string $id_form\r
+ *     Identifiant unique pour le formulaire\r
+ * @return text\r
+ *     Code javascript\r
+ */\r
+function saisies_generer_js_afficher_si($saisies,$id_form){\r
+       $i = 0;\r
+       $saisies = saisies_lister_par_nom($saisies,true);\r
+       $code = '';\r
+       $code .= '(function($){';\r
+       $code .= '$(document).ready(function(){';\r
+               $code .= 'verifier_saisies_'.$id_form.' = function(form){';\r
+                               foreach ($saisies as $saisie) {\r
+                                       // on utilise comme selecteur l'identifiant de saisie en priorite s'il est connu\r
+                                       // parce que li_class = 'tableau[nom][option]' ne fonctionne evidement pas\r
+                                       // lorsque le name est un tableau\r
+                                       if (isset($saisie['options']['afficher_si'])) {\r
+                                               $i++;\r
+                                               // retrouver la classe css probable\r
+                                               switch ($saisie['saisie']) {\r
+                                                       case 'fieldset':\r
+                                                               $class_li = 'fieldset_'.$saisie['options']['nom'];\r
+                                                               break;\r
+                                                       case 'explication':\r
+                                                               $class_li = 'explication_'.$saisie['options']['nom'];\r
+                                                               break;\r
+                                                       default:\r
+                                                               $class_li = 'editer_'.$saisie['options']['nom'];\r
+                                               }\r
+                                               $condition = $saisie['options']['afficher_si'];\r
+                                               // retrouver l'identifiant\r
+                                               $identifiant = '';\r
+                                               if (isset($saisie['identifiant']) and $saisie['identifiant']) {\r
+                                                       $identifiant = $saisie['identifiant'];\r
+                                               }\r
+                                               // On gère le cas @plugin:non_plugin@\r
+                                               preg_match_all('#@plugin:(.+)@#U', $condition, $matches);\r
+                                               foreach ($matches[1] as $plug) {\r
+                                                       if (defined('_DIR_PLUGIN_'.strtoupper($plug)))\r
+                                                               $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);\r
+                                                       else\r
+                                                               $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);\r
+                                               }\r
+                                               // On gère le cas @config:plugin:meta@ suivi d'un test\r
+                                               preg_match_all('#@config:(.+):(.+)@#U', $condition, $matches);\r
+                                               foreach ($matches[1] as $plugin) {\r
+                                                       $config = lire_config($plugin);\r
+                                                       $condition = preg_replace('#@config:'.$plugin.':'.$matches[2][0].'@#U', '"'.$config[$matches[2][0]].'"', $condition);\r
+                                               }\r
+                                               // On transforme en une condition valide\r
+                                               preg_match_all('#@(.+)@#U', $condition, $matches);\r
+                                               foreach ($matches[1] as $nom) {\r
+                                                       switch($saisies[$nom]['saisie']) {\r
+                                                               case 'radio':\r
+                                                               case 'oui_non':\r
+                                                                       $condition = preg_replace('#@'.preg_quote($nom).'@#U', '$(form).find("[name=\''.$nom.'\']:checked").val()', $condition);\r
+                                                                       break;\r
+                                                               case 'case':\r
+                                                                       $condition = preg_replace('#@'.preg_quote($nom).'@#U', '($(form).find("[name=\''.$nom.'\']").is(":checked") ? $(form).find("[name=\''.$nom.'\']").val() : "")', $condition);\r
+                                                                       break;\r
+                                                               default:\r
+                                                                       $condition = preg_replace('#@'.preg_quote($nom).'@#U', '$(form).find("[name=\''.$nom.'\']").val()', $condition);\r
+                                                       }\r
+                                               }\r
+                                               if ($identifiant) {\r
+                                                       $sel = "li[data-id='$identifiant']";\r
+                                               } else {\r
+                                                       $sel = "li.$class_li";\r
+                                               }\r
+                                               $code .= 'if ('.$condition.') {$(form).find("'.$sel.'").show(400);} ';\r
+                                               $code .= 'else {$(form).find("'.$sel.'").hide(400).css("display", "none");} ';\r
+                                       }\r
+                               }\r
+               $code .= '};';\r
+               $code .= '$("li#afficher_si_'.$id_form.'").parents("form").each(function(){verifier_saisies_'.$id_form.'(this);});';\r
+               $code .= '$("li#afficher_si_'.$id_form.'").parents("form").change(function(){verifier_saisies_'.$id_form.'(this);});';\r
+       $code .= '});';\r
+       $code .= '})(jQuery);';\r
+       return $i>0 ? $code : '';\r
+}\r
+\r
+/**\r
+ * Lorsque l'on affiche les saisies (#VOIR_SAISIES), les saisies ayant une option afficher_si\r
+ * et dont les conditions ne sont pas remplies doivent être retirées du tableau de saisies.\r
+ * \r
+ * Cette fonction sert aussi lors de la vérification des saisies avec saisies_verifier().\r
+ * À ce moment là, les saisies non affichées sont retirées de _request\r
+ * (on passe leur valeur à NULL).\r
+ *\r
+ * @param array $saisies\r
+ *     Tableau de descriptions de saisies\r
+ * @param array|null $env\r
+ *     Tableau d'environnement transmis dans inclure/voi_saisies.html,\r
+ *     NULL si on doit rechercher dans _request (pour saisies_verifier()).\r
+ * @return array\r
+ *     Tableau de descriptions de saisies\r
+ */\r
+function saisies_verifier_afficher_si($saisies, $env=NULL) {\r
+       // eviter une erreur par maladresse d'appel :)\r
+       if (!is_array($saisies)) {\r
+               return array();\r
+       }\r
+       foreach ($saisies as $cle => $saisie) {\r
+               if (isset($saisie['options']['afficher_si'])) {\r
+                       $condition = $saisie['options']['afficher_si'];\r
+                       // On gère le cas @plugin:non_plugin@\r
+                       preg_match_all('#@plugin:(.+)@#U', $condition, $matches);\r
+                       foreach ($matches[1] as $plug) {\r
+                               if (defined('_DIR_PLUGIN_'.strtoupper($plug)))\r
+                                       $condition = preg_replace('#@plugin:'.$plug.'@#U', 'true', $condition);\r
+                               else\r
+                                       $condition = preg_replace('#@plugin:'.$plug.'@#U', 'false', $condition);\r
+                       }\r
+                       // On gère le cas @config:plugin:meta@ suivi d'un test\r
+                       preg_match_all('#@config:(.+):(.+)@#U', $condition, $matches);\r
+                       foreach ($matches[1] as $plugin) {\r
+                               $config = lire_config($plugin);\r
+                               $condition = preg_replace('#@config:'.$plugin.':'.$matches[2][0].'@#U', '"'.$config[$matches[2][0]].'"', $condition);\r
+                       }\r
+                       // On transforme en une condition valide\r
+                       if (is_null($env))\r
+                               $condition = preg_replace('#@(.+)@#U', '_request(\'$1\')', $condition);\r
+                       else\r
+                               $condition = preg_replace('#@(.+)@#U', '$env["valeurs"][\'$1\']', $condition);\r
+                       eval('$ok = '.$condition.';');\r
+                       if (!$ok) {\r
+                               unset($saisies[$cle]);\r
+                               if (is_null($env)) set_request($saisie['options']['nom'],NULL);\r
+                       }\r
+               }\r
+               if (isset($saisies[$cle]['saisies'])) // S'il s'agit d'un fieldset ou equivalent, verifier les sous-saisies\r
+                       $saisies[$cle]['saisies'] = saisies_verifier_afficher_si($saisies[$cle]['saisies'], $env);\r
+       }\r
+       return $saisies;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/saisies/inc/saisies_lister.php b/www/plugins/saisies/inc/saisies_lister.php
new file mode 100644 (file)
index 0000000..f924bd1
--- /dev/null
@@ -0,0 +1,321 @@
+<?php
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/*
+ * Prend la description complète du contenu d'un formulaire et retourne
+ * les saisies "à plat" classées par identifiant unique.
+ *
+ * @param array $contenu Le contenu d'un formulaire
+ * @param bool $avec_conteneur Indique si on renvoie aussi les saisies ayant des enfants, comme les fieldsets
+ * @return array Un tableau avec uniquement les saisies
+ */
+function saisies_lister_par_identifiant($contenu, $avec_conteneur=true){
+       $saisies = array();
+       
+       if (is_array($contenu)){
+               foreach ($contenu as $ligne){
+                       if (is_array($ligne)) {
+                               $enfants_presents = (isset($ligne['saisies']) and is_array($ligne['saisies']));
+                               if (array_key_exists('saisie', $ligne) and (!$enfants_presents or $avec_conteneur)){
+                                       $saisies[$ligne['identifiant']] = $ligne;
+                               }
+                               if ($enfants_presents) {
+                                       $saisies = array_merge($saisies, saisies_lister_par_identifiant($ligne['saisies']));
+                               }
+                       }
+               }
+       }
+       
+       return $saisies;
+}
+
+/*
+ * Prend la description complète du contenu d'un formulaire et retourne
+ * les saisies "à plat" classées par nom.
+ *
+ * @param array $contenu Le contenu d'un formulaire
+ * @param bool $avec_conteneur Indique si on renvoie aussi les saisies ayant des enfants, comme les fieldset
+ * @return array Un tableau avec uniquement les saisies
+ */
+function saisies_lister_par_nom($contenu, $avec_conteneur=true){
+       $saisies = array();
+       
+       if (is_array($contenu)){
+               foreach ($contenu as $ligne){
+                       if (is_array($ligne)){
+                               if (array_key_exists('saisie', $ligne) and (!isset($ligne['saisies']) OR !is_array($ligne['saisies']) or $avec_conteneur)){
+                                       $saisies[$ligne['options']['nom']] = $ligne;
+                               }
+                               if (isset($ligne['saisies']) AND is_array($ligne['saisies'])){
+                                       $saisies = array_merge($saisies, saisies_lister_par_nom($ligne['saisies']));
+                               }
+                       }
+               }
+       }
+       
+       return $saisies;
+}
+
+/*
+ * Liste les saisies ayant une option X
+ * # saisies_lister_avec_option('sql', $saisies);
+ *  
+ *
+ * @param String $option Nom de l'option cherchée
+ * @param Array $saisies Liste de saisies
+ * @param String $tri tri par défaut des résultats (s'ils ne sont pas deja triés) ('nom', 'identifiant')
+ * @return liste de ces saisies triees par nom ayant une option X définie
+ */
+function saisies_lister_avec_option($option, $saisies, $tri = 'nom') {
+       $saisies_option = array();
+       // tri par nom si ce n'est pas le cas
+       $s = array_keys($saisies);
+       if (is_int(array_shift($s))) {
+               $trier = 'saisies_lister_par_' . $tri;
+               $saisies = $trier($saisies);
+       }
+       foreach ($saisies as $nom_ou_id => $saisie) {
+               if (isset($saisie['options'][$option]) and $saisie['options'][$option]) {
+                       $saisies_option[$nom_ou_id] = $saisie;
+               }
+       }
+
+       return $saisies_option;
+}
+
+/*
+ * Liste les saisies ayant une definition SQL
+ *
+ * @param Array $saisies liste de saisies
+ * @param String $tri tri par défaut des résultats (s'ils ne sont pas deja triés) ('nom', 'identifiant')
+ * @return liste de ces saisies triees par nom ayant une option sql définie
+ */
+function saisies_lister_avec_sql($saisies, $tri = 'nom') {
+       return saisies_lister_avec_option('sql', $saisies, $tri);
+}
+
+/*
+ * Prend la description complète du contenu d'un formulaire et retourne
+ * les saisies "à plat" classées par type de saisie.
+ * $saisie['input']['input_1'] = $saisie
+ *
+ * @param array $contenu Le contenu d'un formulaire
+ * @return array Un tableau avec uniquement les saisies
+ */
+function saisies_lister_par_type($contenu) {
+       $saisies = array();
+       
+       if (is_array($contenu)){
+               foreach ($contenu as $ligne){
+                       if (is_array($ligne)){
+                               if (array_key_exists('saisie', $ligne) and (!is_array($ligne['saisies']))){
+                                       $saisies[ $ligne['saisie'] ][ $ligne['options']['nom'] ] = $ligne;
+                               }
+                               if (is_array($ligne['saisies'])){
+                                       $saisies = array_merge($saisies, saisies_lister_par_type($ligne['saisies']));
+                               }
+                       }
+               }
+       }
+       
+       return $saisies;
+}
+
+/*
+ * Prend la description complète du contenu d'un formulaire et retourne
+ * une liste des noms des champs du formulaire.
+ *
+ * @param array $contenu Le contenu d'un formulaire
+ * @return array Un tableau listant les noms des champs
+ */
+function saisies_lister_champs($contenu, $avec_conteneur=true){
+       $saisies = saisies_lister_par_nom($contenu, $avec_conteneur);
+       return array_keys($saisies);
+}
+
+/*
+ * A utiliser dans une fonction charger d'un formulaire CVT,
+ * cette fonction renvoie le tableau de contexte correspondant
+ * de la forme $contexte['nom_champ'] = ''
+ *
+ * @param array $contenu Le contenu d'un formulaire (un tableau de saisies)
+ * @return array Un tableau de contexte
+ */
+function saisies_charger_champs($contenu) {
+       // array_fill_keys est disponible uniquement avec PHP >= 5.2.0
+       // return array_fill_keys(saisies_lister_champs($contenu, false), '');
+       $champs = array();
+       foreach (saisies_lister_champs($contenu, false) as $champ)
+               $champs[$champ] = '';
+       return $champs;
+}
+
+/*
+ * Prend la description complète du contenu d'un formulaire et retourne
+ * une liste des valeurs par défaut des champs du formulaire.
+ *
+ * @param array $contenu Le contenu d'un formulaire
+ * @return array Un tableau renvoyant la valeur par défaut de chaque champs
+ */
+function saisies_lister_valeurs_defaut($contenu){
+       $contenu = saisies_lister_par_nom($contenu, false);
+       $defauts = array();
+       foreach ($contenu as $nom => $saisie){
+               // Si le nom du champ est un tableau indexé, il faut parser !
+               if (preg_match('/([\w]+)((\[[\w]+\])+)/', $nom, $separe)){
+                       $nom = $separe[1];
+                       // Dans ce cas on ne récupère que le nom, la valeur par défaut du tableau devra être renseigné autre part
+                       $defauts[$nom] = array();
+               }
+               else{
+                       $defauts[$nom] = isset($saisie['options']['defaut']) ? $saisie['options']['defaut'] : '';
+               }
+       }
+       return $defauts;
+}
+
+/*
+ * Compare deux tableaux de saisies pour connaitre les différences
+ * @param array $saisies_anciennes Un tableau décrivant des saisies
+ * @param array $saisies_nouvelles Un autre tableau décrivant des saisies
+ * @param bool $avec_conteneur Indique si on veut prendre en compte dans la comparaison les conteneurs comme les fieldsets
+ * @param string $tri Comparer selon quel tri ? 'nom' / 'identifiant'
+ * @return array Retourne le tableau des saisies supprimées, ajoutées et modifiées
+ */
+function saisies_comparer($saisies_anciennes, $saisies_nouvelles, $avec_conteneur=true, $tri = 'nom') {
+       $trier = "saisies_lister_par_$tri";
+       $saisies_anciennes = $trier($saisies_anciennes, $avec_conteneur);
+       $saisies_nouvelles = $trier($saisies_nouvelles, $avec_conteneur);
+       
+       // Les saisies supprimées sont celles qui restent dans les anciennes quand on a enlevé toutes les nouvelles
+       $saisies_supprimees = array_diff_key($saisies_anciennes, $saisies_nouvelles);
+       // Les saisies ajoutées, c'est le contraire
+       $saisies_ajoutees = array_diff_key($saisies_nouvelles, $saisies_anciennes);
+       // Il reste alors les saisies qui ont le même nom
+       $saisies_restantes = array_intersect_key($saisies_anciennes, $saisies_nouvelles);
+       // Dans celles-ci, celles qui sont modifiées sont celles dont la valeurs est différentes
+       $saisies_modifiees = array_udiff(array_diff_key($saisies_nouvelles, $saisies_ajoutees), $saisies_restantes, 'saisies_comparer_rappel');
+       #$saisies_modifiees = array_udiff($saisies_nouvelles, $saisies_restantes, 'saisies_comparer_rappel');
+       // Et enfin les saisies qui ont le même nom et la même valeur
+       $saisies_identiques = array_diff_key($saisies_restantes, $saisies_modifiees);
+       
+       return array(
+               'supprimees' => $saisies_supprimees,
+               'ajoutees' => $saisies_ajoutees,
+               'modifiees' => $saisies_modifiees,
+               'identiques' => $saisies_identiques
+       );
+}
+
+/*
+ * Compare deux saisies et indique si elles sont égales ou pas
+ */
+function saisies_comparer_rappel($a, $b){
+       if ($a === $b) return 0;
+       else return 1;
+}
+
+/*
+ * Compare deux tableaux de saisies pour connaitre les différences
+ * en s'appuyant sur les identifiants de saisies
+ *
+ * @see saisies_comparer()
+ * @param array $saisies_anciennes Un tableau décrivant des saisies
+ * @param array $saisies_nouvelles Un autre tableau décrivant des saisies
+ * @param bool $avec_conteneur Indique si on veut prendre en compte dans la comparaison les conteneurs comme les fieldsets
+ * @return array Retourne le tableau des saisies supprimées, ajoutées et modifiées
+ */
+function saisies_comparer_par_identifiant($saisies_anciennes, $saisies_nouvelles, $avec_conteneur=true) {
+       return saisies_comparer($saisies_anciennes, $saisies_nouvelles, $avec_conteneur, $tri = 'identifiant');
+}
+
+/*
+ * Liste toutes les saisies configurables (ayant une description)
+ *
+ * @return array Un tableau listant des saisies et leurs options
+ */
+function saisies_lister_disponibles(){
+       static $saisies = null;
+       
+       if (is_null($saisies)){
+               $saisies = array();
+               $liste = find_all_in_path('saisies/', '.+[.]yaml$');
+               
+               if (count($liste)){
+                       foreach ($liste as $fichier=>$chemin){
+                               $type_saisie = preg_replace(',[.]yaml$,i', '', $fichier);
+                               $dossier = str_replace($fichier, '', $chemin);
+                               // On ne garde que les saisies qui ont bien le HTML avec !
+                               if (file_exists("$dossier$type_saisie.html")
+                                       and (
+                                               is_array($saisie = saisies_charger_infos($type_saisie))
+                                       )
+                               ){
+                                       $saisies[$type_saisie] = $saisie;
+                               }
+                       }
+               }
+       }
+       
+       return $saisies;
+}
+
+/*
+ * Lister les saisies existantes ayant une définition SQL 
+ *
+ * @return array Un tableau listant des saisies et leurs options
+ */
+function saisies_lister_disponibles_sql() {
+       $saisies = array();
+       $saisies_disponibles = saisies_lister_disponibles();
+       foreach ($saisies_disponibles as $type=>$saisie) {
+               if (isset($saisie['defaut']['options']['sql']) and $saisie['defaut']['options']['sql']) {
+                       $saisies[$type] = $saisie;
+               }
+       }
+       return $saisies;
+}
+
+/*
+ * Charger les informations contenues dans le YAML d'une saisie
+ *
+ * @param string $type_saisie Le type de la saisie
+ * @return array Un tableau contenant le YAML décodé
+ */
+function saisies_charger_infos($type_saisie){
+       include_spip('inc/yaml');
+       $fichier = find_in_path("saisies/$type_saisie.yaml");
+       $saisie = yaml_decode_file($fichier);
+       if (is_array($saisie)){
+               $saisie['titre'] = (isset($saisie['titre']) AND $saisie['titre'])
+                       ? _T_ou_typo($saisie['titre']) : $type_saisie;
+               $saisie['description'] = (isset($saisie['description']) AND $saisie['description'])
+                       ? _T_ou_typo($saisie['description']) : '';
+               $saisie['icone'] = (isset($saisie['icone']) AND $saisie['icone'])
+                       ? find_in_path($saisie['icone']) : '';
+       }
+       return $saisie;
+}
+
+/*
+ * Quelles sont les saisies qui se débrouillent toutes seules, sans le _base commun
+ *
+ * @return array Retourne un tableau contenant les types de saisies qui ne doivent pas utiliser le _base.html commun
+ */
+function saisies_autonomes(){
+       $saisies_autonomes = pipeline(
+               'saisies_autonomes',
+               array(
+                       'fieldset',
+                       'hidden',
+                       'destinataires', 
+                       'explication'
+               )
+       );
+       
+       return $saisies_autonomes;
+}
+
+?>
diff --git a/www/plugins/saisies/inc/saisies_manipuler.php b/www/plugins/saisies/inc/saisies_manipuler.php
new file mode 100644 (file)
index 0000000..9ccffda
--- /dev/null
@@ -0,0 +1,303 @@
+<?php
+
+/**
+ * Gestion de l'affichage des saisies
+ *
+ * @return SPIP\Saisies\Manipuler
+**/
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Supprimer une saisie dont on donne l'identifiant, le nom ou le chemin
+ *
+ * @param array $saisies
+ *     Tableau des descriptions de saisies
+ * @param string|array $id_ou_nom_ou_chemin
+ *     L'identifiant unique
+ *     ou le nom de la saisie à supprimer
+ *     ou son chemin sous forme d'une liste de clés
+ * @return array
+ *     Tableau modifié décrivant les saisies
+ */
+function saisies_supprimer($saisies, $id_ou_nom_ou_chemin){
+       // Si la saisie n'existe pas, on ne fait rien
+       if ($chemin = saisies_chercher($saisies, $id_ou_nom_ou_chemin, true)){
+               // La position finale de la saisie
+               $position = array_pop($chemin);
+       
+               // On va chercher le parent par référence pour pouvoir le modifier
+               $parent =& $saisies;
+               foreach($chemin as $cle){
+                       $parent =& $parent[$cle];
+               }
+               
+               // On supprime et réordonne
+               unset($parent[$position]);
+               $parent = array_values($parent);
+       }
+       
+       return $saisies;
+}
+
+/**
+ * Insère une saisie à une position donnée
+ *
+ * @param array $saisies
+ *     Tableau des descriptions de saisies
+ * @param array $saisie
+ *     Description de la saisie à insérer
+ * @param array $chemin
+ *     Position complète où insérer la saisie.
+ *     En absence, insère la saisie à la fin.
+ * @return array
+ *     Tableau des saisies complété de la saisie insérée
+ */
+function saisies_inserer($saisies, $saisie, $chemin=array()){
+       // On vérifie quand même que ce qu'on veut insérer est correct
+       if ($saisie['saisie'] and $saisie['options']['nom']){
+               // ajouter un identifiant
+               $saisie = saisie_identifier($saisie);
+               
+               // Par défaut le parent c'est la racine
+               $parent =& $saisies;
+               // S'il n'y a pas de position, on va insérer à la fin du formulaire
+               if (!$chemin){
+                       $position = count($parent);
+               }
+               elseif (is_array($chemin)){
+                       $position = array_pop($chemin);
+                       foreach ($chemin as $cle){
+                               // Si la clé est un conteneur de saisies "saisies" et qu'elle n'existe pas encore, on la crée
+                               if ($cle == 'saisies' and !isset($parent[$cle]))
+                                       $parent[$cle] = array();
+                               $parent =& $parent[$cle];
+                       }
+                       // On vérifie maintenant que la position est cohérente avec le parent
+                       if ($position < 0) $position = 0;
+                       elseif ($position > count($parent)) $position = count($parent);
+               }
+               // Et enfin on insère
+               array_splice($parent, $position, 0, array($saisie));
+       }
+       
+       return $saisies;
+}
+
+/*
+ * Duplique une saisie (ou groupe de saisies)
+ * en placant la copie à la suite de la saisie d'origine.
+ * Modifie automatiquement les identifiants des saisies
+ *
+ * @param array $saisies Un tableau décrivant les saisies
+ * @param unknown_type $id_ou_nom_ou_chemin L'identifiant unique ou le nom ou le chemin de la saisie a dupliquer
+ * @return array Retourne le tableau modifié des saisies
+ */
+function saisies_dupliquer($saisies, $id_ou_nom_ou_chemin){
+       // On récupère le contenu de la saisie à déplacer
+       $saisie = saisies_chercher($saisies, $id_ou_nom_ou_chemin);
+       if ($saisie) {
+               list($clone) = saisies_transformer_noms_auto($saisies, array($saisie));
+               // insertion apres quoi ?
+               $chemin_validation = saisies_chercher($saisies, $id_ou_nom_ou_chemin, true);
+               // 1 de plus pour mettre APRES le champ trouve
+               $chemin_validation[count($chemin_validation)-1]++;
+               // On ajoute "copie" après le label du champs
+               $clone['options']['label'] .= ' '._T('saisies:construire_action_dupliquer_copie');
+
+               // Création de nouveau identifiants pour le clone
+               $clone = saisie_identifier($clone, true);
+               
+               $saisies = saisies_inserer($saisies, $clone, $chemin_validation);
+       }
+
+       return $saisies;
+}
+
+/*
+ * Déplace une saisie existante autre part
+ *
+ * @param array $saisies Un tableau décrivant les saisies
+ * @param unknown_type $id_ou_nom_ou_chemin L'identifiant unique ou le nom ou le chemin de la saisie à déplacer
+ * @param string $ou Le nom de la saisie devant laquelle on déplacera OU le nom d'un conteneur entre crochets [conteneur]
+ * @return array Retourne le tableau modifié des saisies
+ */
+function saisies_deplacer($saisies, $id_ou_nom_ou_chemin, $ou){
+       // On récupère le contenu de la saisie à déplacer
+       $saisie = saisies_chercher($saisies, $id_ou_nom_ou_chemin);
+
+       // Si on l'a bien trouvé
+       if ($saisie){
+               // On cherche l'endroit où la déplacer
+               // Si $ou est vide, c'est à la fin de la racine
+               if (!$ou){
+                       $saisies = saisies_supprimer($saisies, $id_ou_nom_ou_chemin);
+                       $chemin = array(count($saisies));
+               }
+               // Si l'endroit est entre crochet, c'est un conteneur
+               elseif (preg_match('/^\[(@?[\w]*)\]$/', $ou, $match)){
+                       $parent = $match[1];
+                       // Si dans les crochets il n'y a rien, on met à la fin du formulaire
+                       if (!$parent){
+                               $saisies = saisies_supprimer($saisies, $id_ou_nom_ou_chemin);
+                               $chemin = array(count($saisies));
+                       }
+                       // Sinon on vérifie que ce conteneur existe
+                       elseif (saisies_chercher($saisies, $parent, true)){
+                               // S'il existe on supprime la saisie et on recherche la nouvelle position
+                               $saisies = saisies_supprimer($saisies, $id_ou_nom_ou_chemin);
+                               $parent = saisies_chercher($saisies, $parent, true);
+                               $chemin = array_merge($parent, array('saisies', 1000000));
+                       }
+                       else
+                               $chemin = false;
+               }
+               // Sinon ça sera devant un champ
+               else{
+                       // On vérifie que le champ existe
+                       if (saisies_chercher($saisies, $ou, true)){
+                               // S'il existe on supprime la saisie
+                               $saisies = saisies_supprimer($saisies, $id_ou_nom_ou_chemin);
+                               // Et on recherche la nouvelle position qui n'est plus forcément la même maintenant qu'on a supprimé une saisie
+                               $chemin = saisies_chercher($saisies, $ou, true);
+                       }
+                       else
+                               $chemin = false;
+               }
+               
+               // Si seulement on a bien trouvé un nouvel endroit où la placer, alors on déplace
+               if ($chemin)
+                       $saisies = saisies_inserer($saisies, $saisie, $chemin);
+       }
+       
+       return $saisies;
+}
+
+/*
+ * Modifie une saisie
+ *
+ * @param array $saisies Un tableau décrivant les saisies
+ * @param unknown_type $id_ou_nom_ou_chemin L'identifiant unique ou le nom ou le chemin de la saisie à modifier
+ * @param array $modifs Le tableau des modifications à apporter à la saisie
+ * @return Retourne le tableau décrivant les saisies, mais modifié
+ */
+function saisies_modifier($saisies, $id_ou_nom_ou_chemin, $modifs){
+       $chemin = saisies_chercher($saisies, $id_ou_nom_ou_chemin, true);
+       $position = array_pop($chemin);
+       $parent =& $saisies;
+       foreach ($chemin as $cle){
+               $parent =& $parent[$cle];
+       }
+       
+       // On récupère le type tel quel
+       $modifs['saisie'] = $parent[$position]['saisie'];
+       // On récupère le nom s'il n'y est pas
+       if (!isset($modifs['options']['nom'])){
+               $modifs['options']['nom'] = $parent[$position]['options']['nom'];
+       }
+       // On récupère les enfants tels quels s'il n'y a pas des enfants dans la modif
+       if (
+               !isset($modifs['saisies'])
+               and isset($parent[$position]['saisies'])
+               and is_array($parent[$position]['saisies'])
+       ){
+               $modifs['saisies'] = $parent[$position]['saisies'];
+       }
+
+       // Si une option 'nouveau_type_saisie' est donnee, c'est que l'on souhaite
+       // peut être changer le type de saisie !
+       if (isset($modifs['options']['nouveau_type_saisie']) and $type = $modifs['options']['nouveau_type_saisie']) {
+               $modifs['saisie'] = $type;
+               unset($modifs['options']['nouveau_type_saisie']);
+       }
+                       
+       // On remplace tout
+       $parent[$position] = $modifs;
+       
+       // Cette méthode ne marche pas trop
+       //$parent[$position] = array_replace_recursive($parent[$position], $modifs);
+       
+       return $saisies;
+}
+
+/**
+ * Transforme tous les noms du formulaire avec un preg_replace
+ *
+ * @param array $saisies
+ *     Un tableau décrivant les saisies
+ * @param string $masque
+ *     Ce que l'on doit chercher dans le nom
+ * @param string $remplacement
+ *     Ce par quoi on doit remplacer
+ * @return array
+ *     Retourne le tableau modifié des saisies
+ */
+function saisies_transformer_noms($saisies, $masque, $remplacement){
+       if (is_array($saisies)){
+               foreach ($saisies as $cle => $saisie){
+                       $saisies[$cle]['options']['nom'] = preg_replace($masque, $remplacement, $saisie['options']['nom']);
+                       if (isset($saisie['saisies']) and is_array($saisie['saisies'])) {
+                               $saisies[$cle]['saisies'] = saisies_transformer_noms($saisie['saisies'], $masque, $remplacement);
+                       }
+               }
+       }
+       
+       return $saisies;
+}
+
+/**
+ * Transforme les noms d'une liste de saisies pour qu'ils soient
+ * uniques dans le formulaire donné.
+ *
+ * @param array $formulaire
+ *     Le formulaire à analyser 
+ * @param array $saisies
+ *     Un tableau décrivant les saisies.
+ * @return array
+ *     Retourne le tableau modifié des saisies
+ */
+function saisies_transformer_noms_auto($formulaire, $saisies){
+
+       if (is_array($saisies)){
+               foreach ($saisies as $cle => $saisie){
+                       $saisies[$cle]['options']['nom'] = saisies_generer_nom($formulaire, $saisie['saisie']);
+                       // il faut prendre en compte dans $formulaire les saisies modifiees
+                       // sinon on aurait potentiellement 2 champs successifs avec le meme nom.
+                       // on n'ajoute pas les saisies dont les noms ne sont pas encore calculees.
+                       $new = $saisies[$cle];
+                       unset($new['saisies']);
+                       $formulaire[] = $new;
+                       
+                       if (is_array($saisie['saisies']))
+                               $saisies[$cle]['saisies'] = saisies_transformer_noms_auto($formulaire, $saisie['saisies']);
+               }
+       }
+
+       return $saisies;
+}
+
+/*
+ * Insère du HTML au début ou à la fin d'une saisie
+ *
+ * @param array $saisie La description d'une seule saisie
+ * @param string $insertion Du code HTML à insérer dans la saisie 
+ * @param string $ou L'endroit où insérer le HTML : "debut" ou "fin"
+ * @return array Retourne la description de la saisie modifiée
+ */
+function saisies_inserer_html($saisie, $insertion, $ou='fin'){
+       if (!in_array($ou, array('debut', 'fin')))
+               $ou = 'fin';
+       
+       if ($ou == 'debut') {
+               $saisie['options']['inserer_debut'] =
+                       $insertion . (isset($saisie['options']['inserer_debut']) ? $saisie['options']['inserer_debut'] : '');
+       } elseif ($ou == 'fin') {
+               $saisie['options']['inserer_fin'] =
+                       (isset($saisie['options']['inserer_fin']) ? $saisie['options']['inserer_fin'] : '') . $insertion;
+       }
+       
+       return $saisie;
+}
+
+?>
diff --git a/www/plugins/saisies/inclure/configurer_saisie.html b/www/plugins/saisies/inclure/configurer_saisie.html
new file mode 100644 (file)
index 0000000..70991bb
--- /dev/null
@@ -0,0 +1,19 @@
+[(#REM) 
+  
+  ### /!\ necessite le plugin YAML ###
+  
+  Genere l'intérieur d'un formulaire permettant de configurer une saisie.
+  
+  Par defaut, ne permet pas de configurer le "name" de la saisie car dans la
+  plupart des cas c'est une valeur qui sera automatique. On utilise le parametre
+  "avec_nom=oui" pour forcer le champ.
+  
+  Exemples d'appels :
+    #INCLURE{fond=inclure/configurer_saisie, env, saisie=input}
+    #INCLURE{fond=inclure/configurer_saisie, env, saisie=input, avec_nom=oui}
+
+]
+
+[(#SET{config, #ENV{saisie}|construire_configuration_saisie{#ENV{avec_nom}}})]
+
+#GENERER_SAISIES{#GET{config}}
diff --git a/www/plugins/saisies/inclure/configurer_saisie_fonctions.php b/www/plugins/saisies/inclure/configurer_saisie_fonctions.php
new file mode 100644 (file)
index 0000000..5285b93
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function construire_configuration_saisie($saisie, $avec_nom='non'){
+       include_spip('inc/yaml');
+       $configuration_saisie = yaml_decode_file(find_in_path('saisies/'.$saisie.'.yaml'));
+       
+       if (is_array($configuration_saisie)){
+               $configuration_saisie = $configuration_saisie['options'];
+               // On ne met le premier champ permettant de configurer le "name" seulement si on le demande explicitement
+               if ($avec_nom == 'oui')
+                       array_unshift($configuration_saisie[0]['contenu'],
+                               array(
+                                       'saisie' => 'input',
+                                       'options' => array(
+                                               'nom' => 'nom',
+                                               'label' => '<:saisies:option_nom_label:>',
+                                               'explication' => '<:saisies:option_nom_explication:>',
+                                               'obligatoire' => 'oui'
+                                       ),
+                                       'verifier' => array(
+                                               'type' => 'regex',
+                                               'options' => array(
+                                                       'modele' => '/^[\w]+$/'
+                                               )
+                                       )
+                               )
+                       );
+       }
+       else
+               $configuration_saisie = array();
+       
+       return $configuration_saisie;
+}
+
+?>
diff --git a/www/plugins/saisies/inclure/generer_saisies.html b/www/plugins/saisies/inclure/generer_saisies.html
new file mode 100644 (file)
index 0000000..5380e0f
--- /dev/null
@@ -0,0 +1,46 @@
+[(#REM) 
+  
+  ### /!\ boucle POUR (spip Bonux) ###
+  
+  Génère le contenu (l'intérieur) d'un formulaire, à partir d'une description dans un tableau PHP.
+  Le tableau doit être de la forme suivante :
+  
+  // Chaque ligne est elle-même un tableau
+  array(
+       // Ligne de type "explication"
+       array(
+               'explication' => 'Ceci est un bloc d'explication général.'
+       ),
+       // Ligne classique, cad un champ de formulaire
+       array(
+               'saisie' => 'input',
+               'options => array(
+                       'nom' => 'mon_champ',
+                       'label' => 'Un joli titre',
+                       'obligatoire' => 'oui'
+               )
+       ),
+       // Ligne contenant un fieldset
+       array(
+               'groupe' => 'Ceci est le titre du groupe de champs (fieldset)',
+               'css' => 'eventuelles classes css',
+               'contenu' => array(
+                       // On recommence ici suivant le même formalisme que le tableau général.
+               )
+       )
+  )
+  
+  
+  Exemples d'appels :
+    # INCLURE{fond=inclure/generer_saisies, env, saisies=#ENV{tableau}}
+
+]
+
+<BOUCLE_contenu(POUR){tableau #ENV{saisies}}>
+[(#VAL{saisie}|array_key_exists{#VALEUR}|oui)
+[(#VALEUR**|saisies_generer_html{#ENV{_env}|sinon{#ENV**|unserialize}})]
+]
+</BOUCLE_contenu>
+
+[(#REM) Ajout du script js pour l'option si des saisies ]
+[(#ENV{from_fieldset}|non|et{#ENV{saisies}|saisies_afficher_si}) #INCLURE{fond=inclure/js_afficher_si,env}]
diff --git a/www/plugins/saisies/inclure/js_afficher_si.html b/www/plugins/saisies/inclure/js_afficher_si.html
new file mode 100644 (file)
index 0000000..6866cbe
--- /dev/null
@@ -0,0 +1,7 @@
+[(#REM) Ajout d'un marqueur unique pour identifier le formulaire]\r
+[(#SET{id_unique,#EVAL{'rand();'}})]\r
+<li id="afficher_si_#GET{id_unique}" style="display:none;" >\r
+<script type="text/javascript">// <![CDATA[\r
+[(#ENV**{saisies}|saisies_generer_js_afficher_si{#GET{id_unique}})]\r
+ //]]></script>\r
+ </li>
\ No newline at end of file
diff --git a/www/plugins/saisies/inclure/saisies_aide.html b/www/plugins/saisies/inclure/saisies_aide.html
new file mode 100644 (file)
index 0000000..4f3363b
--- /dev/null
@@ -0,0 +1,65 @@
+
+Sauter à : <a href="#liste_saisies">Toutes les saisies</a>, <a href="#liste_options_saisies">Toutes les options</a>
+
+<h2 class="h2 spip">Utilisation des options</h2>
+<B_options_tableau>
+<div style="overflow:auto;">
+<table class="spip">
+<thead>
+       <tr class="first_row">
+               <th>Options \ Saisies</th>
+               <BOUCLE_saisies_tableau_th(POUR){tableau #ENV{saisies}}>
+               <th><a href="#saisie_#CLE">#CLE</a></th>
+               </BOUCLE_saisies_tableau_th>
+       </tr>
+</thead>
+<tbody>
+       <BOUCLE_options_tableau(POUR){tableau #ENV{options}}>
+       <tr class="tr_liste [(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
+               <th><a href="#option_#CLE">#CLE</a></th>
+               <BOUCLE_saisies_tableau(POUR){tableau #ENV{saisies}}>
+               <td>[(#CLE|in_array{[(#_options_tableau:VALEUR|table_valeur{utilisee_par})]}|?{'X','-'})]</td>
+               </BOUCLE_saisies_tableau>
+       </tr>
+       </BOUCLE_options_tableau>
+</tbody>
+</table>
+</div>
+</B_options_tableau>
+
+<h2 class="h2 spip" id="liste_saisies">Toutes les saisies</h2>
+<BOUCLE_saisies(POUR){tableau #ENV{saisies}}>
+<h3 class="h3 spip" id="saisie_#CLE">[(#VALEUR|table_valeur{titre})] (#CLE)</h3>
+<p class="description">
+       <strong>Description :</strong> [(#VALEUR|table_valeur{description})]
+</p>
+<p class="options">
+       <strong>Options :</strong>
+       <BOUCLE_options_saisie(POUR){tableau #VALEUR|table_valeur{options}}{", "}><a href="#option_#CLE">#CLE</a></BOUCLE_options_saisie>
+</p>
+</BOUCLE_saisies>
+
+<h2 class="h2 spip" id="liste_options_saisies">Toutes les options</h2>
+<BOUCLE_options(POUR){tableau #ENV{options}}>
+[(#SET{label, [(#VALEUR|table_valeur{label}|sinon{[(#VALEUR|table_valeur{label_case})]})]})]
+<h3 class="h3 spip" id="option_#CLE">[(#GET{label}|?{#GET{label} [ ((#CLE))], #CLE})]</h3>
+[<p class="description">
+       <strong>Description :</strong> (#VALEUR|table_valeur{explication}|sinon{[(#VALEUR|table_valeur{label}|?{[(#VALEUR|table_valeur{label_case})]})]})
+</p>]
+<B_utilisee_par>
+<p class="utilisee_par">
+       <strong>Utilisée par :</strong>
+       <BOUCLE_utilisee_par(POUR){tableau #VALEUR|table_valeur{utilisee_par}}{", "}><a href="#saisie_#VALEUR">#VALEUR</a></BOUCLE_utilisee_par>
+</p>
+</B_utilisee_par>
+<B_choix>
+<p class="choix_possibles">
+       <strong>Choix possibles :</strong>
+       <ul class="spip">
+               <BOUCLE_choix(POUR){tableau #VALEUR|table_valeur{datas}}>
+               <li>"#CLE" : #VALEUR</li>
+               </BOUCLE_choix>
+       </ul>
+</p>
+</B_choix>
+</BOUCLE_options>
diff --git a/www/plugins/saisies/inclure/voir_saisies.html b/www/plugins/saisies/inclure/voir_saisies.html
new file mode 100644 (file)
index 0000000..7a77eee
--- /dev/null
@@ -0,0 +1,7 @@
+[(#REM) S'il y a des options afficher_si, il faut vérifier que les conditions sont remplies ]
+[(#SET{saisies,#ENV{saisies}|saisies_verifier_afficher_si{#ENV**|unserialize}})]
+<BOUCLE_saisies(POUR){tableau #GET{saisies}}>
+[(#VAL{saisie}|array_key_exists{#VALEUR}|oui)
+       [(#VALEUR|saisies_generer_vue{#ENV{_env}|sinon{#ENV**|unserialize}})]
+]
+</BOUCLE_saisies>
diff --git a/www/plugins/saisies/javascript/saisies.js b/www/plugins/saisies/javascript/saisies.js
new file mode 100644 (file)
index 0000000..4a588ee
--- /dev/null
@@ -0,0 +1,31 @@
+$(function(){
+       saisies_fieldset_pliable();
+       onAjaxLoad(saisies_fieldset_pliable);
+});
+
+function saisies_fieldset_pliable(){
+       // On cherche les groupes de champs pliables
+       $('li.fieldset.pliable')
+               .each(function(){
+                       var li = $(this);
+                       var ul = $(this).find('> fieldset > ul');
+                       var legend = $(this).find('> fieldset > .legend');
+                       
+                       // S'il est déjà plié on cache le contenu
+                       if (li.is('.plie'))
+                               ul.hide();
+                       
+                       // Ensuite on ajoute une action sur le titre
+                       legend
+                               .unbind('click')
+                               .click(
+                                       function(){
+                                               li.toggleClass('plie');
+                                               if (ul.is(':hidden'))
+                                                       ul.show();
+                                               else
+                                                       ul.hide();
+                                       }
+                               );
+               });
+};
diff --git a/www/plugins/saisies/lang/paquet-saisies.xml b/www/plugins/saisies/lang/paquet-saisies.xml
new file mode 100644 (file)
index 0000000..48b9aa8
--- /dev/null
@@ -0,0 +1,16 @@
+<traduction module="paquet-saisies" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/saisies/lang/" reference="fr">
+       <langue code="de" url="http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=de">
+               <traducteur nom="klaus++" lien="http://trad.spip.net/auteur/klaus" />
+       </langue>
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/saisies/lang/paquet-saisies_de.php b/www/plugins/saisies/lang/paquet-saisies_de.php
new file mode 100644 (file)
index 0000000..4fb90f5
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'saisies_description' => 'Dieses Plugin erleichtert die Erstellung von Eingabefeldern für Formulare und bietet einen Tag #SAISIE. Das erzeugte HTML ist mit der Nomenklatur der von SPIP > 2.0 und dem Plugin CFG kompatibel.',
+       'saisies_nom' => 'Eingabefelder für Formulare',
+       'saisies_slogan' => 'Unkompliziertes Erstellen von Eingabefeldern für Formulare.',
+       'saisies_titre' => 'Eingabefelder für Formulare'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/paquet-saisies_en.php b/www/plugins/saisies/lang/paquet-saisies_en.php
new file mode 100644 (file)
index 0000000..ac252f3
--- /dev/null
@@ -0,0 +1,19 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'saisies_description' => 'This plugin makes it easier to write form fields by providing a #SAISIE tag. 
+               The generated HTML is compatible with the classification of forms
+               proposed by SPIP > 2.0 and with the configuration plugin CFG.',
+       'saisies_nom' => 'Entries for forms',
+       'saisies_slogan' => 'Create easily forms fields.',
+       'saisies_titre' => 'Entries for forms'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/paquet-saisies_es.php b/www/plugins/saisies/lang/paquet-saisies_es.php
new file mode 100644 (file)
index 0000000..eb06ed8
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'saisies_description' => 'Este plugin permite facilitar la redacción de campos de formularios proponiendo una etiqueta #SAISIE. El HTML generado es compatible con la nomenclatura de los formularios propuestos por SPIP > 2.0 y con el plugin de configuración CFG.',
+       'saisies_nom' => 'Entradas para formularios',
+       'saisies_slogan' => 'Escribir fácilmente los campos de formularios.',
+       'saisies_titre' => 'Entradas para formularios'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/paquet-saisies_fr.php b/www/plugins/saisies/lang/paquet-saisies_fr.php
new file mode 100644 (file)
index 0000000..2edcbf9
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/saisies/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'saisies_description' => 'Ce plugin permet de faciliter l\'écriture de champs de formulaires en proposant une
+               balise #SAISIE. Le HTML généré est compatible avec la nomenclature des formulaires
+               proposée par SPIP > 2.0 et avec le plugin de configuration CFG.',
+       'saisies_nom' => 'Saisies pour formulaires',
+       'saisies_slogan' => 'Écrire facilement des champs de formulaires.',
+       'saisies_titre' => 'Saisies pour formulaires'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/paquet-saisies_ru.php b/www/plugins/saisies/lang/paquet-saisies_ru.php
new file mode 100644 (file)
index 0000000..1fc60c0
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'saisies_description' => 'Этот плагин облегчает работу по созданию форм. Вам предоставляется возможность создавать поля (input,textarea) в форме при помощи тега #SAISIE. Полученная форма полностью совместима со стандартом  SPIP 2.0+ и c плагином CFG.',
+       'saisies_nom' => 'Поля для форм (saises)',
+       'saisies_slogan' => 'Упрощение работы по созданию форм',
+       'saisies_titre' => 'Поля для форм (saises)'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/paquet-saisies_sk.php b/www/plugins/saisies/lang/paquet-saisies_sk.php
new file mode 100644 (file)
index 0000000..406bad6
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-saisies?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'saisies_description' => 'Tento zásuvný modul uľahčuje zápis polí formulára ponúknutím tagu #INPUT. Vytvorený kód HTML je kompatibilný s klasifikáciou formulárov, ktorú ponúka SPIP > 2.0 a so zásuvným modulom na konfiguráciu – CFG.',
+       'saisies_nom' => 'Vstupy pre formuláre',
+       'saisies_slogan' => 'Jednoduchý zápis polí formulárov.',
+       'saisies_titre' => 'Vstupy pre formuláre'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies.xml b/www/plugins/saisies/lang/saisies.xml
new file mode 100644 (file)
index 0000000..5fb936b
--- /dev/null
@@ -0,0 +1,28 @@
+<traduction module="saisies" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/saisies/lang/" reference="fr">
+       <langue code="ca" />
+       <langue code="de" url="http://trad.spip.net/tradlang_module/saisies?lang_cible=de">
+               <traducteur nom="klaus++" lien="http://trad.spip.net/auteur/klaus" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/saisies?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+               <traducteur nom="Paolo" lien="http://trad.spip.net/auteur/paolo" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/saisies?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/saisies?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="fr_tu" url="http://trad.spip.net/tradlang_module/saisies?lang_cible=fr_tu">
+               <traducteur nom="beatnick" lien="http://trad.spip.net/auteur/beatnick" />
+       </langue>
+       <langue code="it" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/saisies?lang_cible=ru">
+               <traducteur nom="nazar" lien="http://trad.spip.net/auteur/nazar" />
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/saisies?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/saisies/lang/saisies_ca.php b/www/plugins/saisies/lang/saisies_ca.php
new file mode 100644 (file)
index 0000000..9579db8
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=ca
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Fullejar l\'article',
+       'bouton_parcourir_docs_breve' => 'Fullejar la breu',
+       'bouton_parcourir_docs_rubrique' => 'Fullejar la secció',
+       'bouton_parcourir_mediatheque' => 'Fullejar la mediateca',
+
+       // C
+       'construire_action_annuler' => 'Annuler', # NEW
+       'construire_action_configurer' => 'Configurer', # NEW
+       'construire_action_deplacer' => 'Déplacer', # NEW
+       'construire_action_dupliquer' => 'Dupliquer', # NEW
+       'construire_action_dupliquer_copie' => '(copie)', # NEW
+       'construire_action_supprimer' => 'Supprimer', # NEW
+       'construire_ajouter_champ' => 'Ajouter un champ', # NEW
+       'construire_attention_enregistrer' => 'N\'oubliez pas d\'enregistrer vos modifications !', # NEW
+       'construire_attention_modifie' => 'Le formulaire ci-dessous est différent du formulaire initial. Vous avez la possibilité de le réinitialiser à son état avant vos modifications.', # NEW
+       'construire_attention_supprime' => 'Vos modifications comportent des suppressions de champs. Veuillez confirmer l\'enregistrement de cette nouvelle version du formulaire.', # NEW
+       'construire_aucun_champs' => 'Il n\'y a pour l\'instant aucun champ dans ce formulaire.', # NEW
+       'construire_confirmer_supprimer_champ' => 'Voulez-vous vraiment supprimer ce champ ?', # NEW
+       'construire_info_nb_champs_masques' => '@nb@ champ(s) masqué(s) le temps de configurer le groupe.', # NEW
+       'construire_position_explication' => 'Indiquez devant quel autre champ sera placé celui-ci.', # NEW
+       'construire_position_fin_formulaire' => 'À la fin du formulaire', # NEW
+       'construire_position_fin_groupe' => 'À la fin du groupe @groupe@', # NEW
+       'construire_position_label' => 'Position du champ', # NEW
+       'construire_reinitialiser' => 'Réinitialiser le formulaire', # NEW
+       'construire_reinitialiser_confirmer' => 'Vous allez perdre toutes vos modifications. Êtes-vous sûr de vouloir revenir au formulaire initial ?', # NEW
+       'construire_verifications_aucune' => 'Aucune', # NEW
+       'construire_verifications_label' => 'Type de vérification à effectuer', # NEW
+
+       // E
+       'erreur_generique' => 'Il y a des erreurs dans les champs ci-dessous, veuillez vérifier vos saisies', # NEW
+       'erreur_option_nom_unique' => 'Ce nom est déjà utilisé par un autre champ et il doit être unique dans ce formulaire.', # NEW
+
+       // I
+       'info_configurer_saisies' => 'Page de test des Saisies', # NEW
+
+       // L
+       'label_annee' => 'Any',
+       'label_jour' => 'Dia',
+       'label_mois' => 'Mes',
+
+       // O
+       'option_aff_art_interface_explication' => 'Afficher uniquement les articles de la langue de l\'utilisateur', # NEW
+       'option_aff_art_interface_label' => 'Affichage multilingue', # NEW
+       'option_aff_langue_explication' => 'Affiche la langue de l\'article ou rubrique sélectionné devant le titre', # NEW
+       'option_aff_langue_label' => 'Afficher la langue', # NEW
+       'option_aff_rub_interface_explication' => 'Afficher uniquement les rubriques de la langue de l\'utilisateur', # NEW
+       'option_aff_rub_interface_label' => 'Affichage multilingue', # NEW
+       'option_attention_explication' => 'Un missatge més important que l\'explicació.',
+       'option_attention_label' => 'Advertència',
+       'option_autocomplete_defaut' => 'Laisser par défaut', # NEW
+       'option_autocomplete_explication' => 'Au chargement de la page, votre navigateur peut pré-remplir le champ en fonction de son historique', # NEW
+       'option_autocomplete_label' => 'Pré-remplissage du champ', # NEW
+       'option_autocomplete_off' => 'Désactiver', # NEW
+       'option_autocomplete_on' => 'Activer', # NEW
+       'option_cacher_option_intro_label' => 'Amagar la primera elecció buida',
+       'option_choix_destinataires_explication' => 'Un o diversos autors, d\'entre els quals hi ha l\'usuari, podrà fer la seva tria. Si no hi ha res seleccionat, és l\'autor que ha instal·lat el lloc el que serà escollit.',
+       'option_choix_destinataires_label' => 'Possibles destinataris',
+       'option_class_label' => 'Classes CSS suplementàries',
+       'option_cols_explication' => 'Amplada del bloc en número de caràcters. Aquesta opció no s\'aplica sempre ja que els estils CSS del vostre lloc el poden anul·lar.', # MODIF
+       'option_cols_label' => 'Amplada',
+       'option_datas_explication' => 'Heu d\'especificar una opció per línia en la forma "cle|Label du choix"',
+       'option_datas_label' => 'Llista d\'eleccions possibles',
+       'option_defaut_label' => 'Valor per defecte',
+       'option_disable_avec_post_explication' => 'Idèntic que l\'opció anterior però tanmateix envia el valor dins d\'un camps amagat.',
+       'option_disable_avec_post_label' => 'Desactivar però enviar',
+       'option_disable_explication' => 'El camp no pot obtenir el focus.',
+       'option_disable_label' => 'Desactivar el camp',
+       'option_erreur_obligatoire_explication' => 'Vous pouvez personnaliser le message d\'erreur affiché pour indiquer l\'obligation (sinon laisser vide).', # NEW
+       'option_erreur_obligatoire_label' => 'Message d\'obligation', # NEW
+       'option_explication_explication' => 'Si és necessari, una frase curta descriu l\'objecte del camp.',
+       'option_explication_label' => 'Explicació',
+       'option_groupe_affichage' => 'Visualització',
+       'option_groupe_description' => 'Descripció',
+       'option_groupe_utilisation' => 'Utilització',
+       'option_groupe_validation' => 'Validació',
+       'option_heure_pas_explication' => 'Lorsque vous utilisez l’horaire, un menu s’affiche pour aider à saisir heures et minutes. Vous pouvez ici choisir l’intervalle de temps entre chaque choix (par défaut 30min).', # NEW
+       'option_heure_pas_label' => 'Intervalle des minutes dans le menu d’aide à la saisie', # NEW
+       'option_horaire_label' => 'Horaire', # NEW
+       'option_horaire_label_case' => 'Permettre de saisie aussi l’horaire', # NEW
+       'option_info_obligatoire_explication' => 'Podeu, per defecte, modificar la indicació d\'obligació: <i>[Obligatoire]</i>.',
+       'option_info_obligatoire_label' => 'Indicació d\'obligació',
+       'option_inserer_barre_choix_edition' => 'barra d\'edició completa',
+       'option_inserer_barre_choix_forum' => 'barra dels fòrums',
+       'option_inserer_barre_explication' => 'Insereix una barra d\'eines del portaplomes si aquest està activat.',
+       'option_inserer_barre_label' => 'Inserir una barra d\'eines',
+       'option_label_case_label' => 'Etiqueta situada al costat de la casella',
+       'option_label_explication' => 'El títol que es mostrarà.',
+       'option_label_label' => 'Etiqueta',
+       'option_maxlength_explication' => 'L\'usuari no podrà escriure més caràcters que aquest nombre.',
+       'option_maxlength_label' => 'Número màxim de caràcters',
+       'option_multiple_explication' => 'L\'utilisateur pourra sélectionner plusieurs valeurs', # NEW
+       'option_multiple_label' => 'Sélection multiple', # NEW
+       'option_nom_explication' => 'Un nom informàtic que identificarà el camp. Ha de contenir només caràcters alfanumèrics minúsculs o el caràcter "_".', # MODIF
+       'option_nom_label' => 'Nom del camp',
+       'option_obligatoire_label' => 'Camp obligatori',
+       'option_option_intro_label' => 'Etiqueta de la primera elecció buida',
+       'option_option_statut_label' => 'Afficher les statuts', # NEW
+       'option_pliable_label' => 'Plegable',
+       'option_pliable_label_case' => 'El grup de camps es podrà replegar.',
+       'option_plie_label' => 'Ja plegat',
+       'option_plie_label_case' => 'Si el grup de camps és plegable, ja estarà plegat a la visualització del formulari.',
+       'option_previsualisation_explication' => 'Si el portaplomes està activat, afegit una pestanya per fer una visualització prèvia del text introduït. ',
+       'option_previsualisation_label' => 'Activar la visualització prèvia',
+       'option_readonly_explication' => 'El camp es pot llegir, seleccionar, però no modificar.',
+       'option_readonly_label' => 'Només lectura',
+       'option_rows_explication' => 'Alçada del bloc en número de línies. Aquesta opció no es pot aplicar sempre ja que els estils CSS del vostre lloc el poden anul·lar.',
+       'option_rows_label' => 'Número de línies',
+       'option_size_explication' => 'Amplada del camp en número de caràcters. Aquesta opció no es pot aplicar sempre ja que els estils CSS del vostre lloc el poden anul·lar. ',
+       'option_size_label' => 'Mida del camp',
+       'option_type_choix_plusieurs' => 'Permetrà a l\'usuari escollir <strong>diversos</strong> destinataris.', # MODIF
+       'option_type_choix_tous' => 'Posar <strong>tots</strong> aquests autors com a destinataris. L\'usuari no tindrà cap tria.',
+       'option_type_choix_un' => 'Permetre a l\'usuari escollir <strong>un únic</strong> destinatari.', # MODIF
+       'option_type_explication' => 'En mode "amagat", el contingut del camp no serà visible.',
+       'option_type_label' => 'Tipus del camp',
+       'option_type_password' => 'Amagat',
+       'option_type_text' => 'Normal',
+
+       // S
+       'saisie_auteurs_explication' => 'Permet de sélectionner un ou plusieurs auteurs', # NEW
+       'saisie_auteurs_titre' => 'Auteurs', # NEW
+       'saisie_case_explication' => 'Permet activar o desactivar alguna cosa.',
+       'saisie_case_titre' => 'Casella única',
+       'saisie_checkbox_explication' => 'Permet escollir diverses opcions amb caselles.',
+       'saisie_checkbox_titre' => 'Caselles a marcar', # MODIF
+       'saisie_date_explication' => 'Permet de saisir une date ? l\'aide d\'un calendrier', # NEW
+       'saisie_date_titre' => 'Date', # NEW
+       'saisie_destinataires_explication' => 'Permet escollir un o diversos destinataris entre els autors seleccionats prèviament.',
+       'saisie_destinataires_titre' => 'Destinataris',
+       'saisie_explication_explication' => 'Un text explicatiu general.',
+       'saisie_explication_titre' => 'Explicació',
+       'saisie_fieldset_explication' => 'Un quadre que podrà englobar diversos camps.',
+       'saisie_fieldset_titre' => 'Grup de camps',
+       'saisie_file_explication' => 'Enviament d\'un arxiu ',
+       'saisie_file_titre' => 'Arxiu',
+       'saisie_hidden_explication' => 'Un camp omplert prèviament que l\'usuari no podrà veure.',
+       'saisie_hidden_titre' => 'Camp amagat',
+       'saisie_input_explication' => 'Una simple línia de text, que podrà ser visible o estar amagada (contrasenya).',
+       'saisie_input_titre' => 'Línia de text',
+       'saisie_oui_non_explication' => 'Si o no, està clar? :)',
+       'saisie_oui_non_titre' => 'Si o no ',
+       'saisie_radio_defaut_choix1' => 'Un',
+       'saisie_radio_defaut_choix2' => 'Dos',
+       'saisie_radio_defaut_choix3' => 'Tres',
+       'saisie_radio_explication' => 'Permet escollir una opció entre les diverses disponibles.',
+       'saisie_radio_titre' => 'Botons ràdios',
+       'saisie_selecteur_article' => 'Affiche un navigateur de sélection d\'article', # NEW
+       'saisie_selecteur_article_titre' => 'Sélecteur d\'article', # NEW
+       'saisie_selecteur_rubrique' => 'Affiche un navigateur de sélection de rubrique', # NEW
+       'saisie_selecteur_rubrique_article' => 'Affiche un navigateur de sélection d\'article ou de rubrique', # NEW
+       'saisie_selecteur_rubrique_article_titre' => 'Sélecteur d\'article ou rubrique', # NEW
+       'saisie_selecteur_rubrique_titre' => 'Sélecteur de rubrique', # NEW
+       'saisie_selection_explication' => 'Escollir una opció en una llista desplegable.', # MODIF
+       'saisie_selection_multiple_explication' => 'Permet escollir diverses opcions amb una llista.',
+       'saisie_selection_multiple_titre' => 'Selecció múltiple',
+       'saisie_selection_titre' => 'Llista desplegable',
+       'saisie_textarea_explication' => 'Un camp de text en diverses línies.',
+       'saisie_textarea_titre' => 'Bloc de text',
+
+       // T
+       'tous_visiteurs' => 'Tots els visitants (fins i tot els no registrats)',
+       'tout_selectionner' => 'Tout sélectionner', # NEW
+
+       // V
+       'vue_sans_reponse' => '<i>Sense resposta</i>', # MODIF
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_de.php b/www/plugins/saisies/lang/saisies_de.php
new file mode 100644 (file)
index 0000000..c55a121
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Artikel durchsuchen',
+       'bouton_parcourir_docs_breve' => 'Meldung durchsuchen',
+       'bouton_parcourir_docs_rubrique' => 'Rubrik durchsuchen',
+       'bouton_parcourir_mediatheque' => 'Mediathek durchsuchen',
+
+       // C
+       'construire_action_annuler' => 'Abbrechen',
+       'construire_action_configurer' => 'Konfigurieren',
+       'construire_action_deplacer' => 'Verschieben',
+       'construire_action_dupliquer' => 'Duplizieren',
+       'construire_action_dupliquer_copie' => '(Kopie)',
+       'construire_action_supprimer' => 'Löschen',
+       'construire_ajouter_champ' => 'Feld hinzufügen',
+       'construire_attention_enregistrer' => 'Vergessen Sie nicht, Ihre Änderungen zu speichern.',
+       'construire_attention_modifie' => 'Das untere Formular unterscheidet sich vom ursprünglichen. Sie können es in den Zustand vor den Änderungen zurücksetzen.',
+       'construire_attention_supprime' => 'Ihre Änderungen umfassen das Löschen von Feldern. Bitte bestätigen das Speichern dieser neuen Version des Formulars.',
+       'construire_aucun_champs' => 'Dieses Formular enthält noch keine Felder.',
+       'construire_confirmer_supprimer_champ' => 'Wollen Sie dieses Feld wirklich löschen?',
+       'construire_info_nb_champs_masques' => '@nb@ Feld/er während der Konfiguration der Gruppe ausgeblendet.',
+       'construire_position_explication' => 'Geben Sie an, vor welchem anderen Feld dieses erscheinen soll.',
+       'construire_position_fin_formulaire' => 'Am Ende des Formulars',
+       'construire_position_fin_groupe' => 'Am Ende der Gruppe @groupe@',
+       'construire_position_label' => 'Feldposition',
+       'construire_reinitialiser' => 'Formular neu initialisieren',
+       'construire_reinitialiser_confirmer' => 'Alle Ihre Änderungen werden verlorengehen. Wollen Sie wirklich das ursprüngliche Formular wieder herstellen?',
+       'construire_verifications_aucune' => 'Keine',
+       'construire_verifications_label' => 'Art der Überprüfung',
+
+       // E
+       'erreur_generique' => 'Fehler im folgenden Feld. Bitte überprüfen Sie Ihre Eingabe.',
+       'erreur_option_nom_unique' => 'Dieser Name wird bereits für ein anderes Feld verwendet; er kann in diesem Formular nur einmal verwendet werden.',
+
+       // I
+       'info_configurer_saisies' => 'Testseite der Eingabefelder.',
+
+       // L
+       'label_annee' => 'Jahr',
+       'label_jour' => 'Tag',
+       'label_mois' => 'Monat',
+
+       // O
+       'option_aff_art_interface_explication' => 'Ausschließlich Artikel in der Sprache des Nutzers anzeigen',
+       'option_aff_art_interface_label' => 'Mehrsprachige Anzeige',
+       'option_aff_langue_explication' => 'Sprache des ausgewählten Artikels oder der Rubrik vor dem Titel anzeigen',
+       'option_aff_langue_label' => 'Sprache anzeigen',
+       'option_aff_rub_interface_explication' => 'Ausschließlich Rubriken in der Sprache des Nutzers anzeigen',
+       'option_aff_rub_interface_label' => 'Mehrsprachige Anzeige',
+       'option_attention_explication' => 'Nachricht wichtiger als Meldung',
+       'option_attention_label' => 'Achtung',
+       'option_autocomplete_defaut' => 'Standardeinstellung belassen',
+       'option_autocomplete_explication' => 'Beim Laden der Seite kann Ihr Browser das Feld mit bereits verwendeten Werten vorausfüllen.',
+       'option_autocomplete_label' => 'Feld vorausfüllen',
+       'option_autocomplete_off' => 'Deaktivieren',
+       'option_autocomplete_on' => 'Aktivieren',
+       'option_cacher_option_intro_label' => 'Erste leere Auswahl ausblenden',
+       'option_choix_destinataires_explication' => 'Einer oder mehrere Empfänger, welche der Besucher auswählen kann. Wenn er keine Auswahl trifft, geht die Nachricht an den ersten Administrator (Autor 1).',
+       'option_choix_destinataires_label' => 'Mögliche Empfänger',
+       'option_class_label' => 'Zusätzliche CSS-Klassen',
+       'option_cols_explication' => 'Breite des Blocks in Zeichen. Diese Option kann durch ihre CSS-Stile unwirksam grmacht werden.',
+       'option_cols_label' => 'Breite',
+       'option_datas_explication' => 'Sie müssen in jeder Zeile eine Option im Format "Schlüssel|Bezeichnung" angeben.',
+       'option_datas_label' => 'Mögliche Angaben',
+       'option_defaut_label' => 'Standardwert',
+       'option_disable_avec_post_explication' => 'Identisch mit voriger Option, jedoch wird der Wert in ein verstecktes Feld eingefügt.',
+       'option_disable_avec_post_label' => 'Senden trotz Deaktivierung',
+       'option_disable_explication' => 'Das Feld erhält keinen Fokus.',
+       'option_disable_label' => 'Feld deaktivieren',
+       'option_erreur_obligatoire_explication' => 'Sie können eine eigene Fehlermeldung bei nicht ausgefüllten Pflichtfeldern eingeben oder darauf verzichten.',
+       'option_erreur_obligatoire_label' => 'Hinweis Pflichtfeld',
+       'option_explication_explication' => 'Falls erforderlich kurze Beschreibung des Feldobjekts',
+       'option_explication_label' => 'Erläuterung',
+       'option_groupe_affichage' => 'Anzeige',
+       'option_groupe_description' => 'Beschreibung',
+       'option_groupe_utilisation' => 'Verwendung',
+       'option_groupe_validation' => 'Bestätigung',
+       'option_heure_pas_explication' => 'Lorsque vous utilisez l’horaire, un menu s’affiche pour aider à saisir heures et minutes. Vous pouvez ici choisir l’intervalle de temps entre chaque choix (par défaut 30min).', # NEW
+       'option_heure_pas_label' => 'Intervalle des minutes dans le menu d’aide à la saisie', # NEW
+       'option_horaire_label' => 'Horaire', # NEW
+       'option_horaire_label_case' => 'Permettre de saisie aussi l’horaire', # NEW
+       'option_info_obligatoire_explication' => 'Sie können die Standardbezeichnung für Pflichtfelder ändern:<i>[Pflichtfeld]</i>.',
+       'option_info_obligatoire_label' => 'Pflichtfeld-Anzeige',
+       'option_inserer_barre_choix_edition' => 'Vollständige Symbolleiste "Bearbeiten"',
+       'option_inserer_barre_choix_forum' => 'Symbolleiste "Foren"',
+       'option_inserer_barre_explication' => 'Eine Symbolleiste hinzufügen, wenn das Plugin Porte-Plume aktiviert ist.',
+       'option_inserer_barre_label' => 'Symbolleiste einfügen',
+       'option_label_case_label' => 'Bezeichnung neben dem Feld',
+       'option_label_explication' => 'Anzeigetitel',
+       'option_label_label' => 'Bezeichnung',
+       'option_maxlength_explication' => 'Der Besucher kann maximal diese Anzahl Zeichen eingeben',
+       'option_maxlength_label' => 'Zeichen maximal',
+       'option_multiple_explication' => 'Der Nutzer kann mehrere Optionen auswählen',
+       'option_multiple_label' => 'Mehrfachauswahl',
+       'option_nom_explication' => 'Reserviertes Wort für das Feld. Darf nur alphanumerische klein geschriebene und das Zeichen "_" (Unterstrich) enthalten.',
+       'option_nom_label' => 'Feldname',
+       'option_obligatoire_label' => 'Pflichtfeld',
+       'option_option_intro_label' => 'Bezeichnung der ersten leeren Auswahl',
+       'option_option_statut_label' => 'Status anzeigen',
+       'option_pliable_label' => 'Klappbar',
+       'option_pliable_label_case' => 'Die Feldgruppe kann zugeklappt werden',
+       'option_plie_label' => 'Bereits zugeklappt',
+       'option_plie_label_case' => 'Wen die Feldgruppe klappbar ist, wird sie beim Anzeigen des Formulars zunächst zugeklappt angezeigt.',
+       'option_previsualisation_explication' => 'Reiter "Vorschau" hinzufügen, wenn das Plugin Porte-Plume aktiviert ist.',
+       'option_previsualisation_label' => 'Vorschau aktivieren',
+       'option_readonly_explication' => 'Dieses Feld kann angezeigt aber nicht bearbeitet werden.',
+       'option_readonly_label' => 'Nur Lesen',
+       'option_rows_explication' => 'Höhe des Blocks in Zeilen. Diese Option ist nicht immer wirksam, da sie von individuellen CSS-Stilen abgeschaltet werden kann.',
+       'option_rows_label' => 'Anzahl Zeilen',
+       'option_size_explication' => 'Breite des Felds in Zeichen. Diese Option ist nicht immer wirksam, da sie durch individuelle CSS.Stile abgeschaltet werden kann.',
+       'option_size_label' => 'Feldgröße',
+       'option_type_choix_plusieurs' => 'Auswahl <strong>mehrerer</strong> Empfänger erlauben',
+       'option_type_choix_tous' => '<strong>Alle</strong> diese Autoren als Empfänger hinzufügen. Der Besucher kann keine Auswahl treffen.',
+       'option_type_choix_un' => 'Der Besucher kann nur <strong>einen einzigen</strong> Empfänger auswählen.',
+       'option_type_explication' => 'Im "versteckten" Modus wird der Inhalt dieses Felds nicht angezeigt.',
+       'option_type_label' => 'Feldtyp',
+       'option_type_password' => 'Versteckt',
+       'option_type_text' => 'Normal',
+
+       // S
+       'saisie_auteurs_explication' => 'Ermöglicht einen oder mehrere Autoren auszuwählen',
+       'saisie_auteurs_titre' => 'Autoren',
+       'saisie_case_explication' => 'Ermöglicht Dinge zu aktivieren und deaktivieren',
+       'saisie_case_titre' => 'Nur eine Option',
+       'saisie_checkbox_explication' => 'Erlaubt mehrer Optionen auszuwählen',
+       'saisie_checkbox_titre' => 'Kästchen zum Abhaken',
+       'saisie_date_explication' => 'Datum aus Kalendarium auswählen',
+       'saisie_date_titre' => 'Datum',
+       'saisie_destinataires_explication' => 'Ermöglicht mehrere Empfänger aus den vorgeschlagenen Autoren auszuwählen',
+       'saisie_destinataires_titre' => 'Empfänger',
+       'saisie_explication_explication' => 'Allgemeine Beschreibung',
+       'saisie_explication_titre' => 'Beschreibung',
+       'saisie_fieldset_explication' => 'Ein Rahmen, der mehrere Felder enthalten kann',
+       'saisie_fieldset_titre' => 'Feldgruppe',
+       'saisie_file_explication' => 'Datei senden',
+       'saisie_file_titre' => 'Datei',
+       'saisie_hidden_explication' => 'Ein für den Nutzer unsichtbares, vorab ausgefülltes Feld',
+       'saisie_hidden_titre' => 'Verborgenes Feld',
+       'saisie_input_explication' => 'Eine einfache Textzeile, kann angezeigt oder ausgeblendet werden (Passwort)',
+       'saisie_input_titre' => 'Textzeile',
+       'saisie_oui_non_explication' => 'Ja oder nein, alle klar ? :)',
+       'saisie_oui_non_titre' => 'Ja oder nein',
+       'saisie_radio_defaut_choix1' => 'Eins',
+       'saisie_radio_defaut_choix2' => 'Zwei',
+       'saisie_radio_defaut_choix3' => 'Drei',
+       'saisie_radio_explication' => 'Ermöglicht eine Option aus mehreren verfügbaren auszuwählen',
+       'saisie_radio_titre' => 'Radioknöpfe',
+       'saisie_selecteur_article' => 'Werkzeug zur Auswahl eines Artikels anzeigen',
+       'saisie_selecteur_article_titre' => 'Artikelwahl',
+       'saisie_selecteur_rubrique' => 'Werkzeug zur Auswahl einer Rubrik anzeigen',
+       'saisie_selecteur_rubrique_article' => 'Werkzeug zur Auswahl einer Rubrik oder eines Artikels anzeigen',
+       'saisie_selecteur_rubrique_article_titre' => 'Rubrik- oder Artikelwahl',
+       'saisie_selecteur_rubrique_titre' => 'Rubrikwahl',
+       'saisie_selection_explication' => 'Eine Option aus einer Drop-Down-Liste auswählen.',
+       'saisie_selection_multiple_explication' => 'Mehrere Optionen aus einer Liste auswählen',
+       'saisie_selection_multiple_titre' => 'Mehrfachauswahl',
+       'saisie_selection_titre' => 'Drop-Down-Liste',
+       'saisie_textarea_explication' => 'Mehrzeiliges Textfeld',
+       'saisie_textarea_titre' => 'Textblock',
+
+       // T
+       'tous_visiteurs' => 'Alle Besucher (auch nicht eingeschriebene)',
+       'tout_selectionner' => 'Alles auswählen',
+
+       // V
+       'vue_sans_reponse' => '<i>Ohne Antwort</i>',
+
+       // Z
+       'z' => 'Zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_en.php b/www/plugins/saisies/lang/saisies_en.php
new file mode 100644 (file)
index 0000000..dddd5e0
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Browse through the article',
+       'bouton_parcourir_docs_breve' => 'Browse through the news item',
+       'bouton_parcourir_docs_rubrique' => 'Browse through the section',
+       'bouton_parcourir_mediatheque' => 'Browse through the multimedia library',
+
+       // C
+       'construire_action_annuler' => 'Cancel',
+       'construire_action_configurer' => 'Set up',
+       'construire_action_deplacer' => 'Move',
+       'construire_action_dupliquer' => 'Duplicate',
+       'construire_action_dupliquer_copie' => '(copy)',
+       'construire_action_supprimer' => 'Delete',
+       'construire_ajouter_champ' => 'Add a field',
+       'construire_attention_enregistrer' => 'Remember to save your changes!',
+       'construire_attention_modifie' => 'The form below is different from the initial form. You can reset it to the state before the changes.',
+       'construire_attention_supprime' => 'Your changes include deletions of fields. Please confirm the registration of the new version of the form.',
+       'construire_aucun_champs' => 'There is currently no field in this form.',
+       'construire_confirmer_supprimer_champ' => 'Do you really want to delete this field?',
+       'construire_info_nb_champs_masques' => '@nb@ hidden field(s) the time to set up the group.',
+       'construire_position_explication' => 'Specify before which other field this one should be placed.',
+       'construire_position_fin_formulaire' => 'At the end of the form',
+       'construire_position_fin_groupe' => 'At the end of the group @groupe@',
+       'construire_position_label' => 'Position of the field',
+       'construire_reinitialiser' => 'Reset form',
+       'construire_reinitialiser_confirmer' => 'You will lose all your changes. Are you sure you want to go back to the original form?',
+       'construire_verifications_aucune' => 'None',
+       'construire_verifications_label' => 'Type of verification to be performed',
+
+       // E
+       'erreur_generique' => 'There are errors in the fields below, please check your inputs',
+       'erreur_option_nom_unique' => 'This name is already used by another field and it must be unique in this form.',
+
+       // I
+       'info_configurer_saisies' => 'Test page for Entries',
+
+       // L
+       'label_annee' => 'Year',
+       'label_jour' => 'Day',
+       'label_mois' => 'Month',
+
+       // O
+       'option_aff_art_interface_explication' => 'Display only the articles in the user\'s language',
+       'option_aff_art_interface_label' => 'Multilingual display',
+       'option_aff_langue_explication' => 'Display the selected language of the article or section before the title',
+       'option_aff_langue_label' => 'Display the language',
+       'option_aff_rub_interface_explication' => 'Display only the sections in the user\'s language',
+       'option_aff_rub_interface_label' => 'Multilingual display',
+       'option_attention_explication' => 'A message more important than the explanation.',
+       'option_attention_label' => 'Warning',
+       'option_autocomplete_defaut' => 'Leave the default',
+       'option_autocomplete_explication' => 'At page load, your browser may pre-fill the field based on its history',
+       'option_autocomplete_label' => 'Pre-fill the field',
+       'option_autocomplete_off' => 'Disable',
+       'option_autocomplete_on' => 'Enable',
+       'option_cacher_option_intro_label' => 'Hide the first empty choice',
+       'option_choix_destinataires_explication' => 'One or several authors among which the user can make his choice. If nothing selected, it will be the author who installed the site to be chosen.',
+       'option_choix_destinataires_label' => 'Possible recipients',
+       'option_class_label' => 'Additional CSS Classes',
+       'option_cols_explication' => 'Field width in characters. This option is not always applied/used because the CSS styles of your site may override it.',
+       'option_cols_label' => 'Width',
+       'option_datas_explication' => 'You need to specify a choice for each row in the form of "key|label of the choice"',
+       'option_datas_label' => 'List of the available choices',
+       'option_defaut_label' => 'Default value',
+       'option_disable_avec_post_explication' => 'Same as previous option position but still post value in a hidden field.',
+       'option_disable_avec_post_label' => 'Disabled but posted.',
+       'option_disable_explication' => 'The field can not get the focus.',
+       'option_disable_label' => 'Disable the field',
+       'option_erreur_obligatoire_explication' => 'You can customize the error message displayed to show an obligation (otherwise leave blank).',
+       'option_erreur_obligatoire_label' => 'Obligation message',
+       'option_explication_explication' => 'If necessary, a short sentence describing the subject field.',
+       'option_explication_label' => 'Explanation',
+       'option_groupe_affichage' => 'Display',
+       'option_groupe_description' => 'Description',
+       'option_groupe_utilisation' => 'Usage',
+       'option_groupe_validation' => 'Validation',
+       'option_heure_pas_explication' => 'When using the schedule, a menu is displayed to help enter hours and minutes. Here you can choose the time interval between each option (default 30 minutes).',
+       'option_heure_pas_label' => 'Interval of the minutes in the help menu of the input',
+       'option_horaire_label' => 'Schedule',
+       'option_horaire_label_case' => 'Allow to fill in the time',
+       'option_info_obligatoire_explication' => 'You can modify the default indication of obligation: <i>[Obligatoire]</i>.',
+       'option_info_obligatoire_label' => 'Indication of obligation',
+       'option_inserer_barre_choix_edition' => 'complete editing toolbar',
+       'option_inserer_barre_choix_forum' => 'forums toolbar',
+       'option_inserer_barre_explication' => 'Insert a porte-plume toolbar if that tool is activated.',
+       'option_inserer_barre_label' => 'Insert a toolbar',
+       'option_label_case_label' => 'Label located beside the check box',
+       'option_label_explication' => 'The title that will be displayed.',
+       'option_label_label' => 'Label',
+       'option_maxlength_explication' => 'The user can not type more characters than this number.',
+       'option_maxlength_label' => 'Maximum number of characters',
+       'option_multiple_explication' => 'The user will be able to select several values',
+       'option_multiple_label' => 'Multiple selection',
+       'option_nom_explication' => 'A computer ID name that identifies the field. It may only contain lowercase alphanumeric characters or the underscore character "_".',
+       'option_nom_label' => 'Field name',
+       'option_obligatoire_label' => 'Required field',
+       'option_option_intro_label' => 'Label for the first empty choice',
+       'option_option_statut_label' => 'Show the status',
+       'option_pliable_label' => 'Expandable',
+       'option_pliable_label_case' => 'The group of fields can be expanded or shrunk.',
+       'option_plie_label' => 'Already shrunk',
+       'option_plie_label_case' => 'If the group of fields can be expanded and shrunk, then this option will make it already shrink with the form displays.',
+       'option_previsualisation_explication' => 'If porte-plume is activated, add a tab to preview the appearance of the text entered.',
+       'option_previsualisation_label' => 'Activate previews',
+       'option_readonly_explication' => 'The field can be viewed, selected, but not modified.',
+       'option_readonly_label' => 'Read only',
+       'option_rows_explication' => 'Field height in lines. This option is not always applied/used because the CSS styles of your site can cancel it.',
+       'option_rows_label' => 'Lines number',
+       'option_size_explication' => 'Field width in characters. This option is not always applied/used because the CSS styles of your site can cancel it.',
+       'option_size_label' => 'Field size',
+       'option_type_choix_plusieurs' => 'Allow the user to choose <strong>several</ strong> message recipients.',
+       'option_type_choix_tous' => 'Make <strong>all</ strong> these authors as recipients. The user will not have choice.',
+       'option_type_choix_un' => 'Allow the user to choose <strong>only one</strong> message recipient.',
+       'option_type_explication' => 'In "disguised" mode, the field contents as typed will be replaced with asterisks.',
+       'option_type_label' => 'Field type',
+       'option_type_password' => 'Disguised',
+       'option_type_text' => 'Normal',
+
+       // S
+       'saisie_auteurs_explication' => 'Allows you to select one or more authors',
+       'saisie_auteurs_titre' => 'Autors',
+       'saisie_case_explication' => 'Used to activate or deactivate a particular option.',
+       'saisie_case_titre' => 'Single check box',
+       'saisie_checkbox_explication' => 'Used to select several options using check boxes.',
+       'saisie_checkbox_titre' => 'Check boxes',
+       'saisie_date_explication' => 'Used to enter a date using a calendar tool',
+       'saisie_date_titre' => 'Date',
+       'saisie_destinataires_explication' => 'Used to select one or more recipients from among the pre-selected authors.',
+       'saisie_destinataires_titre' => 'Recipients',
+       'saisie_explication_explication' => 'A general explanatory description.',
+       'saisie_explication_titre' => 'Explanation',
+       'saisie_fieldset_explication' => 'A frame which may include several fields.',
+       'saisie_fieldset_titre' => 'Fieldset',
+       'saisie_file_explication' => 'Send a file',
+       'saisie_file_titre' => 'File',
+       'saisie_hidden_explication' => 'A pre-filled field that the user will never see.',
+       'saisie_hidden_titre' => 'Hidden field',
+       'saisie_input_explication' => 'A simple line of text that can be visible or hidden (password).',
+       'saisie_input_titre' => 'Textfield',
+       'saisie_oui_non_explication' => 'Either a Yes or No response',
+       'saisie_oui_non_titre' => 'Yes or No',
+       'saisie_radio_defaut_choix1' => 'One',
+       'saisie_radio_defaut_choix2' => 'Two',
+       'saisie_radio_defaut_choix3' => 'Three',
+       'saisie_radio_explication' => 'Used to select one single option from several possibilities.',
+       'saisie_radio_titre' => 'Radio buttons',
+       'saisie_selecteur_article' => 'Display an article selection browser',
+       'saisie_selecteur_article_titre' => 'Article selector',
+       'saisie_selecteur_rubrique' => 'Display a section selector browser',
+       'saisie_selecteur_rubrique_article' => 'Display an article or section selector browser',
+       'saisie_selecteur_rubrique_article_titre' => 'Article or section selector',
+       'saisie_selecteur_rubrique_titre' => 'Section selector',
+       'saisie_selection_explication' => 'Select an option from a dropdown list box.',
+       'saisie_selection_multiple_explication' => 'Used for selecting several options from a list.',
+       'saisie_selection_multiple_titre' => 'Multiple selection',
+       'saisie_selection_titre' => 'Dropdown list box',
+       'saisie_textarea_explication' => 'A multilines text field.',
+       'saisie_textarea_titre' => 'Textarea',
+
+       // T
+       'tous_visiteurs' => 'All visitors (even if not registered)',
+       'tout_selectionner' => 'Select all',
+
+       // V
+       'vue_sans_reponse' => '<i>(no data entered)</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_es.php b/www/plugins/saisies/lang/saisies_es.php
new file mode 100644 (file)
index 0000000..3e099c5
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Buscar artículo',
+       'bouton_parcourir_docs_breve' => 'Buscar breve',
+       'bouton_parcourir_docs_rubrique' => 'Buscar la sección',
+       'bouton_parcourir_mediatheque' => 'Buscar mediateca',
+
+       // C
+       'construire_action_annuler' => 'Anular',
+       'construire_action_configurer' => 'Configurar',
+       'construire_action_deplacer' => 'Mover',
+       'construire_action_dupliquer' => 'Duplicar',
+       'construire_action_dupliquer_copie' => '(copia)',
+       'construire_action_supprimer' => 'Eliminar',
+       'construire_ajouter_champ' => 'Añadir un campo',
+       'construire_attention_enregistrer' => '¡No olvide guardar sus cambios!',
+       'construire_attention_modifie' => 'Este formulario es diferente al original. Tiene la posibilidad de restablecerlo conforme a su estado inical. ',
+       'construire_attention_supprime' => 'Sus cambios implican suprimir campos. Confirme por favor esta nueva versión del formulario. ',
+       'construire_aucun_champs' => 'Actualmente no existen campos en este formulario. ',
+       'construire_confirmer_supprimer_champ' => '¿Desea eliminar realmente este campo?',
+       'construire_info_nb_champs_masques' => '@nb@ campo(s) oculto(s) el tiempo de configurar el grupo.',
+       'construire_position_explication' => 'Indique delante de qué otro campo se cololocará.',
+       'construire_position_fin_formulaire' => 'Al final del formulario',
+       'construire_position_fin_groupe' => 'Al final del grupo @groupe@',
+       'construire_position_label' => 'Posición del campo',
+       'construire_reinitialiser' => 'Restablecer el formulario',
+       'construire_reinitialiser_confirmer' => 'Va a perder todos los cambios. ¿Está seguro de volver al formulario original?',
+       'construire_verifications_aucune' => 'Ninguna',
+       'construire_verifications_label' => 'Tipo de verificación a efectuar',
+
+       // E
+       'erreur_generique' => 'Hay errores en los siguientes campos, revise por favor sus entradas',
+       'erreur_option_nom_unique' => 'Este nombre ya ha sido utilizado en otro campo, y ha de ser único en el formulario.',
+
+       // I
+       'info_configurer_saisies' => 'Página de prueba de las entradas',
+
+       // L
+       'label_annee' => 'Año',
+       'label_jour' => 'Día',
+       'label_mois' => 'Mes',
+
+       // O
+       'option_aff_art_interface_explication' => 'Mostrar sólo los artículos en el idioma del usuario',
+       'option_aff_art_interface_label' => 'Aparencia multilingüe',
+       'option_aff_langue_explication' => 'Muestra el idioma del artículo o de la sección enfrente de su título',
+       'option_aff_langue_label' => 'Mostrar el idioma',
+       'option_aff_rub_interface_explication' => 'Mostrar sólo las secciones en el idioma del usuario',
+       'option_aff_rub_interface_label' => 'Aparencia multilingüe',
+       'option_attention_explication' => 'Un mensaje más importante que la explicación.',
+       'option_attention_label' => 'Aviso',
+       'option_autocomplete_defaut' => 'Dejar por defecto',
+       'option_autocomplete_explication' => 'Al cargar la página, su navegador puede rellenar el campo en función de sus historial',
+       'option_autocomplete_label' => 'Pre-relleno del campo',
+       'option_autocomplete_off' => 'Desactivar',
+       'option_autocomplete_on' => 'Activar',
+       'option_cacher_option_intro_label' => 'Esconder la primera opción vacía',
+       'option_choix_destinataires_explication' => 'Una lista de autoras o autores de SPIP. Se podrán elegir los destinatorios dentro de esta lista. Si no se selecciona nadie, la elección será la persona que instaló el sitio.',
+       'option_choix_destinataires_label' => 'Destinaciones posibles',
+       'option_class_label' => 'Clases CSS adicionales',
+       'option_cols_explication' => 'Ancho del bloque (en número de carácteres). Esta opción no se aplica siempre, porque puede ser cancelada por los estilos CSS de tu sitio.',
+       'option_cols_label' => 'Ancho',
+       'option_datas_explication' => 'Tiene que dar una opción por línea bajo la forma "clave|Etiqueta de la opción"',
+       'option_datas_label' => 'Lista de opciones posibles',
+       'option_defaut_label' => 'Valor por defecto',
+       'option_disable_avec_post_explication' => 'Como la opción anterior, pero igual envía el valor en un campo escondido.',
+       'option_disable_avec_post_label' => 'Deactivar pero enviar',
+       'option_disable_explication' => 'El campo ya no puede obtener el foco.',
+       'option_disable_label' => 'Deactivar el campo',
+       'option_erreur_obligatoire_explication' => 'Puede personalizar el mensaje de error mostrado para indicar una obligación (sino dejar en blanco).',
+       'option_erreur_obligatoire_label' => 'Mensaje de obligación',
+       'option_explication_explication' => 'Si hace falta, una frase corta que describe el campo',
+       'option_explication_label' => 'Explicación',
+       'option_groupe_affichage' => 'Aparencia',
+       'option_groupe_description' => 'Descripción',
+       'option_groupe_utilisation' => 'Uso',
+       'option_groupe_validation' => 'Validación',
+       'option_heure_pas_explication' => 'Cuando usa el horario, se muestra un menú para ayudar a introducir horas y minutos. Aquí puede elegir el intervalo de tiempo entre cada opción (por defecto 30 minutos).',
+       'option_heure_pas_label' => 'Intervalo de minutos en el menú de ayuda a la entrada',
+       'option_horaire_label' => 'Horario',
+       'option_horaire_label_case' => 'Permite introducir también la hora',
+       'option_info_obligatoire_explication' => 'Puede modificar la indicación de campo obligatoria: <i>[Obligatorio</i>.',
+       'option_info_obligatoire_label' => 'Indicación de campo obligatorio',
+       'option_inserer_barre_choix_edition' => 'Barra de edición completa',
+       'option_inserer_barre_choix_forum' => 'barra de los foros',
+       'option_inserer_barre_explication' => 'Integra una barra tipográfica si ésta es activa.',
+       'option_inserer_barre_label' => 'Integrar una barra de herramientas',
+       'option_label_case_label' => 'Etiqueta posicionada al lado de la checkbox',
+       'option_label_explication' => 'El título que se enseñará',
+       'option_label_label' => 'Etiqueta',
+       'option_maxlength_explication' => 'El campo no podrá contener más carácteres que este número.',
+       'option_maxlength_label' => 'Número máximo de carácteres',
+       'option_multiple_explication' => 'Se podrán seleccionar varias opciones',
+       'option_multiple_label' => 'Selección múltiple',
+       'option_nom_explication' => 'Un nombre informático que identificará el campo. Sólo puede contener carácteres alfanuméricos minúsculos o el carácter "_".',
+       'option_nom_label' => 'Nombre del campo',
+       'option_obligatoire_label' => 'Campo obligatorio',
+       'option_option_intro_label' => 'Label de la primera opción vacía',
+       'option_option_statut_label' => 'Mostrar el estatus',
+       'option_pliable_label' => 'Desplegable',
+       'option_pliable_label_case' => 'El grupo de campos se podrá contraer y desplegar.',
+       'option_plie_label' => 'Ya está contraido',
+       'option_plie_label_case' => 'Si el grupo de campos se puede contraer, ya estará contraido cuando se enseñe el formulario.',
+       'option_previsualisation_explication' => 'Si la barra tipográfica es activa, añade una pestaña de previsualización del texto.',
+       'option_previsualisation_label' => 'Activar la previsualización',
+       'option_readonly_explication' => 'El campo se puede leer, seleccionar, pero no se puede modificar.',
+       'option_readonly_label' => 'Sólo lectura',
+       'option_rows_explication' => 'Altura del bloque en número de líneas. Esta opción no se aplica siempre, porque puede ser cancelada por los estilos CSS de su sitio.',
+       'option_rows_label' => 'Número de líneas',
+       'option_size_explication' => 'Ancho del campo (número de carácteres). Esta opción no se aplica siempre, porque puede ser cancelada por los estilos CSS de su sitio.',
+       'option_size_label' => 'Tamaño del campo',
+       'option_type_choix_plusieurs' => 'Permitirle al usuario elegir <strong>varias</strong> personas destinatorias.',
+       'option_type_choix_tous' => 'Poner a <strong>todos/as</strong> estas autoras como destinatorias. El usuario no tendrá ninguna opción.',
+       'option_type_choix_un' => 'Permitirle al usuario elegir <strong>sólo una</strong> persona destinatoria.',
+       'option_type_explication' => 'En modo "escondido", el contenido del campo no será visible.',
+       'option_type_label' => 'Tipo del campo',
+       'option_type_password' => 'Escondido',
+       'option_type_text' => 'Normal',
+
+       // S
+       'saisie_auteurs_explication' => 'Permite seleccionar uno o más autores',
+       'saisie_auteurs_titre' => 'Autores',
+       'saisie_case_explication' => 'Permite activar o deactivar algo.',
+       'saisie_case_titre' => 'Checkbox único',
+       'saisie_checkbox_explication' => 'Permite elegir varias opciones con checkboxes',
+       'saisie_checkbox_titre' => 'Checkboxes',
+       'saisie_date_explication' => '¿Permitir introducir una fecha? Ayuda de calendario',
+       'saisie_date_titre' => 'Fecha',
+       'saisie_destinataires_explication' => 'Permite elegir una o varias personas destinatorias dentro de las autoras seleccionadas.',
+       'saisie_destinataires_titre' => 'Personas destinatorias',
+       'saisie_explication_explication' => 'Una explicación general.',
+       'saisie_explication_titre' => 'Explicación',
+       'saisie_fieldset_explication' => 'Un marco que podrá englobar varios campos.',
+       'saisie_fieldset_titre' => 'Grupo de campos',
+       'saisie_file_explication' => 'Mandar un archivo',
+       'saisie_file_titre' => 'Archivo',
+       'saisie_hidden_explication' => 'Un campo invisible, que ya contiene un valor',
+       'saisie_hidden_titre' => 'Campo escondido',
+       'saisie_input_explication' => 'Una sola línea de texto, que puede ser visible u ocultada (contraseña).',
+       'saisie_input_titre' => 'Línea de texto',
+       'saisie_oui_non_explication' => 'Sí o no. ¿Está claro? :)',
+       'saisie_oui_non_titre' => 'Sí o no',
+       'saisie_radio_defaut_choix1' => 'Uno',
+       'saisie_radio_defaut_choix2' => 'Dos',
+       'saisie_radio_defaut_choix3' => 'Tres',
+       'saisie_radio_explication' => 'Permite elegir una opción dentro de varias opciones disponibles.',
+       'saisie_radio_titre' => 'Botones de opción',
+       'saisie_selecteur_article' => 'Muestra un navegador de selección de artículo',
+       'saisie_selecteur_article_titre' => 'Selector de artículo',
+       'saisie_selecteur_rubrique' => 'Muestra un navegador de selección de sección',
+       'saisie_selecteur_rubrique_article' => 'Muestra un navegador de selección de artículo o de sección',
+       'saisie_selecteur_rubrique_article_titre' => 'Selector de artículo o de sección',
+       'saisie_selecteur_rubrique_titre' => 'Selector de sección',
+       'saisie_selection_explication' => 'Elegir una opción dentro de una lista desplegable.',
+       'saisie_selection_multiple_explication' => 'Permite elegir varias opciones con una lista.',
+       'saisie_selection_multiple_titre' => 'Selección multiple',
+       'saisie_selection_titre' => 'Lista desplegable',
+       'saisie_textarea_explication' => 'Un campo de texto sobre varias líneas.',
+       'saisie_textarea_titre' => 'Bloque de texto',
+
+       // T
+       'tous_visiteurs' => 'Todos los visitantes (incluso no registrados)',
+       'tout_selectionner' => 'Seleccionar todo',
+
+       // V
+       'vue_sans_reponse' => '<i>Sin respuesta</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_fa.php b/www/plugins/saisies/lang/saisies_fa.php
new file mode 100644 (file)
index 0000000..e9de88d
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'مرور مقاله',
+       'bouton_parcourir_docs_breve' => 'مرور خبر',
+       'bouton_parcourir_docs_rubrique' => 'مرور بخش',
+       'bouton_parcourir_mediatheque' => 'مرور كتابخانه چندرسانه‌اي',
+
+       // C
+       'construire_action_annuler' => 'Annuler', # NEW
+       'construire_action_configurer' => 'Configurer', # NEW
+       'construire_action_deplacer' => 'Déplacer', # NEW
+       'construire_action_dupliquer' => 'Dupliquer', # NEW
+       'construire_action_dupliquer_copie' => '(copie)', # NEW
+       'construire_action_supprimer' => 'Supprimer', # NEW
+       'construire_ajouter_champ' => 'Ajouter un champ', # NEW
+       'construire_attention_enregistrer' => 'N\'oubliez pas d\'enregistrer vos modifications !', # NEW
+       'construire_attention_modifie' => 'Le formulaire ci-dessous est différent du formulaire initial. Vous avez la possibilité de le réinitialiser à son état avant vos modifications.', # NEW
+       'construire_attention_supprime' => 'Vos modifications comportent des suppressions de champs. Veuillez confirmer l\'enregistrement de cette nouvelle version du formulaire.', # NEW
+       'construire_aucun_champs' => 'Il n\'y a pour l\'instant aucun champ dans ce formulaire.', # NEW
+       'construire_confirmer_supprimer_champ' => 'Voulez-vous vraiment supprimer ce champ ?', # NEW
+       'construire_info_nb_champs_masques' => '@nb@ champ(s) masqué(s) le temps de configurer le groupe.', # NEW
+       'construire_position_explication' => 'Indiquez devant quel autre champ sera placé celui-ci.', # NEW
+       'construire_position_fin_formulaire' => 'À la fin du formulaire', # NEW
+       'construire_position_fin_groupe' => 'À la fin du groupe @groupe@', # NEW
+       'construire_position_label' => 'Position du champ', # NEW
+       'construire_reinitialiser' => 'Réinitialiser le formulaire', # NEW
+       'construire_reinitialiser_confirmer' => 'Vous allez perdre toutes vos modifications. Êtes-vous sûr de vouloir revenir au formulaire initial ?', # NEW
+       'construire_verifications_aucune' => 'Aucune', # NEW
+       'construire_verifications_label' => 'Type de vérification à effectuer', # NEW
+
+       // E
+       'erreur_generique' => 'Il y a des erreurs dans les champs ci-dessous, veuillez vérifier vos saisies', # NEW
+       'erreur_option_nom_unique' => 'Ce nom est déjà utilisé par un autre champ et il doit être unique dans ce formulaire.', # NEW
+
+       // I
+       'info_configurer_saisies' => 'Page de test des Saisies', # NEW
+
+       // L
+       'label_annee' => 'سال',
+       'label_jour' => 'روز',
+       'label_mois' => 'ماه',
+
+       // O
+       'option_aff_art_interface_explication' => 'نمايش مقالات فقط به زبان كاربر',
+       'option_aff_art_interface_label' => 'نمايش چندزبانه',
+       'option_aff_langue_explication' => 'نمايش زبان مقاله يا بخش انتخاب شده‌ پيش از تيتر',
+       'option_aff_langue_label' => 'نمايش زبان',
+       'option_aff_rub_interface_explication' => 'نمايش بخش‌ها فقط به زبان كاربر',
+       'option_aff_rub_interface_label' => 'نمايش چندزبانه',
+       'option_attention_explication' => 'پيامي مهم‌تر از توضيح.',
+       'option_attention_label' => 'هشدار',
+       'option_autocomplete_defaut' => 'Laisser par défaut', # NEW
+       'option_autocomplete_explication' => 'Au chargement de la page, votre navigateur peut pré-remplir le champ en fonction de son historique', # NEW
+       'option_autocomplete_label' => 'Pré-remplissage du champ', # NEW
+       'option_autocomplete_off' => 'Désactiver', # NEW
+       'option_autocomplete_on' => 'Activer', # NEW
+       'option_cacher_option_intro_label' => 'پنهان‌سازي نخستين انتخاب خالي ',
+       'option_choix_destinataires_explication' => 'يك يا چند نويسنده كه كاربر مي‌تواند از ميانشان انتخاب كند. اگر كسي انتخاب نشود،‌ نويسنده‌اي كه سايت را نصب كرده انتخاب خواهد شد.<NEW>Un ou plusieurs auteurs parmis lesquels l\'utilisateur pourra faire son choix. Si rien n\'est sélectionné, c\'est l\'auteur qui a installé le site qui sera choisi.',
+       'option_choix_destinataires_label' => '<دريافت‌ كنندگان محتمل',
+       'option_class_label' => 'كلاس‌هاي سي.اس.اس اضافي ',
+       'option_cols_explication' => 'پهناي بلوك به تعداد كارآكترها. اين گزينه هميشه كاربرد ندارد چرا كه شيوه‌هاي سي.اس.اس سايت شما مي‌تواند آن را منتفي سازد.',
+       'option_cols_label' => 'پهنا',
+       'option_datas_explication' => 'لازم است براي هر رديف يك گزينه در قالب «گزينه‌ي كليد|برچسبِ» انتخاب كنيد.',
+       'option_datas_label' => 'فهرست گزينه‌هاي ممكن ',
+       'option_defaut_label' => 'مقدار پيش‌ گزيده',
+       'option_disable_avec_post_explication' => 'همانند وضعيت گزينه‌ي قبلي اما هنوز مقدار در ميدان مخفي پست شود.',
+       'option_disable_avec_post_label' => 'غيرفعال اما پست شده',
+       'option_disable_explication' => 'ميدان نمي‌‌تواند تمركز بيشتري بگيرد.',
+       'option_disable_label' => 'غيرفعال سازي ميدن',
+       'option_erreur_obligatoire_explication' => 'Vous pouvez personnaliser le message d\'erreur affiché pour indiquer l\'obligation (sinon laisser vide).', # NEW
+       'option_erreur_obligatoire_label' => 'Message d\'obligation', # NEW
+       'option_explication_explication' => 'در هنگام نياز، يك عبارت كوتاه موضوع ميدان را بيان كند.',
+       'option_explication_label' => 'توضيح',
+       'option_groupe_affichage' => 'نمايش ',
+       'option_groupe_description' => 'توصيف',
+       'option_groupe_utilisation' => 'كاربرد',
+       'option_groupe_validation' => 'ارزش‌گذاري',
+       'option_heure_pas_explication' => 'Lorsque vous utilisez l’horaire, un menu s’affiche pour aider à saisir heures et minutes. Vous pouvez ici choisir l’intervalle de temps entre chaque choix (par défaut 30min).', # NEW
+       'option_heure_pas_label' => 'Intervalle des minutes dans le menu d’aide à la saisie', # NEW
+       'option_horaire_label' => 'Horaire', # NEW
+       'option_horaire_label_case' => 'Permettre de saisie aussi l’horaire', # NEW
+       'option_info_obligatoire_explication' => 'مي‌توانيد كاربرد پيش‌ گزيده‌ي الزامي را اصلاح كنيد: <i>[Obligatoire]</i>.',
+       'option_info_obligatoire_label' => 'نشان الزام',
+       'option_inserer_barre_choix_edition' => 'ميل‌ابزار ويرايش كامل ',
+       'option_inserer_barre_choix_forum' => 'ميل‌ابزار سخنگاه‌ها',
+       'option_inserer_barre_explication' => 'گنجاندن يك ميل‌‌ابزار «چوب قلم» «porte-plume» اگر آن ابزار فعال باشد.',
+       'option_inserer_barre_label' => 'گنجاندن يك ميل‌ابزار',
+       'option_label_case_label' => 'برچسب كنار چك باكس ',
+       'option_label_explication' => 'تيتري كه نمايش داده خواهد شد.',
+       'option_label_label' => 'برچسب',
+       'option_maxlength_explication' => 'كاربر نمي‌تواند كارآكترهايي بيش از اين تعداد تايپ كند.',
+       'option_maxlength_label' => 'تعداد بيشترين كارآكتر',
+       'option_multiple_explication' => 'توانايي كاربر در انتخاب چند مقدار',
+       'option_multiple_label' => 'چندگزينه‌اي',
+       'option_nom_explication' => 'يك اسم انفورماتيك كه اين ميدان را معرفي كند. اين اسم فقط بايد مركب از حروف كوچك و يا آندر لاين «_» باشد. ',
+       'option_nom_label' => 'اسم ميدان',
+       'option_obligatoire_label' => 'ميدان الزامي',
+       'option_option_intro_label' => 'برچسب نخستين گزينه‌ي خالي ',
+       'option_option_statut_label' => 'Afficher les statuts', # NEW
+       'option_pliable_label' => 'گسترشي ',
+       'option_pliable_label_case' => 'گروه‌ ميدان‌هاي چين خور.',
+       'option_plie_label' => 'چين خورده',
+       'option_plie_label_case' => 'اگر گروه ميدان‌ها چين خور باشد، اين گزينه آن‌ها را در نمايش فرم چين خور كرده است. ',
+       'option_previsualisation_explication' => 'اگر چوب قلم فعال باشد، يك تب براي پيش‌ نمايش متن ورودي اضافه كن.',
+       'option_previsualisation_label' => 'فعال سازي پيش نمايش ',
+       'option_readonly_explication' => 'ميدان قابل مشاهده و گزينش، اما ناويرايشي.',
+       'option_readonly_label' => 'فقط خوانداني',
+       'option_rows_explication' => 'بلندي ميدان در پيوند‌ها. اين گزينه كاربردي/كاربستي نيست زيرا سي.اس.اس سايت شما آن را رد مي‌كند.',
+       'option_rows_label' => 'تعداد پيوندها',
+       'option_size_explication' => 'پهناي ميدان بر اساس تعدا كارآكتر. اين گزينه هميشه كاربردي/كاربستي نيست زيرا سي.اس.اس سايت شما آن را رد مي‌كند.',
+       'option_size_label' => 'اندازه‌ي ميدان',
+       'option_type_choix_plusieurs' => 'اجازه به كاربر در انتخاب <strong> چند</strong> دريافت كننده‌ي ايميل.',
+       'option_type_choix_tous' => '<strong>تمام</strong> مؤلفان دريافت‌كننده شوند. كاربر گزينه‌اي نخواهد داشت.',
+       'option_type_choix_un' => 'اجازه به كاربر براي گزينش <strong> فقط يك </strong> دريافت‌كننده ',
+       'option_type_explication' => 'در حالت «پوشيده»، محتواي ميدان قابل رؤيت نخواهد بود. ',
+       'option_type_label' => 'نوع ميدان',
+       'option_type_password' => 'پوشيده',
+       'option_type_text' => 'عادي',
+
+       // S
+       'saisie_auteurs_explication' => 'Permet de sélectionner un ou plusieurs auteurs', # NEW
+       'saisie_auteurs_titre' => 'Auteurs', # NEW
+       'saisie_case_explication' => 'فعال يا غيرفعال‌سازي يك گزينه‌ي مشخص.',
+       'saisie_case_titre' => 'تك چك‌ باكش',
+       'saisie_checkbox_explication' => 'اجازه‌ي گزينش چك‌ باكس چندگزينه‌اي.',
+       'saisie_checkbox_titre' => 'چك باكس‌ها',
+       'saisie_date_explication' => 'اجازه واردسازي داده با كمك تقويم',
+       'saisie_date_titre' => 'تاريخ',
+       'saisie_destinataires_explication' => 'اجازه‌ي گزينش يك يا چند دريافت كننده از ميان نويسندگان پيش‌ گزيده.',
+       'saisie_destinataires_titre' => 'دريافت‌ كنندگان',
+       'saisie_explication_explication' => 'يك متن توصيفي كلي.',
+       'saisie_explication_titre' => 'توصيف',
+       'saisie_fieldset_explication' => 'كادري كه ممكن است چند ميدان داشته باشد.',
+       'saisie_fieldset_titre' => 'گروه ميدان',
+       'saisie_file_explication' => 'ارسال پرونده',
+       'saisie_file_titre' => 'پرونده',
+       'saisie_hidden_explication' => 'ميدان از‌پيش‌‌ پُري كه بازديدكننده هرگز نخواهد ديد.',
+       'saisie_hidden_titre' => 'ميدان پوشيده',
+       'saisie_input_explication' => 'خط ساده‌اي از متن كه مي‌تواند پوشيده يا آشكار باشد (گذرواژه)',
+       'saisie_input_titre' => 'ميدان متني',
+       'saisie_oui_non_explication' => 'بله يا نه، روشن است؟ :)',
+       'saisie_oui_non_titre' => 'بله يا نه',
+       'saisie_radio_defaut_choix1' => 'يك ',
+       'saisie_radio_defaut_choix2' => 'دو',
+       'saisie_radio_defaut_choix3' => 'سه',
+       'saisie_radio_explication' => 'اجازه‌ي گزينش يك تك گزينه‌اي از ميان چند امكان.',
+       'saisie_radio_titre' => 'دكمه راديويي',
+       'saisie_selecteur_article' => 'نمايش يك مرورگر گزينش مقاله',
+       'saisie_selecteur_article_titre' => 'گزينشگر مقاله',
+       'saisie_selecteur_rubrique' => 'نمايش مرورگر گزينشگر مقاله',
+       'saisie_selecteur_rubrique_article' => 'نمايش مرورگر گزينشگر يك مقاله يا يك بخش',
+       'saisie_selecteur_rubrique_article_titre' => 'گزينشگر مقاله يا بخش',
+       'saisie_selecteur_rubrique_titre' => 'گزينشگر بخش',
+       'saisie_selection_explication' => 'گزينش يك گزينه از فهرست آبشاري.',
+       'saisie_selection_multiple_explication' => 'اجازه‌ي گزينش چند گزينه با يك فهرست.',
+       'saisie_selection_multiple_titre' => 'چندگزينه‌اي',
+       'saisie_selection_titre' => 'فهرست‌دان آبشاري ',
+       'saisie_textarea_explication' => 'ميدان متن چندخطي.',
+       'saisie_textarea_titre' => 'بلوك‌متن',
+
+       // T
+       'tous_visiteurs' => 'تمام بازديدكنندگان (حتي ثبت ‌نام ناشدگان)',
+       'tout_selectionner' => 'Tout sélectionner', # NEW
+
+       // V
+       'vue_sans_reponse' => '<i>بي‌ پاسخ</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_fr.php b/www/plugins/saisies/lang/saisies_fr.php
new file mode 100644 (file)
index 0000000..f6e55a2
--- /dev/null
@@ -0,0 +1,178 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/saisies/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Parcourir l\'article',
+       'bouton_parcourir_docs_breve' => 'Parcourir la brève',
+       'bouton_parcourir_docs_rubrique' => 'Parcourir la rubrique',
+       'bouton_parcourir_mediatheque' => 'Parcourir la médiathèque',
+
+       // C
+       'construire_action_annuler' => 'Annuler',
+       'construire_action_configurer' => 'Configurer',
+       'construire_action_deplacer' => 'Déplacer',
+       'construire_action_dupliquer' => 'Dupliquer',
+       'construire_action_dupliquer_copie' => '(copie)',
+       'construire_action_supprimer' => 'Supprimer',
+       'construire_ajouter_champ' => 'Ajouter un champ',
+       'construire_attention_enregistrer' => 'N\'oubliez pas d\'enregistrer vos modifications !',
+       'construire_attention_modifie' => 'Le formulaire ci-dessous est différent du formulaire initial. Vous avez la possibilité de le réinitialiser à son état avant vos modifications.',
+       'construire_attention_supprime' => 'Vos modifications comportent des suppressions de champs. Veuillez confirmer l\'enregistrement de cette nouvelle version du formulaire.',
+       'construire_aucun_champs' => 'Il n\'y a pour l\'instant aucun champ dans ce formulaire.',
+       'construire_confirmer_supprimer_champ' => 'Voulez-vous vraiment supprimer ce champ ?',
+       'construire_info_nb_champs_masques' => '@nb@ champ(s) masqué(s) le temps de configurer le groupe.',
+       'construire_position_explication' => 'Indiquez devant quel autre champ sera placé celui-ci.',
+       'construire_position_fin_formulaire' => 'À la fin du formulaire',
+       'construire_position_fin_groupe' => 'À la fin du groupe @groupe@',
+       'construire_position_label' => 'Position du champ',
+       'construire_reinitialiser' => 'Réinitialiser le formulaire',
+       'construire_reinitialiser_confirmer' => 'Vous allez perdre toutes vos modifications. Êtes-vous sûr de vouloir revenir au formulaire initial ?',
+       'construire_verifications_aucune' => 'Aucune',
+       'construire_verifications_label' => 'Type de vérification à effectuer',
+
+       // E
+       'erreur_generique' => 'Il y a des erreurs dans les champs ci-dessous, veuillez vérifier vos saisies',
+       'erreur_option_nom_unique' => 'Ce nom est déjà utilisé par un autre champ et il doit être unique dans ce formulaire.',
+
+       // I
+       'info_configurer_saisies' => 'Page de test des Saisies',
+
+       // L
+       'label_annee' => 'Année',
+       'label_jour' => 'Jour',
+       'label_mois' => 'Mois',
+
+       // O
+       'option_aff_art_interface_explication' => 'Afficher uniquement les articles de la langue de l\'utilisateur',
+       'option_aff_art_interface_label' => 'Affichage multilingue',
+       'option_aff_langue_explication' => 'Affiche la langue de l\'article ou rubrique sélectionné devant le titre',
+       'option_aff_langue_label' => 'Afficher la langue',
+       'option_aff_rub_interface_explication' => 'Afficher uniquement les rubriques de la langue de l\'utilisateur',
+       'option_aff_rub_interface_label' => 'Affichage multilingue',
+       'option_attention_explication' => 'Un message plus important que l\'explication.',
+       'option_attention_label' => 'Avertissement',
+       'option_autocomplete_defaut' => 'Laisser par défaut',
+       'option_autocomplete_explication' => 'Au chargement de la page, votre navigateur peut pré-remplir le champ en fonction de son historique',
+       'option_autocomplete_label' => 'Pré-remplissage du champ',
+       'option_autocomplete_off' => 'Désactiver',
+       'option_autocomplete_on' => 'Activer',
+       'option_cacher_option_intro_label' => 'Cacher le premier choix vide',
+       'option_choix_destinataires_explication' => 'Un ou plusieurs auteurs parmis lesquels l\'utilisateur pourra faire son choix. Si rien n\'est sélectionné, c\'est l\'auteur qui a installé le site qui sera choisi.',
+       'option_choix_destinataires_label' => 'Destinataires possibles',
+       'option_class_label' => 'Classes CSS supplémentaires',
+       'option_cols_explication' => 'Largeur du bloc en nombre de caractères. Cette option n\'est pas toujours appliquée car les styles CSS de votre site peuvent l\'annuler.',
+       'option_cols_label' => 'Largeur',
+       'option_datas_explication' => 'Vous devez indiquez un choix par ligne sous la forme "cle|Label du choix"',
+       'option_datas_label' => 'Liste des choix possibles',
+       'option_defaut_label' => 'Valeur par défaut',
+       'option_disable_avec_post_explication' => 'Identique à l\'option précédente mais poste quand même la valeur dans un champ caché.',
+       'option_disable_avec_post_label' => 'Désactiver mais poster',
+       'option_disable_explication' => 'Le champ ne peut plus obtenir le focus.',
+       'option_disable_label' => 'Désactiver le champ',
+       'option_erreur_obligatoire_explication' => 'Vous pouvez personnaliser le message d\'erreur affiché pour indiquer l\'obligation (sinon laisser vide).',
+       'option_erreur_obligatoire_label' => 'Message d\'obligation',
+       'option_explication_explication' => 'Si besoin, une courte phrase décrivant l\'objet du champ.',
+       'option_explication_label' => 'Explication',
+       'option_groupe_affichage' => 'Affichage',
+       'option_groupe_description' => 'Description',
+       'option_groupe_utilisation' => 'Utilisation',
+       'option_groupe_validation' => 'Validation',
+       'option_heure_pas_explication' => 'Lorsque vous utilisez l’horaire, un menu s’affiche pour aider à saisir heures et minutes. Vous pouvez ici choisir l’intervalle de temps entre chaque choix (par défaut 30min).',
+       'option_heure_pas_label' => 'Intervalle des minutes dans le menu d’aide à la saisie',
+       'option_horaire_label' => 'Horaire',
+       'option_horaire_label_case' => 'Permettre de saisir aussi l’horaire',
+       'option_info_obligatoire_explication' => 'Vous pouvez modifier l\'indication d\'obligation par défaut : <i>[Obligatoire]</i>.',
+       'option_info_obligatoire_label' => 'Indication d\'obligation',
+       'option_inserer_barre_choix_edition' => 'barre d\'édition complète',
+       'option_inserer_barre_choix_forum' => 'barre des forums',
+       'option_inserer_barre_explication' => 'Insère une barre d\'outils du porte-plume si ce dernier est activé.',
+       'option_inserer_barre_label' => 'Insérer une barre d\'outils',
+       'option_label_case_label' => 'Label placé à côté de la case',
+       'option_label_explication' => 'Le titre qui sera affiché.',
+       'option_label_label' => 'Label',
+       'option_maxlength_explication' => 'L\'utilisateur ne pourra pas taper plus de caractères que ce nombre.',
+       'option_maxlength_label' => 'Nombre de caractères maximum',
+       'option_multiple_explication' => 'L\'utilisateur pourra sélectionner plusieurs valeurs',
+       'option_multiple_label' => 'Sélection multiple',
+       'option_nom_explication' => 'Un nom informatique qui identifiera le champ. Il ne doit contenir que des caractères alpha-numériques minuscules ou le caractère "_".',
+       'option_nom_label' => 'Nom du champ',
+       'option_obligatoire_label' => 'Champ obligatoire',
+       'option_option_intro_label' => 'Label du premier choix vide',
+       'option_option_statut_label' => 'Afficher les statuts',
+       'option_pliable_label' => 'Pliable',
+       'option_pliable_label_case' => 'Le groupe de champs pourra être replié.',
+       'option_plie_label' => 'Déjà plié',
+       'option_plie_label_case' => 'Si le groupe de champs est pliable, il sera déjà plié à l\'affichage du formulaire.',
+       'option_previsualisation_explication' => 'Si le porte-plume est activé, ajoute un onglet pour prévisualiser le rendu du texte saisi.',
+       'option_previsualisation_label' => 'Activer la prévisualisation',
+       'option_readonly_explication' => 'Le champ peut être lu, sélectionné, mais pas modifié.',
+       'option_readonly_label' => 'Lecture seule',
+       'option_rows_explication' => 'Hauteur du bloc en nombre de ligne. Cette option n\'est pas toujours appliquée car les styles CSS de votre site peuvent l\'annuler.',
+       'option_rows_label' => 'Nombre de lignes',
+       'option_size_explication' => 'Largeur du champ en nombre de caractères. Cette option n\'est pas toujours appliquée car les styles CSS de votre site peuvent l\'annuler.',
+       'option_size_label' => 'Taille du champ',
+       'option_type_choix_plusieurs' => 'Permettre à l\'utilisateur de choisir <strong>plusieurs</strong> destinataires.',
+       'option_type_choix_tous' => 'Mettre <strong>tous</strong> ces auteurs en destinataires. L\'utilisateur n\'aura aucun choix.',
+       'option_type_choix_un' => 'Permettre à l\'utilisateur de choisir <strong>un seul</strong> destinataire.',
+       'option_type_explication' => 'En mode "masqué", le contenu du champ ne sera pas visible.',
+       'option_type_label' => 'Type du champ',
+       'option_type_password' => 'Masqué',
+       'option_type_text' => 'Normal',
+
+       // S
+       'saisie_auteurs_explication' => 'Permet de sélectionner un ou plusieurs auteurs',
+       'saisie_auteurs_titre' => 'Auteurs',
+       'saisie_case_explication' => 'Permet d\'activer ou de désactiver quelque chose.',
+       'saisie_case_titre' => 'Case unique',
+       'saisie_checkbox_explication' => 'Permet de choisir plusieurs options avec des cases.',
+       'saisie_checkbox_titre' => 'Cases à cocher',
+       'saisie_date_explication' => 'Permet de saisir une date ? l\'aide d\'un calendrier',
+       'saisie_date_titre' => 'Date',
+       'saisie_destinataires_explication' => 'Permet de choisir un ou plusieurs destinataires parmis des auteurs pré-sélectionné.',
+       'saisie_destinataires_titre' => 'Destinataires',
+       'saisie_explication_explication' => 'Un texte explicatif général.',
+       'saisie_explication_titre' => 'Explication',
+       'saisie_fieldset_explication' => 'Un cadre qui pourra englober plusieurs champs.',
+       'saisie_fieldset_titre' => 'Groupe de champs',
+       'saisie_file_explication' => 'Envoi d\'un fichier',
+       'saisie_file_titre' => 'Fichier',
+       'saisie_hidden_explication' => 'Un champ pré-rempli que l\'utilisateur ne pourra pas voir.',
+       'saisie_hidden_titre' => 'Champ caché',
+       'saisie_input_explication' => 'Une simple ligne de texte, pouvant être visible ou masquée (mot de passe).',
+       'saisie_input_titre' => 'Ligne de texte',
+       'saisie_oui_non_explication' => 'Oui ou non, c\'est clair ? :)',
+       'saisie_oui_non_titre' => 'Oui ou non',
+       'saisie_radio_defaut_choix1' => 'Un',
+       'saisie_radio_defaut_choix2' => 'Deux',
+       'saisie_radio_defaut_choix3' => 'Trois',
+       'saisie_radio_explication' => 'Permet de choisir une option parmis plusieurs disponibles.',
+       'saisie_radio_titre' => 'Boutons radios',
+       'saisie_selecteur_article' => 'Affiche un navigateur de sélection d\'article',
+       'saisie_selecteur_article_titre' => 'Sélecteur d\'article',
+       'saisie_selecteur_rubrique' => 'Affiche un navigateur de sélection de rubrique',
+       'saisie_selecteur_rubrique_article' => 'Affiche un navigateur de sélection d\'article ou de rubrique',
+       'saisie_selecteur_rubrique_article_titre' => 'Sélecteur d\'article ou rubrique',
+       'saisie_selecteur_rubrique_titre' => 'Sélecteur de rubrique',
+       'saisie_selection_explication' => 'Choisir une option dans une liste déroulante.',
+       'saisie_selection_multiple_explication' => 'Permet de choisir plusieurs options avec une liste.',
+       'saisie_selection_multiple_titre' => 'Sélection multiple',
+       'saisie_selection_titre' => 'Liste déroulante',
+       'saisie_textarea_explication' => 'Un champ de texte sur plusieurs lignes.',
+       'saisie_textarea_titre' => 'Bloc de texte',
+
+       // T
+       'tous_visiteurs' => 'Tous les visiteurs (même non enregistrés)',
+       'tout_selectionner' => 'Tout sélectionner',
+
+       // V
+       'vue_sans_reponse' => '<i>Sans réponse</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_fr_tu.php b/www/plugins/saisies/lang/saisies_fr_tu.php
new file mode 100644 (file)
index 0000000..9380d49
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=fr_tu
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Parcourir l\'article',
+       'bouton_parcourir_docs_breve' => 'Parcourir la brève',
+       'bouton_parcourir_docs_rubrique' => 'Parcourir la rubrique',
+       'bouton_parcourir_mediatheque' => 'Parcourir la médiathèque',
+
+       // C
+       'construire_action_annuler' => 'Annuler', # NEW
+       'construire_action_configurer' => 'Configurer', # NEW
+       'construire_action_deplacer' => 'Déplacer', # NEW
+       'construire_action_dupliquer' => 'Dupliquer', # NEW
+       'construire_action_dupliquer_copie' => '(copie)', # NEW
+       'construire_action_supprimer' => 'Supprimer', # NEW
+       'construire_ajouter_champ' => 'Ajouter un champ', # NEW
+       'construire_attention_enregistrer' => 'N\'oubliez pas d\'enregistrer vos modifications !', # NEW
+       'construire_attention_modifie' => 'Le formulaire ci-dessous est différent du formulaire initial. Vous avez la possibilité de le réinitialiser à son état avant vos modifications.', # NEW
+       'construire_attention_supprime' => 'Vos modifications comportent des suppressions de champs. Veuillez confirmer l\'enregistrement de cette nouvelle version du formulaire.', # NEW
+       'construire_aucun_champs' => 'Il n\'y a pour l\'instant aucun champ dans ce formulaire.', # NEW
+       'construire_confirmer_supprimer_champ' => 'Voulez-vous vraiment supprimer ce champ ?', # NEW
+       'construire_info_nb_champs_masques' => '@nb@ champ(s) masqué(s) le temps de configurer le groupe.', # NEW
+       'construire_position_explication' => 'Indiquez devant quel autre champ sera placé celui-ci.', # NEW
+       'construire_position_fin_formulaire' => 'À la fin du formulaire', # NEW
+       'construire_position_fin_groupe' => 'À la fin du groupe @groupe@', # NEW
+       'construire_position_label' => 'Position du champ', # NEW
+       'construire_reinitialiser' => 'Réinitialiser le formulaire', # NEW
+       'construire_reinitialiser_confirmer' => 'Vous allez perdre toutes vos modifications. Êtes-vous sûr de vouloir revenir au formulaire initial ?', # NEW
+       'construire_verifications_aucune' => 'Aucune', # NEW
+       'construire_verifications_label' => 'Type de vérification à effectuer', # NEW
+
+       // E
+       'erreur_generique' => 'Il y a des erreurs dans les champs ci-dessous, veuillez vérifier vos saisies', # NEW
+       'erreur_option_nom_unique' => 'Ce nom est déjà utilisé par un autre champ et il doit être unique dans ce formulaire.', # NEW
+
+       // I
+       'info_configurer_saisies' => 'Page de test des Saisies', # NEW
+
+       // L
+       'label_annee' => 'Année',
+       'label_jour' => 'Jour',
+       'label_mois' => 'Mois',
+
+       // O
+       'option_aff_art_interface_explication' => 'Afficher uniquement les articles de la langue de l\'utilisateur',
+       'option_aff_art_interface_label' => 'Affichage multilingue',
+       'option_aff_langue_explication' => 'Affiche la langue de l\'article ou rubrique sélectionné devant le titre',
+       'option_aff_langue_label' => 'Afficher la langue',
+       'option_aff_rub_interface_explication' => 'Afficher uniquement les rubriques de la langue de l\'utilisateur',
+       'option_aff_rub_interface_label' => 'Affichage multilingue',
+       'option_attention_explication' => 'Un message plus important que l\'explication.',
+       'option_attention_label' => 'Avertissement',
+       'option_autocomplete_defaut' => 'Laisser par défaut', # NEW
+       'option_autocomplete_explication' => 'Au chargement de la page, votre navigateur peut pré-remplir le champ en fonction de son historique', # NEW
+       'option_autocomplete_label' => 'Pré-remplissage du champ', # NEW
+       'option_autocomplete_off' => 'Désactiver', # NEW
+       'option_autocomplete_on' => 'Activer', # NEW
+       'option_cacher_option_intro_label' => 'Cacher le premier choix vide',
+       'option_choix_destinataires_explication' => 'Un ou plusieurs auteurs parmis lesquels l\'utilisateur pourra faire son choix. Si rien n\'est sélectionné, c\'est l\'auteur qui a installé le site qui sera choisi.',
+       'option_choix_destinataires_label' => 'Destinataires possibles',
+       'option_class_label' => 'Classes CSS supplémentaires',
+       'option_cols_explication' => 'Largeur du bloc en nombre de caractères. Cette option n\'est pas toujours appliquée car les styles CSS de ton site peuvent l\'annuler.',
+       'option_cols_label' => 'Largeur',
+       'option_datas_explication' => 'Tu dois indiquez un choix par ligne sous la forme "cle|Label du choix"',
+       'option_datas_label' => 'Liste des choix possibles',
+       'option_defaut_label' => 'Valeur par défaut',
+       'option_disable_avec_post_explication' => 'Identique à l\'option précédente mais poste quand même la valeur dans un champ caché.',
+       'option_disable_avec_post_label' => 'Désactiver mais poster',
+       'option_disable_explication' => 'Le champ ne peut plus obtenir le focus.',
+       'option_disable_label' => 'Désactiver le champ',
+       'option_erreur_obligatoire_explication' => 'Vous pouvez personnaliser le message d\'erreur affiché pour indiquer l\'obligation (sinon laisser vide).', # NEW
+       'option_erreur_obligatoire_label' => 'Message d\'obligation', # NEW
+       'option_explication_explication' => 'Si besoin, une courte phrase décrivant l\'objet du champ.',
+       'option_explication_label' => 'Explication',
+       'option_groupe_affichage' => 'Affichage',
+       'option_groupe_description' => 'Description',
+       'option_groupe_utilisation' => 'Utilisation',
+       'option_groupe_validation' => 'Validation',
+       'option_heure_pas_explication' => 'Lorsque vous utilisez l’horaire, un menu s’affiche pour aider à saisir heures et minutes. Vous pouvez ici choisir l’intervalle de temps entre chaque choix (par défaut 30min).', # NEW
+       'option_heure_pas_label' => 'Intervalle des minutes dans le menu d’aide à la saisie', # NEW
+       'option_horaire_label' => 'Horaire', # NEW
+       'option_horaire_label_case' => 'Permettre de saisie aussi l’horaire', # NEW
+       'option_info_obligatoire_explication' => 'Tu peux modifier l\'indication d\'obligation par défaut : <i>[Obligatoire]</i>.',
+       'option_info_obligatoire_label' => 'Indication d\'obligation',
+       'option_inserer_barre_choix_edition' => 'barre d\'édition complète',
+       'option_inserer_barre_choix_forum' => 'barre des forums',
+       'option_inserer_barre_explication' => 'Insère une barre d\'outils du porte-plume si ce dernier est activé.',
+       'option_inserer_barre_label' => 'Insérer une barre d\'outils',
+       'option_label_case_label' => 'Label placé à côté de la case',
+       'option_label_explication' => 'Le titre qui sera affiché.',
+       'option_label_label' => 'Label',
+       'option_maxlength_explication' => 'L\'utilisateur ne pourra pas taper plus de caractères que ce nombre.',
+       'option_maxlength_label' => 'Nombre de caractères maximum',
+       'option_multiple_explication' => 'L\'utilisateur pourra sélectionner plusieurs valeurs',
+       'option_multiple_label' => 'Sélection multiple',
+       'option_nom_explication' => 'Un nom informatique qui identifiera le champ. Il ne doit contenir que des caractères alpha-numériques minuscules ou le caractère "_".',
+       'option_nom_label' => 'Nom du champ',
+       'option_obligatoire_label' => 'Champ obligatoire',
+       'option_option_intro_label' => 'Label du premier choix vide',
+       'option_option_statut_label' => 'Afficher les statuts', # NEW
+       'option_pliable_label' => 'Pliable',
+       'option_pliable_label_case' => 'Le groupe de champs pourra être replié.',
+       'option_plie_label' => 'Déjà plié',
+       'option_plie_label_case' => 'Si le groupe de champs est pliable, il sera déjà plié à l\'affichage du formulaire.',
+       'option_previsualisation_explication' => 'Si le porte-plume est activé, ajoute un onglet pour prévisualiser le rendu du texte saisi.',
+       'option_previsualisation_label' => 'Activer la prévisualisation',
+       'option_readonly_explication' => 'Le champ peut être lu, sélectionné, mais pas modifié.',
+       'option_readonly_label' => 'Lecture seule',
+       'option_rows_explication' => 'Hauteur du bloc en nombre de ligne. Cette option n\'est pas toujours appliquée car les styles CSS de votre site peuvent l\'annuler.',
+       'option_rows_label' => 'Nombre de lignes',
+       'option_size_explication' => 'Largeur du champ en nombre de caractères. Cette option n\'est pas toujours appliquée car les styles CSS de ton site peuvent l\'annuler.',
+       'option_size_label' => 'Taille du champ',
+       'option_type_choix_plusieurs' => 'Permettre à l\'utilisateur de choisir <strong>plusieurs</strong> destinataires.',
+       'option_type_choix_tous' => 'Mettre <strong>tous</strong> ces auteurs en destinataires. L\'utilisateur n\'aura aucun choix.',
+       'option_type_choix_un' => 'Permettre à l\'utilisateur de choisir <strong>un seul</strong> destinataire.',
+       'option_type_explication' => 'En mode "masqué", le contenu du champ ne sera pas visible.',
+       'option_type_label' => 'Type du champ',
+       'option_type_password' => 'Masqué',
+       'option_type_text' => 'Normal',
+
+       // S
+       'saisie_auteurs_explication' => 'Permet de sélectionner un ou plusieurs auteurs', # NEW
+       'saisie_auteurs_titre' => 'Auteurs', # NEW
+       'saisie_case_explication' => 'Permet d\'activer ou de désactiver quelque chose.',
+       'saisie_case_titre' => 'Case unique',
+       'saisie_checkbox_explication' => 'Permet de choisir plusieurs options avec des cases.',
+       'saisie_checkbox_titre' => 'Cases à cocher',
+       'saisie_date_explication' => 'Permet de saisir une date ? l\'aide d\'un calendrier',
+       'saisie_date_titre' => 'Date',
+       'saisie_destinataires_explication' => 'Permet de choisir un ou plusieurs destinataires parmis des auteurs pré-sélectionné.',
+       'saisie_destinataires_titre' => 'Destinataires',
+       'saisie_explication_explication' => 'Un texte explicatif général.',
+       'saisie_explication_titre' => 'Explication',
+       'saisie_fieldset_explication' => 'Un cadre qui pourra englober plusieurs champs.',
+       'saisie_fieldset_titre' => 'Groupe de champs',
+       'saisie_file_explication' => 'Envoi d\'un fichier',
+       'saisie_file_titre' => 'Fichier',
+       'saisie_hidden_explication' => 'Un champ pré-rempli que l\'utilisateur ne pourra pas voir.',
+       'saisie_hidden_titre' => 'Champ caché',
+       'saisie_input_explication' => 'Une simple ligne de texte, pouvant être visible ou masquée (mot de passe).',
+       'saisie_input_titre' => 'Ligne de texte',
+       'saisie_oui_non_explication' => 'Oui ou non, c\'est clair ? :)',
+       'saisie_oui_non_titre' => 'Oui ou non',
+       'saisie_radio_defaut_choix1' => 'Un',
+       'saisie_radio_defaut_choix2' => 'Deux',
+       'saisie_radio_defaut_choix3' => 'Trois',
+       'saisie_radio_explication' => 'Permet de choisir une option parmis plusieurs disponibles.',
+       'saisie_radio_titre' => 'Boutons radios',
+       'saisie_selecteur_article' => 'Affiche un navigateur de sélection d\'article',
+       'saisie_selecteur_article_titre' => 'Sélecteur d\'article',
+       'saisie_selecteur_rubrique' => 'Affiche un navigateur de sélection de rubrique',
+       'saisie_selecteur_rubrique_article' => 'Affiche un navigateur de sélection d\'article ou de rubrique',
+       'saisie_selecteur_rubrique_article_titre' => 'Sélecteur d\'article ou rubrique',
+       'saisie_selecteur_rubrique_titre' => 'Sélecteur de rubrique',
+       'saisie_selection_explication' => 'Choisir une option dans une liste déroulante.',
+       'saisie_selection_multiple_explication' => 'Permet de choisir plusieurs options avec une liste.',
+       'saisie_selection_multiple_titre' => 'Sélection multiple',
+       'saisie_selection_titre' => 'Liste déroulante',
+       'saisie_textarea_explication' => 'Un champ de texte sur plusieurs lignes.',
+       'saisie_textarea_titre' => 'Bloc de texte',
+
+       // T
+       'tous_visiteurs' => 'Tous les visiteurs (même non enregistrés)',
+       'tout_selectionner' => 'Tout sélectionner', # NEW
+
+       // V
+       'vue_sans_reponse' => '<i>Sans réponse</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_it.php b/www/plugins/saisies/lang/saisies_it.php
new file mode 100644 (file)
index 0000000..81f69d5
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Sfoglia l\'articolo',
+       'bouton_parcourir_docs_breve' => 'Sfoglia la breve',
+       'bouton_parcourir_docs_rubrique' => 'Sfoglia la rubrica',
+       'bouton_parcourir_mediatheque' => 'Sfoglia la mediateca',
+
+       // C
+       'construire_action_annuler' => 'Annulla',
+       'construire_action_configurer' => 'Configura',
+       'construire_action_deplacer' => 'Sposta',
+       'construire_action_dupliquer' => 'Duplica',
+       'construire_action_dupliquer_copie' => '(copia)',
+       'construire_action_supprimer' => 'Elimina',
+       'construire_ajouter_champ' => 'Aggiungi un campo',
+       'construire_attention_enregistrer' => 'Non dimenticare di salvare le tue modifiche!',
+       'construire_attention_modifie' => 'Il modulo in oggetto è diverso dal modulo iniziale. Hai la possibilità di reinizializzare il suo stato a quello precedente alle modifiche.',
+       'construire_attention_supprime' => 'Le modifiche includono l\'eliminazione di alcuni campi. Conferma il salvataggio di questa nuova versione del modulo.',
+       'construire_aucun_champs' => 'Al momento non è presente alcun campo in questo modulo.',
+       'construire_confirmer_supprimer_champ' => 'Vuoi veramente eliminare questo campo?',
+       'construire_info_nb_champs_masques' => '@nb@ campo(i) con maschera. Configura il gruppo.',
+       'construire_position_explication' => 'Indica prima di quale altro campo sarà spostato quello corrente.',
+       'construire_position_fin_formulaire' => 'Alla fine del modulo',
+       'construire_position_fin_groupe' => 'Alla fine del gruppo @groupe@',
+       'construire_position_label' => 'Posizione del campo',
+       'construire_reinitialiser' => 'Reinizializza il modulo',
+       'construire_reinitialiser_confirmer' => 'Perderai tutte le modifiche. Sei sicuro di voler tornare al modulo iniziale?',
+       'construire_verifications_aucune' => 'Nessuna',
+       'construire_verifications_label' => 'Tipo di verifica da effettuare',
+
+       // E
+       'erreur_generique' => 'Ci sono degli errori nei campi di seguito, si prega di verificare gli inserimenti',
+       'erreur_option_nom_unique' => 'Questo nome è già utilizzato da un altro campo e deve essere univoco all\'interno del modulo.',
+
+       // I
+       'info_configurer_saisies' => 'Pagina di test di Saisies',
+
+       // L
+       'label_annee' => 'Anno',
+       'label_jour' => 'Giorno',
+       'label_mois' => 'Mese',
+
+       // O
+       'option_aff_art_interface_explication' => 'Mostra unicamente gli articoli della lingua dell\'utente',
+       'option_aff_art_interface_label' => 'Visualizzazione multilingua',
+       'option_aff_langue_explication' => 'Mostra la lingua dell\'articolo o della rubrica selezionata davanti al titolo',
+       'option_aff_langue_label' => 'Mostra la lingua',
+       'option_aff_rub_interface_explication' => 'Mostra unicamente le rubriche della lingua dell\'utente',
+       'option_aff_rub_interface_label' => 'Visualizzazione multilingua',
+       'option_attention_explication' => 'Un messaggio più importante dei una spiegazione.',
+       'option_attention_label' => 'Avvertimento',
+       'option_autocomplete_defaut' => 'Lascia predefinito',
+       'option_autocomplete_explication' => 'Al caricamento della pagina, il tuo navigatore può preimpostare il campo in funzione della sua storia',
+       'option_autocomplete_label' => 'Preimpostazione del campo',
+       'option_autocomplete_off' => 'Disattiva',
+       'option_autocomplete_on' => 'Attiva',
+       'option_cacher_option_intro_label' => 'Nascondi la prima scelta vuota',
+       'option_choix_destinataires_explication' => 'Uno o più autori tra i quali l\'utente potrà fare una scelta. Se non si seleziona niente, è l\'autore che ha installato il sito che sarà scelto.',
+       'option_choix_destinataires_label' => 'Possibili destinatari',
+       'option_class_label' => 'Classi CSS supplementari',
+       'option_cols_explication' => 'Larghezza del blocco in numero di caratteri. Questa opzione non è sempre applicata poichè gli stili CSS la possono annullare.',
+       'option_cols_label' => 'Larghezza',
+       'option_datas_explication' => 'Indica una scelta per riga con il formato "chiave|Etichetta della scelta"',
+       'option_datas_label' => 'Elenco delle scelte possibili',
+       'option_defaut_label' => 'Valore predefinito',
+       'option_disable_avec_post_explication' => 'Identica all\'opzione precedente ma invia lo stesso il valore in un campo nascosto.',
+       'option_disable_avec_post_label' => 'Disattiva ma invia',
+       'option_disable_explication' => 'Il campo non può ottenere il focus.',
+       'option_disable_label' => 'Disattiva il campo',
+       'option_erreur_obligatoire_explication' => 'Vous pouvez personnaliser le message d\'erreur affiché pour indiquer l\'obligation (sinon laisser vide).', # NEW
+       'option_erreur_obligatoire_label' => 'Message d\'obligation', # NEW
+       'option_explication_explication' => 'Se necessario, una frase breve che descrive il campo.',
+       'option_explication_label' => 'Spiegazione',
+       'option_groupe_affichage' => 'Visualizzazione',
+       'option_groupe_description' => 'Descrizione',
+       'option_groupe_utilisation' => 'Utilizzazione',
+       'option_groupe_validation' => 'Validazione',
+       'option_heure_pas_explication' => 'Lorsque vous utilisez l’horaire, un menu s’affiche pour aider à saisir heures et minutes. Vous pouvez ici choisir l’intervalle de temps entre chaque choix (par défaut 30min).', # NEW
+       'option_heure_pas_label' => 'Intervalle des minutes dans le menu d’aide à la saisie', # NEW
+       'option_horaire_label' => 'Horaire', # NEW
+       'option_horaire_label_case' => 'Permettre de saisie aussi l’horaire', # NEW
+       'option_info_obligatoire_explication' => 'Puoi modificare l\'indicazione predefinita per i campi obbligatori : <i>[Obbligatorio]</i>.',
+       'option_info_obligatoire_label' => 'Indicazione obbligatorio',
+       'option_inserer_barre_choix_edition' => 'barra del testo completa',
+       'option_inserer_barre_choix_forum' => 'barra dei forum',
+       'option_inserer_barre_explication' => 'Inserisci una barra del testo se disponibile (porte-plume attivo).',
+       'option_inserer_barre_label' => 'Inserisci una barra di utility',
+       'option_label_case_label' => 'Etichetta a lato della casella',
+       'option_label_explication' => 'Il titolo che sarà mostrato.',
+       'option_label_label' => 'Etichetta',
+       'option_maxlength_explication' => 'L\'utente non può digiatare più caratteri del numero qui indicato.',
+       'option_maxlength_label' => 'Numero massimo di caratteri',
+       'option_multiple_explication' => 'L\'utente può selezionare più valori',
+       'option_multiple_label' => 'Scelta multipla',
+       'option_nom_explication' => 'Un nome informatico che indentifica il campo. Deve contentere solo caratteri alfanumerici minuscoli o il carattere "_".',
+       'option_nom_label' => 'Nome del campo',
+       'option_obligatoire_label' => 'Campo obbligatorio',
+       'option_option_intro_label' => 'Etichetta del primo campo vuoto',
+       'option_option_statut_label' => 'Mostra gli stati',
+       'option_pliable_label' => 'Richiudibile',
+       'option_pliable_label_case' => 'Il gruppo di campi può essere chiuso.',
+       'option_plie_label' => 'Già chiuso',
+       'option_plie_label_case' => 'Se il gruppo di campi è richiudibile, sarà già chiuso alla visualizzazione del modulo.',
+       'option_previsualisation_explication' => 'Se porte-plume è attivo, aggiungi una scheda per previsualizzare la resa del testo inserito.',
+       'option_previsualisation_label' => 'Attiva la previsualizzazione',
+       'option_readonly_explication' => 'Il campo può essere letto, selezionato, ma non modificato.',
+       'option_readonly_label' => 'Sola lettura',
+       'option_rows_explication' => 'Altezza del blocco in numero ri righe. Questa opzione non è sempre applicata poichè gli stili CSS del sito potrebbero annullarla.',
+       'option_rows_label' => 'Numero di righe',
+       'option_size_explication' => 'Larghezza del campo in numero di caratteri. Questa opzione non è sempre applicata poich%egrave; gli stili CSS del sito potrebbero annullarla.',
+       'option_size_label' => 'Dimensione del campo',
+       'option_type_choix_plusieurs' => 'Consenti all\'utente di scegliere <strong>più</strong> destinatari.',
+       'option_type_choix_tous' => 'Imposta <strong>tutti</strong> questi autori come destinatari. L\'utente non avrà alcuna scelta.',
+       'option_type_choix_un' => 'Consenti all\'utente di scegliere <strong>un solo</strong> destinatario.',
+       'option_type_explication' => 'In modalità "mascherata", il contenuto del campo non sarà visibile.',
+       'option_type_label' => 'Tipo del campo',
+       'option_type_password' => 'Mascherato',
+       'option_type_text' => 'Normale',
+
+       // S
+       'saisie_auteurs_explication' => 'Consente di selezionare uno o più autori',
+       'saisie_auteurs_titre' => 'Autori',
+       'saisie_case_explication' => 'Consente di attivare o disattivare qualcosa.',
+       'saisie_case_titre' => 'Casella di spunta',
+       'saisie_checkbox_explication' => 'Consente di scegliere più opzioni da spuntare.',
+       'saisie_checkbox_titre' => 'Caselle di spunta',
+       'saisie_date_explication' => 'Consente di inserire una data con l\'aiuto di un calendario',
+       'saisie_date_titre' => 'Data',
+       'saisie_destinataires_explication' => 'Consente di scegliere uno o più destinatari tra gli autore selezionati.',
+       'saisie_destinataires_titre' => 'Destinatari',
+       'saisie_explication_explication' => 'Un testo esplicativo generale.',
+       'saisie_explication_titre' => 'Spiegazione',
+       'saisie_fieldset_explication' => 'Un blocco che può contenere più campi.',
+       'saisie_fieldset_titre' => 'Gruppo di campi',
+       'saisie_file_explication' => 'Invio di un file',
+       'saisie_file_titre' => 'File',
+       'saisie_hidden_explication' => 'Un campo preimpostato che l\'utente non potrà vedere.',
+       'saisie_hidden_titre' => 'Campo nascosto',
+       'saisie_input_explication' => 'Una semplice riga di testo, che può essere visibile o mascherata (password).',
+       'saisie_input_titre' => 'Riga di testo',
+       'saisie_oui_non_explication' => 'Si o no',
+       'saisie_oui_non_titre' => 'Si o no',
+       'saisie_radio_defaut_choix1' => 'Uno',
+       'saisie_radio_defaut_choix2' => 'Due',
+       'saisie_radio_defaut_choix3' => 'Tre',
+       'saisie_radio_explication' => 'Consente di scegliere un\'opzione tra più disponibili.',
+       'saisie_radio_titre' => 'Scelta unica',
+       'saisie_selecteur_article' => 'Mostra un navigatore per la selezione di un articolo',
+       'saisie_selecteur_article_titre' => 'Selettore d\'articolo',
+       'saisie_selecteur_rubrique' => 'Mostra un navigatore per la selezione di una rubrica',
+       'saisie_selecteur_rubrique_article' => 'Mostra un navigatore per la selezione di un articolo o di una rubrica',
+       'saisie_selecteur_rubrique_article_titre' => 'Selettore d\'articolo o rubrica',
+       'saisie_selecteur_rubrique_titre' => 'Selettore di rubrica',
+       'saisie_selection_explication' => 'Scegli una opzione nel menu a tendina.',
+       'saisie_selection_multiple_explication' => 'Consente di scegliere più opzioni con un elenco.',
+       'saisie_selection_multiple_titre' => 'Scelta multipla',
+       'saisie_selection_titre' => 'Menu a tendina',
+       'saisie_textarea_explication' => 'Un campo di testo su più linee.',
+       'saisie_textarea_titre' => 'Blocco di testo',
+
+       // T
+       'tous_visiteurs' => 'Tutti gli utenti (anche non registrati)',
+       'tout_selectionner' => 'Tout sélectionner', # NEW
+
+       // V
+       'vue_sans_reponse' => '<i>Senza risposta</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_ru.php b/www/plugins/saisies/lang/saisies_ru.php
new file mode 100644 (file)
index 0000000..7778323
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Посмотреть статью',
+       'bouton_parcourir_docs_breve' => 'Посмотреть новость',
+       'bouton_parcourir_docs_rubrique' => 'Посмотреть раздел',
+       'bouton_parcourir_mediatheque' => 'Изменить библиотеку мультимедиа',
+
+       // C
+       'construire_action_annuler' => 'Отменить',
+       'construire_action_configurer' => 'Настройки',
+       'construire_action_deplacer' => 'Переместить',
+       'construire_action_dupliquer' => 'Сделать копию',
+       'construire_action_dupliquer_copie' => '(копия)',
+       'construire_action_supprimer' => 'Удалить',
+       'construire_ajouter_champ' => 'Добавить поле',
+       'construire_attention_enregistrer' => 'Не забудьте сохранить внесенные изменения!',
+       'construire_attention_modifie' => 'На этой странице у вас есть возможность редактировать форму. Для того, чтобы вернуться к списку выбора форм, нажмите на кнопку ниже',
+       'construire_attention_supprime' => 'Изменения включают удаление полей. Пожалуйста, подтвердите регистрацию новой формы.',
+       'construire_aucun_champs' => 'На данный момент поля в форме отсутствуют',
+       'construire_confirmer_supprimer_champ' => 'Вы действительно хотите удалить это поле??',
+       'construire_info_nb_champs_masques' => '@nb@ скрытых полей',
+       'construire_position_explication' => 'На какое поле заменить?',
+       'construire_position_fin_formulaire' => 'В конце формы',
+       'construire_position_fin_groupe' => 'В конце группы @groupe@',
+       'construire_position_label' => 'Замена поля',
+       'construire_reinitialiser' => 'Вернуться назад',
+       'construire_reinitialiser_confirmer' => 'Вы действительно хотите вернуться назад?',
+       'construire_verifications_aucune' => 'Не проверять',
+       'construire_verifications_label' => 'Тип проверки',
+
+       // E
+       'erreur_generique' => 'Вы допустили ошибку! Проверьте введенную Вами информацию.',
+       'erreur_option_nom_unique' => 'Такое название поля уже используется.',
+
+       // I
+       'info_configurer_saisies' => 'Тестовая страница формы',
+
+       // L
+       'label_annee' => 'Год',
+       'label_jour' => 'День',
+       'label_mois' => 'Месяц',
+
+       // O
+       'option_aff_art_interface_explication' => 'Отображать только статьи в настройках языка пользователя',
+       'option_aff_art_interface_label' => 'Многоязычное отображение',
+       'option_aff_langue_explication' => 'Показать выбранный язык статьи или раздела перед названием',
+       'option_aff_langue_label' => 'Показать текущий язык',
+       'option_aff_rub_interface_explication' => 'Отображать только разделы в языковых настройках пользователя.',
+       'option_aff_rub_interface_label' => 'Многоязычное отображение',
+       'option_attention_explication' => 'Сообщение, которое является более важным нежели комментарий.',
+       'option_attention_label' => 'Примечание!',
+       'option_autocomplete_defaut' => 'По умолчанию',
+       'option_autocomplete_explication' => 'При загрузке страницы браузер может предварительно заполнить поля на основании истории',
+       'option_autocomplete_label' => 'Предварительное заполнение поля',
+       'option_autocomplete_off' => 'Отключить',
+       'option_autocomplete_on' => 'Включить',
+       'option_cacher_option_intro_label' => 'Не отображать первый пустой вариант',
+       'option_choix_destinataires_explication' => 'Один или несколько авторов, среди которых пользователь может сделать свой ​​выбор. Если ничего не выбрано, то то будет выбран автор, который сейчас на сайте.',
+       'option_choix_destinataires_label' => 'Возможные получатели',
+       'option_class_label' => 'Дополнительные CSS классы',
+       'option_cols_explication' => 'Длина поля в символах. С помощью CSS возможно переопределить значение данного поля.',
+       'option_cols_label' => 'Ширина',
+       'option_datas_explication' => 'Укажите возможные варианты в формате: ключ|вариант',
+       'option_datas_label' => 'Список возможных вариантов',
+       'option_defaut_label' => 'Выводить по умолчанию',
+       'option_disable_avec_post_explication' => 'Такой же вариант как и предыдущий, но вносит значение в скрытое поле.',
+       'option_disable_avec_post_label' => 'Отключено, но опубликовано.',
+       'option_disable_explication' => 'Поле не может получить фокус',
+       'option_disable_label' => 'Сделать поле неактивным',
+       'option_erreur_obligatoire_explication' => 'Настройте сообщения об ошибке для обязательных полей (в противном случае - оставьте пустым) ',
+       'option_erreur_obligatoire_label' => 'Обязательное сообщение',
+       'option_explication_explication' => 'Краткое описание (по необходимости)',
+       'option_explication_label' => 'Комментарий',
+       'option_groupe_affichage' => 'Показать',
+       'option_groupe_description' => 'Описание',
+       'option_groupe_utilisation' => 'Использование',
+       'option_groupe_validation' => 'Валидация',
+       'option_heure_pas_explication' => 'Lorsque vous utilisez l’horaire, un menu s’affiche pour aider à saisir heures et minutes. Vous pouvez ici choisir l’intervalle de temps entre chaque choix (par défaut 30min).', # NEW
+       'option_heure_pas_label' => 'Intervalle des minutes dans le menu d’aide à la saisie', # NEW
+       'option_horaire_label' => 'Horaire', # NEW
+       'option_horaire_label_case' => 'Permettre de saisie aussi l’horaire', # NEW
+       'option_info_obligatoire_explication' => 'Вы можете изменить стандартные настройки обязательного заполнения полей.. ',
+       'option_info_obligatoire_label' => 'Обязательное заполнение полей',
+       'option_inserer_barre_choix_edition' => 'Да',
+       'option_inserer_barre_choix_forum' => 'Только форум',
+       'option_inserer_barre_explication' => 'Вставить porte-plume?',
+       'option_inserer_barre_label' => 'Панель управления',
+       'option_label_case_label' => 'Позиция чекбокса',
+       'option_label_explication' => 'Название поля',
+       'option_label_label' => 'Название',
+       'option_maxlength_explication' => 'Пользователь не может ввести больше знаков чем:',
+       'option_maxlength_label' => 'Максимальное к-во символов',
+       'option_multiple_explication' => 'Пользователю предоставляется возможность выбрать несколько вариантов',
+       'option_multiple_label' => 'Множественный выбор',
+       'option_nom_explication' => 'ID компьютера , который идентифицирует поле. Он может содержать только строчные буквы и цифры и символ подчеркивания "_".',
+       'option_nom_label' => 'Название поля',
+       'option_obligatoire_label' => 'Поле обязательное для заполнения',
+       'option_option_intro_label' => 'Обозначение для пустого выбора',
+       'option_option_statut_label' => 'Показать статус',
+       'option_pliable_label' => 'Расширяемая',
+       'option_pliable_label_case' => 'Группы полей могут быть расширены или сжаты.',
+       'option_plie_label' => 'Сжато.',
+       'option_plie_label_case' => 'Если группу полей можно расширить или сжать, тогда эта опция их сожмет с отображением полей.',
+       'option_previsualisation_explication' => 'Создать вкладку для просмотра введенного текста?',
+       'option_previsualisation_label' => 'Просмотр',
+       'option_readonly_explication' => 'Поле можно просмотреть, выбрать, но изменить нельзя.',
+       'option_readonly_label' => 'Только чтение',
+       'option_rows_explication' => 'Высота поля в строках.',
+       'option_rows_label' => 'Высота',
+       'option_size_explication' => 'Длина поля в символах.',
+       'option_size_label' => 'Размер поля',
+       'option_type_choix_plusieurs' => 'Позволяет выбрать <strong>несколько</strong> получателей.',
+       'option_type_choix_tous' => 'Отметить <strong>всех</strong> авторов как получателей. Пользователю выбор не предоставляется.',
+       'option_type_choix_un' => 'Сделать возможным выбор только одного получателя.',
+       'option_type_explication' => 'В "скрытом" режиме содержимое поля будет отображаться в виде звездочек.',
+       'option_type_label' => 'Тип поля',
+       'option_type_password' => 'Скрытый',
+       'option_type_text' => 'Нормальный',
+
+       // S
+       'saisie_auteurs_explication' => 'Позволяет выбрать одного или несколько авторов.',
+       'saisie_auteurs_titre' => 'Автора',
+       'saisie_case_explication' => 'Используется для включения/отключения определенной опции.',
+       'saisie_case_titre' => 'Единичный выбор ',
+       'saisie_checkbox_explication' => 'Используется для выбора нескольких вариантов при помощи check-box.',
+       'saisie_checkbox_titre' => 'Чекбокс',
+       'saisie_date_explication' => 'Используется для ввода даты при помощи календаря.',
+       'saisie_date_titre' => 'Дата',
+       'saisie_destinataires_explication' => 'Используется для выбора одного или нескольких получателей из числа предварительно выбранных авторов.',
+       'saisie_destinataires_titre' => 'Получатели',
+       'saisie_explication_explication' => 'Многострочное поле input',
+       'saisie_explication_titre' => 'Информация',
+       'saisie_fieldset_explication' => 'Форма, которая содержит несколько полей.',
+       'saisie_fieldset_titre' => 'Филдсет',
+       'saisie_file_explication' => 'Отправить файл',
+       'saisie_file_titre' => 'Файл',
+       'saisie_hidden_explication' => 'Предварительно заполненные поля, которые недоступны пользователю.',
+       'saisie_hidden_titre' => 'Скрытое поле',
+       'saisie_input_explication' => 'Строчка текста, которая может быть как скрытой так и видимой (пароль).',
+       'saisie_input_titre' => 'Текстовое поле',
+       'saisie_oui_non_explication' => 'Или ДА или НЕТ ',
+       'saisie_oui_non_titre' => 'Да или нет',
+       'saisie_radio_defaut_choix1' => 'Один',
+       'saisie_radio_defaut_choix2' => 'Два',
+       'saisie_radio_defaut_choix3' => 'Три',
+       'saisie_radio_explication' => 'Используется для выбора одной опции из нескольких.',
+       'saisie_radio_titre' => 'Радио кнопка',
+       'saisie_selecteur_article' => 'Отобразить браузер выбора статьи',
+       'saisie_selecteur_article_titre' => 'Селектор статьи',
+       'saisie_selecteur_rubrique' => 'Отобразить браузер выбора раздела',
+       'saisie_selecteur_rubrique_article' => 'Отобразить браузер выбора статьи или раздела',
+       'saisie_selecteur_rubrique_article_titre' => 'Селектор статьи или раздела.',
+       'saisie_selecteur_rubrique_titre' => 'Селектор раздела.',
+       'saisie_selection_explication' => 'Выбрать пункт из выпадающего списка.',
+       'saisie_selection_multiple_explication' => 'Используется для выбора нескольких вариантов из списка.',
+       'saisie_selection_multiple_titre' => 'Множественный выбор',
+       'saisie_selection_titre' => 'Выпадающий список',
+       'saisie_textarea_explication' => 'Многострочное текстовое поле',
+       'saisie_textarea_titre' => 'Текстовое поле',
+
+       // T
+       'tous_visiteurs' => 'Все посетители (в том числе не зарегистрированы)',
+       'tout_selectionner' => 'Tout sélectionner', # NEW
+
+       // V
+       'vue_sans_reponse' => '<i>Без ответа</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/lang/saisies_sk.php b/www/plugins/saisies/lang/saisies_sk.php
new file mode 100644 (file)
index 0000000..27c54ab
--- /dev/null
@@ -0,0 +1,180 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/saisies?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // B
+       'bouton_parcourir_docs_article' => 'Prehľadať článok',
+       'bouton_parcourir_docs_breve' => 'Prehľadať novinku',
+       'bouton_parcourir_docs_rubrique' => 'Prehľadať rubriku',
+       'bouton_parcourir_mediatheque' => 'Prehľadať knižnicu multimédií',
+
+       // C
+       'construire_action_annuler' => 'Zrušiť',
+       'construire_action_configurer' => 'Nastaviť',
+       'construire_action_deplacer' => 'Presunúť',
+       'construire_action_dupliquer' => 'Duplikovať',
+       'construire_action_dupliquer_copie' => '(kópia)',
+       'construire_action_supprimer' => 'Odstrániť',
+       'construire_ajouter_champ' => 'Pridať pole',
+       'construire_attention_enregistrer' => 'Nezabudnite uložiť zmeny!',
+       'construire_attention_modifie' => 'Tento formulár sa odlišuje od pôvodného. Máte možnosť ho obnoviť do stavu pred svojimi zmenami.',
+       'construire_attention_supprime' => 'Medzi vašimi zmenami je vymazanie niekoľkých polí. Potvrďte, prosím, registráciu tejto verzie formulára.',
+       'construire_aucun_champs' => 'V tomto formulári nie je momentálne žiadne pole',
+       'construire_confirmer_supprimer_champ' => 'Chcete odstrániť toto pole?',
+       'construire_info_nb_champs_masques' => '@nb@ skryté (-ých) pole (-í/-ia) času na nastavenie skupiny.',
+       'construire_position_explication' => 'Uveďte akékoľvek ďalšie pole predtým, ako sa vloží.',
+       'construire_position_fin_formulaire' => 'Na koniec formulára',
+       'construire_position_fin_groupe' => 'Na koniec skupiny @groupe@',
+       'construire_position_label' => 'Umiestnenie poľa',
+       'construire_reinitialiser' => 'Znova načítať formulár',
+       'construire_reinitialiser_confirmer' => 'Stratíte všetky svoje zmeny. Určite sa chcete vrátiť na pôvodný formulár?',
+       'construire_verifications_aucune' => 'Žiadne',
+       'construire_verifications_label' => 'Typ overenia, ktorý sa má vykonať',
+
+       // E
+       'erreur_generique' => 'V poliach sú chyby; prosím, skontrolujte údaje, ktoré ste zadali',
+       'erreur_option_nom_unique' => 'Tento názov už používa iné pole, a v tomto formulári musí byť jedinečný.',
+
+       // I
+       'info_configurer_saisies' => 'Testovacia stránka Saisies',
+
+       // L
+       'label_annee' => 'Rok',
+       'label_jour' => 'Deň',
+       'label_mois' => 'Mesiac',
+
+       // O
+       'option_aff_art_interface_explication' => 'Zobrazovať len články v jazyku používateľa',
+       'option_aff_art_interface_label' => 'Viacjazyčné zobrazenie',
+       'option_aff_langue_explication' => 'Pred názvom zobraziť vybratý jazyk článku alebo rubriky',
+       'option_aff_langue_label' => 'Zobraziť jazyk',
+       'option_aff_rub_interface_explication' => 'Zobraziť len rubriky v jazyku používateľa',
+       'option_aff_rub_interface_label' => 'Viacjazyčné zobrazenie',
+       'option_attention_explication' => 'Správa je dôležitejšia ako vysvetlivka.',
+       'option_attention_label' => 'Varovanie',
+       'option_autocomplete_defaut' => 'Nechať ako predvolené',
+       'option_autocomplete_explication' => 'Pri nahrávaní stránky môže váš prehliadač automaticky vyplniť polia podľa histórie',
+       'option_autocomplete_label' => 'Automaticky vyplniť pole',
+       'option_autocomplete_off' => 'Deaktivovať',
+       'option_autocomplete_on' => 'Aktivovať',
+       'option_cacher_option_intro_label' => 'Skryť prvý prázdny výber',
+       'option_choix_destinataires_explication' => 'Jeden autor alebo viacerí, z ktorých si používateľ môže vybrať. Ak nie je vybratý žiaden, vyberie sa autor, ktorý nainštaloval stránku.',
+       'option_choix_destinataires_label' => 'Možní príjemcovia',
+       'option_class_label' => 'Ďalšie triedy CSS',
+       'option_cols_explication' => 'Šírka poľa v znakoch. Táto možnosť sa vždy nepoužíva, lebo štýly CSS na vašej stránke ju môžu prepísať.',
+       'option_cols_label' => 'Šírka',
+       'option_datas_explication' => 'Musíte definovať výber pre každý riadok vo formulári "kľúč|označenie výberu"',
+       'option_datas_label' => 'Zoznam dostupných možností',
+       'option_defaut_label' => 'Predvolená hodnota',
+       'option_disable_avec_post_explication' => 'Rovnaká ako predošlá možnosť, ale hodnotu pošle v skrytom poli.',
+       'option_disable_avec_post_label' => 'Deaktivovať ale poslať.',
+       'option_disable_explication' => 'Na pole sa nedá zacieliť.',
+       'option_disable_label' => 'Deaktivovať pole',
+       'option_erreur_obligatoire_explication' => 'Zobrazovanú chybovú správu môžete upraviť tak, aby označovala povinnosť',
+       'option_erreur_obligatoire_label' => 'Správa s povinnosťou',
+       'option_explication_explication' => 'Ak je to potrebné, krátka veta popisujúca zmysel daného poľa.',
+       'option_explication_label' => 'Vysvetlenie',
+       'option_groupe_affichage' => 'Zobraziť',
+       'option_groupe_description' => 'Popis',
+       'option_groupe_utilisation' => 'Použitie',
+       'option_groupe_validation' => 'Overenie',
+       'option_heure_pas_explication' => 'Pri používaní diára sa zobrazí menu, ktoré vám pomôže zadať hodiny a minúty. Tak môžete vybrať časový interval pre každý údaj (predvolený – 30 min).',
+       'option_heure_pas_label' => 'Interval v minútach v menu pomocníka k zápisu do poľa',
+       'option_horaire_label' => 'Diár',
+       'option_horaire_label_case' => 'Povoliť zápis do diára',
+       'option_info_obligatoire_explication' => 'Môžete zmeniť predvolenú povinnosť vyplniť polia: <i>[Povinné]</i>.',
+       'option_info_obligatoire_label' => 'Označenie povinnosti',
+       'option_inserer_barre_choix_edition' => 'celý editovací panel s nástrojmi',
+       'option_inserer_barre_choix_forum' => 'panel s nástrojmi pre diskusné fóra',
+       'option_inserer_barre_explication' => 'Vložiť panel s nástrojmi porte-plume, ak je tento nástroj aktivovaný.',
+       'option_inserer_barre_label' => 'Vložiť panel s nástrojmi',
+       'option_label_case_label' => 'Označenie sa nachádza pod zaškrtávacím políčkom',
+       'option_label_explication' => 'Zobrazí sa nadpis.',
+       'option_label_label' => 'Označenie',
+       'option_maxlength_explication' => 'Používateľ nemôže napísať viac znakov ako určuje toto číslo.',
+       'option_maxlength_label' => 'Maximálny počet znakov',
+       'option_multiple_explication' => 'Používateľ si bude môcť vybrať niekoľko hodnôt',
+       'option_multiple_label' => 'Výber z viacerých možností',
+       'option_nom_explication' => 'Počítačový názov, ktorý pomenúva pole. Môžu v ňom byť malé písmená abecedy alebo podčiarkovník "_".',
+       'option_nom_label' => 'Názov poľa',
+       'option_obligatoire_label' => 'Povinné pole',
+       'option_option_intro_label' => 'Označenie prvého prázdneho výberu',
+       'option_option_statut_label' => 'Zobraziť stav',
+       'option_pliable_label' => 'Roztiahnuteľné',
+       'option_pliable_label_case' => 'Skupina polí sa dá roztiahnuť alebo stiahnuť.',
+       'option_plie_label' => 'Už stiahnutá',
+       'option_plie_label_case' => 'Ak sa dá skupina polí stiahnuť a roztiahnuť, táto možnosť ju v zobrazeniach formulára nastaví ako už stiahnutú.',
+       'option_previsualisation_explication' => 'Ak je aktivovaný porte-plume, pridať kartu do ukážky vzhľadu zadaného textu.',
+       'option_previsualisation_label' => 'Aktivovať ukážky',
+       'option_readonly_explication' => 'Toto pole môžete zobraziť, vybrať, ale nie upravovať.',
+       'option_readonly_label' => 'Len na čítanie',
+       'option_rows_explication' => 'Výška poľa v riadkoch. Táto možnosť sa nepoužije vždy, pretože  štýly CSS na vašej stránke ju môžu zmeniť.',
+       'option_rows_label' => 'Počet riadkov',
+       'option_size_explication' => 'Šírka poľa v riadkoch. Táto možnosť sa nepoužije vždy, pretože štýly CSS na vašej stránke ju môžu zmeniť.',
+       'option_size_label' => 'Veľkosť poľa',
+       'option_type_choix_plusieurs' => 'Umožní používateľovi vybrať si <strong>mnohých</ strong> príjemcov.',
+       'option_type_choix_tous' => 'Urobiť príjemcov zo <strong>všetkých</ strong> týchto autorov. Používateľ nebude mať na výber.',
+       'option_type_choix_un' => 'Povoliť používateľovi vybrať si <strong>jedného</ strong> príjemcu.',
+       'option_type_explication' => 'V režime hesla sa obsah napísaný do poľa nahradí hviezdičkami.',
+       'option_type_label' => 'Typ poľa',
+       'option_type_password' => 'Maskované',
+       'option_type_text' => 'Normálny',
+
+       // S
+       'saisie_auteurs_explication' => 'Umožňuje vám vybrať jedného alebo viacerých autorov',
+       'saisie_auteurs_titre' => 'Autori',
+       'saisie_case_explication' => 'Používa sa na aktivovanie alebo deaktivovanie konkrétnej možnosti.',
+       'saisie_case_titre' => 'Jedno zaškrtávacie políčko',
+       'saisie_checkbox_explication' => 'Používa sa na výber niekoľkých možností pomocou zaškrtávacích políčok.',
+       'saisie_checkbox_titre' => 'Zaškrtávacie políčka',
+       'saisie_date_explication' => 'Používa sa na zadávanie dátumu pomocou nástroja kalendára',
+       'saisie_date_titre' => 'Dátum',
+       'saisie_destinataires_explication' => 'Používa sa na výber jedného príjemcu alebo viacerých z dopredu vybraných autorov.',
+       'saisie_destinataires_titre' => 'Príjemcovia',
+       'saisie_explication_explication' => 'Všeobecný vysvetľujúci popis.',
+       'saisie_explication_titre' => 'Vysvetlenie',
+       'saisie_fieldset_explication' => 'Rám, v ktorom môže byť niekoľko polí.',
+       'saisie_fieldset_titre' => 'Skupina polí',
+       'saisie_file_explication' => 'Poslať súbor',
+       'saisie_file_titre' => 'Súbor',
+       'saisie_hidden_explication' => 'Predvyplnené pole, ktoré používateľ nikdy neuvidí.',
+       'saisie_hidden_titre' => 'Skryté pole',
+       'saisie_input_explication' => 'Jednoduchý riadok s textom, ktorý môže byť viditeľný alebo skrytý (heslo).',
+       'saisie_input_titre' => 'Textové pole',
+       'saisie_oui_non_explication' => 'Odpoveď buď Áno alebo Nie',
+       'saisie_oui_non_titre' => 'Áno alebo Nie',
+       'saisie_radio_defaut_choix1' => 'Jeden',
+       'saisie_radio_defaut_choix2' => 'Dva',
+       'saisie_radio_defaut_choix3' => 'Tri',
+       'saisie_radio_explication' => 'Používa sa na výber jednej možnosti z viacerých dostupných.',
+       'saisie_radio_titre' => 'Rádiové gombíky',
+       'saisie_selecteur_article' => 'Zobraziť prehliadač výberu článku',
+       'saisie_selecteur_article_titre' => 'Výber článku',
+       'saisie_selecteur_rubrique' => 'Zobraziť prehliadač výberu rubriky',
+       'saisie_selecteur_rubrique_article' => 'Zobraziť prehliadač výberu článku alebo rubriky',
+       'saisie_selecteur_rubrique_article_titre' => 'Výber článku alebo rubriky',
+       'saisie_selecteur_rubrique_titre' => 'Výber rubriky',
+       'saisie_selection_explication' => 'Vyberte možnosť z rozbaľovacieho zoznamu.',
+       'saisie_selection_multiple_explication' => 'Používa sa na výber niekoľkých možností zo zoznamu.',
+       'saisie_selection_multiple_titre' => 'Výber z viacerých možností',
+       'saisie_selection_titre' => 'Rozbaľovací zoznam',
+       'saisie_textarea_explication' => 'Textové pole s viacerými riadkami.',
+       'saisie_textarea_titre' => 'Blok textu',
+
+       // T
+       'tous_visiteurs' => 'Všetci návštevníci (aj ne­za­re­gis­tro­va­ní)',
+       'tout_selectionner' => 'Vybrať všetko',
+
+       // V
+       'vue_sans_reponse' => '<i>Bez reakcie</i>',
+
+       // Z
+       'z' => 'zzz'
+);
+
+?>
diff --git a/www/plugins/saisies/paquet.xml b/www/plugins/saisies/paquet.xml
new file mode 100644 (file)
index 0000000..dd2aae2
--- /dev/null
@@ -0,0 +1,29 @@
+<paquet\r
+       prefix="saisies"\r
+       categorie="outil"\r
+       version="1.31.4"\r
+       etat="test"\r
+       compatibilite="[2.0.0;3.0.*]"\r
+       logo="images/logo_saisie_48.png"\r
+       documentation="http://www.spip-contrib.net/Saisies"\r
+>\r
+       <nom>Saisies</nom>\r
+       <auteur lien="http://contrib.spip.net/Matthieu-Marcillaud">Matthieu Marcillaud</auteur>\r
+       <auteur lien="http://contrib.spip.net/RastaPopoulos">RastaPopoulos</auteur>\r
+       <auteur lien="http://contrib.spip.net/Joseph">Joseph</auteur>\r
+       <auteur lien="http://www.ldd.fr">Les Développements Durables</auteur>\r
+       <licence>GNU/GPL</licence>\r
+       \r
+       <traduire module="saisies" reference="fr" gestionnaire="salvatore" />\r
+\r
+       <pipeline nom="header_prive" inclure="saisies_pipelines.php" />\r
+       <pipeline nom="affichage_final" inclure="saisies_pipelines.php" />\r
+       <pipeline nom="saisies_autonomes" inclure="saisies_pipelines.php" />\r
+       <pipeline nom="formulaire_saisies" inclure="saisies_pipelines.php" />\r
+       <pipeline nom="formulaire_charger" inclure="saisies_pipelines.php" />\r
+       <pipeline nom="formulaire_verifier" inclure="saisies_pipelines.php" />\r
+       <pipeline nom="styliser" inclure="saisies_pipelines.php" />\r
+\r
+       <utilise nom="verifier" />\r
+       <utilise nom="spip_bonux" />\r
+</paquet>\r
diff --git a/www/plugins/saisies/plugin.xml b/www/plugins/saisies/plugin.xml
new file mode 100644 (file)
index 0000000..cc84caa
--- /dev/null
@@ -0,0 +1,65 @@
+<plugin>\r
+    <nom><multi>[fr]Saisies pour formulaires[en]Entries for forms</multi></nom>\r
+       <slogan>Ecrire facilement des champs de formulaires</slogan>\r
+    <auteur>Matthieu Marcillaud - RastaPopoulos - Joseph</auteur>\r
+    <licence>&#169; 2009-2012 GNU/GPL</licence>\r
+    <version>1.31.4</version>\r
+    <etat>test</etat>\r
+    <categorie>outil</categorie>\r
+    \r
+       <description>\r
+               <multi>\r
+               [fr]\r
+               Ce plugin permet de faciliter l'&#233;criture de champs de formulaires en proposant une\r
+               balise #SAISIE. Le HTML g&#233;n&#233;r&#233; est compatible avec la nomenclature des formulaires\r
+               propos&#233;e par SPIP > 2.0 et avec le plugin de configuration CFG.\r
+               [en]\r
+               This plugin makes it easier to write form fields by providing a #SAISIE tag. \r
+               The generated HTML is compatible with the classification of forms\r
+               proposed by SPIP > 2.0 and with the configuration plugin CFG.\r
+               </multi>\r
+       </description>\r
+    \r
+    <lien>http://www.spip-contrib.net/Saisies</lien>\r
+    <prefix>saisies</prefix>\r
+    <icon>images/logo_saisie_48.png</icon>\r
+    \r
+    <fonctions>balise/saisie.php</fonctions>\r
+    <fonctions>inc/saisies.php</fonctions>\r
+    <fonctions>saisies_fonctions.php</fonctions>\r
+    <options>saisies_options.php</options>\r
+\r
+    <pipeline>\r
+       <nom>header_prive</nom>\r
+       <inclure>saisies_pipelines.php</inclure>\r
+    </pipeline>\r
+    <pipeline>\r
+       <nom>affichage_final</nom>\r
+       <inclure>saisies_pipelines.php</inclure>\r
+    </pipeline>\r
+       <pipeline>\r
+               <nom>saisies_autonomes</nom>\r
+               <inclure>saisies_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>formulaire_saisies</nom>\r
+               <inclure>saisies_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>formulaire_charger</nom>\r
+               <inclure>saisies_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>formulaire_verifier</nom>\r
+               <inclure>saisies_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>styliser</nom>\r
+               <inclure>saisies_pipelines.php</inclure>\r
+       </pipeline>\r
+    \r
+       <necessite id="SPIP" version="[2.0.0;3.0.99]" />\r
+       <utilise id="verifier" />\r
+       <utilise id="spip_bonux" />\r
+       <traduire gestionnaire="salvatore" module="saisies" reference="fr" />\r
+</plugin>\r
diff --git a/www/plugins/saisies/prive/exec/construire_formulaire.html b/www/plugins/saisies/prive/exec/construire_formulaire.html
new file mode 100644 (file)
index 0000000..5cd0537
--- /dev/null
@@ -0,0 +1,3 @@
+<h1><:saisies:info_configurer_saisies:></h1>
+
+<div class="ajax">#FORMULAIRE_CONSTRUIRE_FORMULAIRE{test,#ARRAY,#ARRAY{modifier_nom,oui,nom_unique,oui}}</div>
diff --git a/www/plugins/saisies/prive/listes/articles_originaux_recursifs.html b/www/plugins/saisies/prive/listes/articles_originaux_recursifs.html
new file mode 100644 (file)
index 0000000..c62602e
--- /dev/null
@@ -0,0 +1,14 @@
+[(#SET{iteration,#ENV{iteration,1}})]
+[(#SET{separateur,[(#ENV{separateur}|concat{&nbsp;&rsaquo;&nbsp;})]})]
+<BOUCLE_rubriques(RUBRIQUES){id_parent}{tout}>
+       <optgroup label="#GET{separateur}#TITRE">
+               <BOUCLE_articles_originaux(ARTICLES){id_rubrique}{origine_traduction}>
+               [(#ENV{multiple}|oui)
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|in_array{#ENV{valeur,#ENV{defaut,#ARRAY}}}|oui) selected="selected"]>#GET{separateur}#TITRE</option>]
+               [(#ENV{multiple}|non)
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|=={#ENV{valeur,#ENV{defaut}}}|oui) selected="selected"]>#GET{separateur}#TITRE</option>]
+               <INCLURE{fond=prive/listes/articles_originaux_recursifs}{valeur=#ENV{valeur}}{id_rubrique=#ID_RUBRIQUE}{iteration=(#GET{iteration}|plus{1})}{separateur=#GET{separateur}}{_multiple}{defaut} />
+               </BOUCLE_articles_originaux>
+               <BOUCLE_ssrubriques(BOUCLE_rubriques)> </BOUCLE_ssrubriques>
+       </optgroup>
+</BOUCLE_rubriques>
diff --git a/www/plugins/saisies/prive/listes/rubriques_recursives.html b/www/plugins/saisies/prive/listes/rubriques_recursives.html
new file mode 100644 (file)
index 0000000..368e56b
--- /dev/null
@@ -0,0 +1,8 @@
+[(#SET{separateur,[(#ENV{separateur}|concat{&nbsp;&rsaquo;&nbsp;})]})]
+<BOUCLE_rubriques(RUBRIQUES){id_parent=#ENV{id_parent,#ENV{id_rubrique}}}{tout}>
+       [(#ENV{multiple}|oui)
+       <option value="#ID_RUBRIQUE"[(#ID_RUBRIQUE|in_array{#ENV{valeur,#ENV{defaut,#ARRAY}}}|oui) selected="selected"]>#GET{separateur}#TITRE</option>]
+       [(#ENV{multiple}|non)
+       <option value="#ID_RUBRIQUE"[(#ID_RUBRIQUE|=={#ENV{valeur,#ENV{defaut}}}|oui) selected="selected"]>#GET{separateur}#TITRE</option>]
+       <INCLURE{fond=prive/listes/rubriques_recursives,env,id_rubrique=#ID_RUBRIQUE,separateur=#GET{separateur}} />
+</BOUCLE_rubriques>
diff --git a/www/plugins/saisies/saisies-vues/_base.html b/www/plugins/saisies/saisies-vues/_base.html
new file mode 100644 (file)
index 0000000..53d3d6d
--- /dev/null
@@ -0,0 +1,43 @@
+[(#ENV{sans_reponse}|is_null|oui) [(#SET{sans_reponse,<:saisies:vue_sans_reponse:>})] ]\r
+[(#ENV{sans_reponse}|is_null|non) [(#SET{sans_reponse,#ENV{sans_reponse}})] ]\r
+\r
+#SET{valeur_uniquement,#ENV{valeur_uniquement}|et{#ENV{valeur_uniquement}|!={non}}|?{' ',''}}\r
+#SET{enfants,#ENV*{saisies}|et{#ENV*{saisies}|is_array}}\r
+\r
+[(#REM) On génère la réponse et on l'enregistre dans une variable. Doit être VIDE s'il n'y a pas de réponse. ]\r
+       #SET{reponse,''}\r
+       [(#CHEMIN{saisies-vues/#ENV{type_saisie}.html}|oui)\r
+               #SET{reponse,#INCLURE{fond=saisies-vues/#ENV{type_saisie},env,sans_reponse=#GET{sans_reponse}}|trim}\r
+       ]\r
+       [(#CHEMIN{saisies-vues/#ENV{type_saisie}.html}|non)\r
+               #SET{reponse,#ENV*{valeur}|trim}\r
+       ]\r
+\r
+[(#REM) Maintenant on affiche en encapsulant ou pas ]\r
+\r
+[(#REM) Cas normal avec présentation ]\r
+[(#GET{valeur_uniquement}|non)\r
+<div class="afficher[ afficher_(#ENV{nom})][ saisie_(#ENV{type_saisie})][ (#ENV{li_class})][ (#GET{reponse}|non)sans_reponse]">\r
+       [(#REM) S'il y a des enfants on n'inclut que la vue ]\r
+       [(#GET{enfants}|oui)\r
+               #GET{reponse}\r
+       ]\r
+       [(#GET{enfants}|non|et{#ENV{type_saisie}|!={explication}})\r
+               [<strong class="label">(#ENV{label_case,#ENV{label,#ENV{nom}}})</strong>]\r
+               <div class="valeur">\r
+               [(#GET{reponse}|sinon{#GET{sans_reponse}}|propre)]\r
+               </div>\r
+       ]\r
+</div>\r
+]\r
+\r
+[(#REM) Cas où on demande uniquement la valeur ]\r
+[(#GET{valeur_uniquement}|oui)\r
+       [(#REM) S'il y a des enfants on inclut que la vue ]\r
+       [(#GET{enfants}|oui)\r
+               #GET{reponse}\r
+       ]\r
+       [(#GET{enfants}|non)\r
+               [(#GET{reponse}|sinon{#GET{sans_reponse}}|propre)]\r
+       ]\r
+]\r
diff --git a/www/plugins/saisies/saisies-vues/auteurs.html b/www/plugins/saisies/saisies-vues/auteurs.html
new file mode 100644 (file)
index 0000000..e46baf5
--- /dev/null
@@ -0,0 +1,16 @@
+<BOUCLE_test_multiple(CONDITION){si #ENV{multiple}|=={on}|oui}>
+       [(#SET{valeur,[(#ENV*{valeur}|is_array|?{[(#ENV*{valeur})],[(#ENV*{valeur}|explode{','})]})]})]
+       <B_auteurs_selectionnes>
+       <ul>
+       <BOUCLE_auteurs_selectionnes(AUTEURS){id_auteur IN #GET*{valeur}}
+               {par num nom, nom}{statut ?}{statut != 5poubelle}{tout}>
+               <li class="choix">#NOM (#ID_AUTEUR)</li>
+       </BOUCLE_auteurs_selectionnes>
+       </ul>
+       </B_auteurs_selectionnes>
+</BOUCLE_test_multiple>
+       <BOUCLE_auteur_selectionne(AUTEURS){id_auteur=#ENV{valeur}}
+               {statut ?}{statut != 5poubelle}{tout}>
+               <p>#NOM (#ID_AUTEUR)</p>
+       </BOUCLE_auteur_selectionne>
+<//B_test_multiple>
diff --git a/www/plugins/saisies/saisies-vues/case.html b/www/plugins/saisies/saisies-vues/case.html
new file mode 100644 (file)
index 0000000..12a6e3e
--- /dev/null
@@ -0,0 +1 @@
+[<p>(#ENV*{valeur}|?{<:item_oui:>,<:item_non:>})</p>]
diff --git a/www/plugins/saisies/saisies-vues/checkbox.html b/www/plugins/saisies/saisies-vues/checkbox.html
new file mode 100644 (file)
index 0000000..c313025
--- /dev/null
@@ -0,0 +1,11 @@
+[(#REM) datas peut être une chaine qu'on sait décomposer ]\r
+#SET{datas, #ENV{datas}|saisies_chaine2tableau}\r
+#SET{valeur, #ENV{valeur}|saisies_valeur2tableau}\r
+\r
+<B_choix>\r
+<ul>\r
+       <BOUCLE_choix(POUR){tableau #GET{valeur}}>\r
+       <li class="choix">[(#GET{datas}|table_valeur{#VALEUR})]</li>\r
+       </BOUCLE_choix>\r
+</ul>\r
+</B_choix>\r
diff --git a/www/plugins/saisies/saisies-vues/date.html b/www/plugins/saisies/saisies-vues/date.html
new file mode 100644 (file)
index 0000000..d0173b9
--- /dev/null
@@ -0,0 +1,10 @@
+#SET{valeur,#ENV{valeur}|vider_date}
+#SET{date_mysql,([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])}
+[(#GET{valeur}|match{#GET{date_mysql}}|oui)
+       [(#ENV{horaire}|?{      
+               #SET{valeur,#ENV{valeur}|affdate{'d/m/Y H:i:s'}}
+               ,
+               #SET{valeur,#ENV{valeur}|affdate{'d/m/Y'}}
+       })]
+]
+[<p class="date">(#GET{valeur})</p>]
diff --git a/www/plugins/saisies/saisies-vues/destinataires.html b/www/plugins/saisies/saisies-vues/destinataires.html
new file mode 100644 (file)
index 0000000..705e459
--- /dev/null
@@ -0,0 +1,7 @@
+<B_destinataires>\r
+<ul>\r
+       <BOUCLE_destinataires(AUTEURS){tous}{id_auteur IN #ENV*{valeur}}>\r
+       <li class="choix">#NOM</li>\r
+       </BOUCLE_destinataires>\r
+</ul>\r
+</B_destinataires>\r
diff --git a/www/plugins/saisies/saisies-vues/explication.html b/www/plugins/saisies/saisies-vues/explication.html
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/www/plugins/saisies/saisies-vues/fieldset.html b/www/plugins/saisies/saisies-vues/fieldset.html
new file mode 100644 (file)
index 0000000..253044e
--- /dev/null
@@ -0,0 +1,5 @@
+[<h3 class="legend">(#ENV{label})</h3>]
+
+[(#ENV{saisies}|is_array|oui)
+       #INCLURE{fond=inclure/voir_saisies, env, from_fieldset='on'}
+]
diff --git a/www/plugins/saisies/saisies-vues/groupe_mots.html b/www/plugins/saisies/saisies-vues/groupe_mots.html
new file mode 100644 (file)
index 0000000..a820b0b
--- /dev/null
@@ -0,0 +1,9 @@
+[(#SET{valeurs,[(#ENV{multiple}|oui|?{#ENV*{valeur},#ARRAY{0,#ENV{valeur}}})]})]
+
+<B_choix>
+<ul>
+       <BOUCLE_choix(GROUPES_MOTS){id_groupe IN #GET{valeurs}}{par titre}>
+       <li class="choix">#TITRE</li>
+       </BOUCLE_choix>
+</ul>
+</B_choix>
diff --git a/www/plugins/saisies/saisies-vues/oui_non.html b/www/plugins/saisies/saisies-vues/oui_non.html
new file mode 100644 (file)
index 0000000..12a6e3e
--- /dev/null
@@ -0,0 +1 @@
+[<p>(#ENV*{valeur}|?{<:item_oui:>,<:item_non:>})</p>]
diff --git a/www/plugins/saisies/saisies-vues/radio.html b/www/plugins/saisies/saisies-vues/radio.html
new file mode 100644 (file)
index 0000000..b3c9c55
--- /dev/null
@@ -0,0 +1,4 @@
+[(#REM) datas peut être une chaine qu'on sait décomposer ]\r
+#SET{datas, #ENV{datas}|saisies_chaine2tableau}\r
+\r
+[<p>(#GET{datas}|table_valeur{#ENV{valeur}})</p>]\r
diff --git a/www/plugins/saisies/saisies-vues/secteur.html b/www/plugins/saisies/saisies-vues/secteur.html
new file mode 100644 (file)
index 0000000..626572c
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM) valeur peut être une chaine qu'on sait décomposer ]\r
+#SET{valeur, #ENV{valeur}|saisies_chaine2tableau}\r
+\r
+<B_choix>\r
+<ul>\r
+       <BOUCLE_choix(RUBRIQUES){id_rubrique IN #GET*{valeur}}>\r
+       <li class="choix">#TITRE</li>\r
+       </BOUCLE_choix>\r
+</ul>\r
+</B_choix>\r
diff --git a/www/plugins/saisies/saisies-vues/selecteur.html b/www/plugins/saisies/saisies-vues/selecteur.html
new file mode 100644 (file)
index 0000000..419acb6
--- /dev/null
@@ -0,0 +1,30 @@
+[(#REM) 
+         
+  ### /!\ selecteur (spip Bonux) ###
+         Attention, ce qui est retourne est un tableau :
+         _request($name) = array('rubrique|3', 'rubrique|9', 'rubrique|10');
+         Une fonction de SPIP Bonux permet de récupérer un tableau d'identifiants par type d'objet :
+         [(#CHAMP|picker_selected{article})]
+         Cette fonction peut etre pratique dans une boucle en utilisant le critere IN
+         
+]
+
+
+[(#SET{selection,#VALEUR|picker_selected_par_objet})]
+
+<BOUCLE_au_moins_un(CONDITION){si #GET{selection}}>
+       <BOUCLE_un(DATA){source table,#GET{selection}}{si (#GET{selection}|count|=={1})}>
+               <p>
+                       [(#OBJET|objet_info{texte_objet}|_T)] #ID_OBJET&nbsp;: #INFO_TITRE{#OBJET,#ID_OBJET}
+               </p>
+       </BOUCLE_un>
+       <B_plusieurs>
+               <ul>
+       <BOUCLE_plusieurs(DATA){source table,#GET{selection}}{si (#GET{selection}|count|>{1})}>
+                       <li class="choix">
+                               [(#OBJET|objet_info{texte_objet}|_T)] #ID_OBJET&nbsp;: #INFO_TITRE{#OBJET,#ID_OBJET}
+                       </li>
+       </BOUCLE_plusieurs>
+               </ul>
+       </B_plusieurs>
+</BOUCLE_au_moins_un>
diff --git a/www/plugins/saisies/saisies-vues/selecteur_article.html b/www/plugins/saisies/saisies-vues/selecteur_article.html
new file mode 100644 (file)
index 0000000..d7341bb
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM) \r
+         \r
+  ### /!\ selecteur (spip Bonux) ###\r
+         Attention, ce qui est retourne est un tableau :\r
+         _request($name) = array('article|3', 'article|9', 'article|10');\r
+         Une fonction de SPIP Bonux permet de récupérer un tableau d'identifiants par type d'objet :\r
+         [(#CHAMP|picker_selected{article})]\r
+         Cette fonction peut etre pratique dans une boucle en utilisant le critere IN\r
+         \r
+]\r
+<BOUCLE_test_multiple(CONDITION){si #ENV{multiple}|=={on}|oui}>\r
+       <B_articles_selectionnes>\r
+       <ul>\r
+       <BOUCLE_articles_selectionnes(ARTICLES){id_article IN #ENV*{valeur}|picker_selected{article}}>\r
+               <li class="choix">#TITRE (<:article:> #ID_ARTICLE) - #STATUT</li>\r
+       </BOUCLE_articles_selectionnes>\r
+       </ul>\r
+       </B_articles_selectionnes>\r
+</BOUCLE_test_multiple>\r
+       <BOUCLE_article_selectionne(ARTICLES){id_article IN #ENV*{valeur}|picker_selected{article}}>\r
+               <p>#TITRE (<:article:> #ID_ARTICLE) - #STATUT</p>\r
+       </BOUCLE_article_selectionne>\r
+<//B_test_multiple>\r
diff --git a/www/plugins/saisies/saisies-vues/selecteur_article_fonctions.php b/www/plugins/saisies/saisies-vues/selecteur_article_fonctions.php
new file mode 100644 (file)
index 0000000..ba76acb
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+
+include_spip('prive/formulaires/selecteur/selecteur_fonctions');
+
+?>
diff --git a/www/plugins/saisies/saisies-vues/selecteur_document.html b/www/plugins/saisies/saisies-vues/selecteur_document.html
new file mode 100644 (file)
index 0000000..1e4ba7d
--- /dev/null
@@ -0,0 +1,3 @@
+<BOUCLE_doc(DOCUMENTS){id_document=#ENV{valeur}}>\r
+<p>#ID_DOCUMENT - #TITRE (#TYPE_DOCUMENT [(#TAILLE|taille_en_octets)])</p>\r
+</BOUCLE_doc>\r
diff --git a/www/plugins/saisies/saisies-vues/selecteur_rubrique.html b/www/plugins/saisies/saisies-vues/selecteur_rubrique.html
new file mode 100644 (file)
index 0000000..2bf9b24
--- /dev/null
@@ -0,0 +1,24 @@
+[(#REM) \r
+         \r
+  ### /!\ selecteur (spip Bonux) ###\r
+         Attention, ce qui est retourne est un tableau :\r
+         _request($name) = array('rubrique|3', 'rubrique|9', 'rubrique|10');\r
+         Une fonction de SPIP Bonux permet de récupérer un tableau d'identifiants par type d'objet :\r
+         [(#CHAMP|picker_selected{article})]\r
+         Cette fonction peut etre pratique dans une boucle en utilisant le critere IN\r
+         \r
+]\r
+\r
+<BOUCLE_test_multiple(CONDITION){si #ENV{multiple}|=={on}|oui}>\r
+       <B_rubriques_selectionnees>\r
+       <ul>\r
+       <BOUCLE_rubriques_selectionnees(RUBRIQUES){tout}{id_rubrique IN #ENV*{valeur}|picker_selected{rubrique}}>\r
+               <li class="choix">#TITRE (<:rubrique:> #ID_RUBRIQUE) - #STATUT</li>\r
+       </BOUCLE_rubriques_selectionnees>\r
+       </ul>\r
+       </B_rubriques_selectionnees>\r
+</BOUCLE_test_multiple>\r
+       <BOUCLE_rubrique_selectionnee(RUBRIQUES){tout}{id_rubrique IN #ENV*{valeur}|picker_selected{rubrique}}>\r
+               <p>#TITRE (<:rubrique:> #ID_RUBRIQUE) - #STATUT</p>\r
+       </BOUCLE_rubrique_selectionnee>\r
+<//B_test_multiple>\r
diff --git a/www/plugins/saisies/saisies-vues/selecteur_rubrique_article.html b/www/plugins/saisies/saisies-vues/selecteur_rubrique_article.html
new file mode 100644 (file)
index 0000000..c4d9724
--- /dev/null
@@ -0,0 +1,38 @@
+[(#REM) \r
+         \r
+  ### /!\ selecteur (spip Bonux) ###\r
+         Attention, ce qui est retourne est un tableau :\r
+         _request($name) = array('article|3', 'article|9', 'rubrique|10');\r
+         Une fonction de SPIP Bonux permet de récupérer un tableau d'identifiants par type d'objet :\r
+         [(#CHAMP|picker_selected{article})]\r
+         Cette fonction peut etre pratique dans une boucle en utilisant le critere IN\r
+         \r
+]\r
+#SET{reponse,""}\r
+\r
+<BOUCLE_test_multiple(CONDITION){si #ENV{multiple}|=={on}|oui}>\r
+       <B_rubriques_selectionnees>\r
+       <ul>\r
+       <BOUCLE_rubriques_selectionnees(RUBRIQUES){tout}{id_rubrique IN #ENV*{valeur}|picker_selected{rubrique}}>\r
+               <li class="choix">#TITRE (<:rubrique:> #ID_RUBRIQUE) - #STATUT</li>\r
+       </BOUCLE_rubriques_selectionnees>\r
+       </ul>\r
+       </B_rubriques_selectionnees>\r
+\r
+       <B_articles_selectionnes>\r
+       <ul>\r
+       <BOUCLE_articles_selectionnes(ARTICLES){id_article IN #ENV*{valeur}|picker_selected{article}}>\r
+               <li class="choix">#TITRE (<:article:> #ID_ARTICLE) - #STATUT</li>\r
+       </BOUCLE_articles_selectionnes>\r
+       </ul>\r
+       </B_articles_selectionnes>\r
+   \r
+</BOUCLE_test_multiple>\r
+       <BOUCLE_rubrique_selectionnee(RUBRIQUES){tout}{id_rubrique IN #ENV*{valeur}|picker_selected{rubrique}}>\r
+               <p>#TITRE (<:rubrique:> #ID_RUBRIQUE) - #STATUT</p>\r
+       </BOUCLE_rubrique_selectionnee>\r
+   \r
+   <BOUCLE_article_selectionne(ARTICLES){id_article IN #ENV*{valeur}|picker_selected{article}}>\r
+               <p>#TITRE (<:article:> #ID_ARTICLE) - #STATUT</p>\r
+       </BOUCLE_article_selectionne>\r
+<//B_test_multiple>\r
diff --git a/www/plugins/saisies/saisies-vues/selecteur_site.html b/www/plugins/saisies/saisies-vues/selecteur_site.html
new file mode 100644 (file)
index 0000000..1c5eca6
--- /dev/null
@@ -0,0 +1,13 @@
+<BOUCLE_test_multiple(CONDITION){si #ENV{multiple}|oui}>\r
+       <B_sites_selectionnes>\r
+       <ul>\r
+       <BOUCLE_sites_selectionnes(SITES){id_syndic IN #ENV*{valeur}}>\r
+               <li class="choix">#NOM SITE (#ID_SYNDIC)</li>\r
+       </BOUCLE_sites_selectionnes>\r
+       </ul>\r
+       </B_sites_selectionnes>\r
+</BOUCLE_test_multiple>\r
+       <BOUCLE_site_selectionne(SITES){id_syndic=#ENV{valeur}}>\r
+               <p>#NOM_SITE (#ID_SYNDIC)</p>\r
+       </BOUCLE_site_selectionne>\r
+<//B_test_multiple>\r
diff --git a/www/plugins/saisies/saisies-vues/selection.html b/www/plugins/saisies/saisies-vues/selection.html
new file mode 100644 (file)
index 0000000..b3c9c55
--- /dev/null
@@ -0,0 +1,4 @@
+[(#REM) datas peut être une chaine qu'on sait décomposer ]\r
+#SET{datas, #ENV{datas}|saisies_chaine2tableau}\r
+\r
+[<p>(#GET{datas}|table_valeur{#ENV{valeur}})</p>]\r
diff --git a/www/plugins/saisies/saisies-vues/selection_multiple.html b/www/plugins/saisies/saisies-vues/selection_multiple.html
new file mode 100644 (file)
index 0000000..2925716
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM) datas peut être une chaine qu'on sait décomposer ]\r
+#SET{datas, #ENV{datas}|saisies_chaine2tableau}\r
+#SET{valeur, #ENV*{valeur}|saisies_valeur2tableau}\r
+<B_choix>\r
+<ul>\r
+       <BOUCLE_choix(POUR){tableau #GET{valeur}}>\r
+       <li class="choix">[(#GET{datas}|table_valeur{#VALEUR})]</li>\r
+       </BOUCLE_choix>\r
+</ul>\r
+</B_choix>\r
diff --git a/www/plugins/saisies/saisies.css.html b/www/plugins/saisies/saisies.css.html
new file mode 100644 (file)
index 0000000..1686610
--- /dev/null
@@ -0,0 +1,48 @@
+#CACHE{3600*100,cache-client}\r
+[(#REM)<style>]\r
+#HTTP_HEADER{Content-Type: text/css; charset=iso-8859-15}\r
+#HTTP_HEADER{Vary: Accept-Encoding}\r
+\r
+#SET{left,#LANG_DIR|choixsiegal{ltr,left,right}}\r
+#SET{right,#LANG_DIR|choixsiegal{ltr,right,left}}\r
+#SET{fleche,#LANG_DIR|choixsiegal{ltr,#CHEMIN{images/deplierhaut.gif},#CHEMIN{images/deplierhaut_rtl.gif}}}\r
+\r
+/* Dans l'espace privé, afficher les labels des vues de Saisies */\r
+#wysiwyg .afficher .label{ display:block; }\r
+\r
+li.fieldset.pliable > fieldset > .legend{\r
+       cursor:pointer;\r
+}\r
+\r
+li.fieldset.pliable > fieldset > .legend span{\r
+       padding-#GET{left}:15px;\r
+       background:transparent url(#CHEMIN{images/deplierbas.gif}) [(#GET{left}) ]center no-repeat;\r
+}\r
+\r
+li.fieldset.plie > fieldset > .legend span{\r
+       background-image:url(#GET{fleche});\r
+}\r
+/*[(#REM) date triple champs...\r
+       jour    mois    annee\r
+       /12/    /10/    /2010/\r
+]*/\r
+.saisie_date_jour_mois_annee .choix {float:left;}\r
+.saisie_date_jour_mois_annee .choix+.choix {margin-left:1em;}\r
+.saisie_date_jour_mois_annee .choix label{display:block; width:auto;}\r
+.saisie_date_jour_mois_annee .choix .text{width:auto;}\r
+\r
+/*[(#REM) Styles prives de bonux pour la mise en forme du selecteur d'article et/ou de rubrique si bonux disponible]*/\r
+[(#CHEMIN{prive/style_prive_plugin_bonux.html}|oui) \r
+  [(#INCLURE{fond=prive/style_prive_plugin_bonux,ltr=#LANG_LEFT})]\r
+]\r
+\r
+/*[(#REM) On ecrase le style de bonux qui met tous les labels a droite (ou gauche).\r
+        Sinon le p.explication du selecteur ne va pas a la ligne ]*/\r
+.formulaire_spip li.selecteur_item > label {\r
+       float:none;\r
+}\r
+\r
+.formulaire_spip li.selecteur_item div.choix label {\r
+       float:none;\r
+   display:inline;\r
+}\r
diff --git a/www/plugins/saisies/saisies/_base.html b/www/plugins/saisies/saisies/_base.html
new file mode 100644 (file)
index 0000000..e8ab81d
--- /dev/null
@@ -0,0 +1,54 @@
+[(#REM) \r
+\r
+  Parametres :\r
+  ** : obligatoire\r
+  * : fortement conseille\r
+  \r
+  - ** nom : nom du parametre\r
+  - * label : nom joli\r
+  (- * erreurs : tableau des erreurs) (transmis par defaut avec SAISIE)\r
+  (- * valeur : valeur actuelle du parametre) (transmis par defaut avec SAISIE : valeur=#ENV{nom du parametre}})\r
+  - defaut : valeur par defaut du parametre\r
+  - obligatoire : est-ce un parametre obligatoire ? (defaut: non, valeurs : null/"non"/autre=oui )\r
+  - info_obligatoire : si obligatoire, ajoute ce contenu apres le label (defaut : "")\r
+  - explication : texte d'explication suppplementaire\r
+  - attention : texte pour les cas graves !\r
+  - disable : est-ce que le champ est desactive ? (pas de saisie possible, selection impossible, contenus non postes)\r
+              (defaut: non, valeurs : null/"non"/autre=oui ) n'est peut etre pas valable pour toutes les saisies.\r
+  - disable_avec_post : idem disable, mais en envoyant en hidden le champ tout de meme.\r
+  - readonly : est-ce que le champ est non modifiable ? (pas de saisie possible, selection possible, contenus postes)\r
+              (defaut: non, valeurs : null/"non"/autre=oui ) n'est peut etre pas valable pour toutes les saisies.\r
+\r
+  \r
+  Exemples d'appels :\r
+    [(#SAISIE{input, couleur_foncee,\r
+               label=<:spa:couleur_foncee:>,\r
+               obligatoire=oui})]\r
+\r
+]\r
+\r
+[(#ENV{nom}|oui)\r
+       #SET{obligatoire,#ENV{obligatoire}|et{#ENV{obligatoire}|!={non}}|?{obligatoire,''}}\r
+       #SET{disable,#ENV{disable,#ENV{disable_avec_post}}|et{#ENV{disable,#ENV{disable_avec_post}}|!={non}}|?{#ENV{disable}|is_array|?{#ENV{disable,#ARRAY},disabled},''}}\r
+       #SET{readonly,#ENV{readonly}|et{#ENV{readonly}!={non}}|?{readonly,''}}\r
+       #SET{saisies_autonomes,#VAL|saisies_autonomes}\r
+       \r
+       [(#ENV{type_saisie}|in_array{#GET{saisies_autonomes}}|oui)\r
+               [(#INCLURE{fond=saisies/#ENV{type_saisie},env,obligatoire=#GET{obligatoire},disable=#GET{disable},readonly=#GET{readonly}})]\r
+       ]\r
+       [(#ENV{type_saisie}|in_array{#GET{saisies_autonomes}}|non)\r
+               #SET{erreurs,#ENV**{erreurs}|table_valeur{#ENV{nom}}}\r
+               #SET{li_class,#ENV{type_saisie}|substr{0,9}|=={selecteur}|?{selecteur_item,''}}\r
+               <!--!inserer_saisie_editer-->\r
+               <li class="editer editer_[(#ENV{nom}|saisie_nom2classe)][ (#GET{obligatoire})][ (#GET{erreurs}|oui)erreur][ (#GET{li_class})][ (#ENV{li_class})][ saisie_(#ENV{type_saisie})]"[ data-id="(#ENV{id_saisie})"]>\r
+                       #ENV*{inserer_debut}\r
+                       [<label[(#ENV{type_saisie}|match{oui_non|radio|checkbox}|non) for="champ_#ENV{nom}"]>(#ENV*{label})[<span class='obligatoire'>(#GET{obligatoire}|oui)[(#ENV*{info_obligatoire}|is_null|?{<:info_obligatoire_02:>,#ENV*{info_obligatoire}})]</span>]</label>]\r
+                       [<span class='erreur_message'>(#GET{erreurs})</span>]\r
+                       [<p class='explication'>(#ENV*{explication})</p>]\r
+                       [<em class='attention'>(#ENV*{attention})</em>]\r
+                       [(#INCLURE{fond=saisies/#ENV{type_saisie},env,nom=[(#ENV{nom}|saisie_nom2name)], disable=#GET{disable},readonly=#GET{readonly}})]\r
+                       [(#ENV{disable_avec_post}|et{#ENV{disable_avec_post}|!={non}}|oui)<input type='hidden' name='[(#ENV{nom}|saisie_nom2name)]' value="#ENV{valeur,#ENV{defaut}}" />]\r
+                       #ENV**{inserer_fin}\r
+               </li>\r
+       ]\r
+]\r
diff --git a/www/plugins/saisies/saisies/articles_originaux.html b/www/plugins/saisies/saisies/articles_originaux.html
new file mode 100644 (file)
index 0000000..bf38d6e
--- /dev/null
@@ -0,0 +1,51 @@
+[(#REM)\r
+\r
+Saisies qui liste les articles originaux (origine_traduction) du site\r
+Par défaut ne liste que ceux des rubriques à la racine (secteurs)\r
+\r
+  Parametres :\r
+  - class : classe(s) css ajoutes au select\r
+  - multiple : si quelquechose est passe, le select est multiple, sinon, c'est un select simple\r
+       Dans le cas multiple, defaut et valeur doivent etre un array, sinon un int\r
+  - recursif : si oui liste les articles des rubriques de facon recursive, et pas uniquement les secteurs\r
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")\r
+    (seulement si non multiple)\r
+  - cacher_option_intro : pas de premier option vide  (defaut:"")\r
+  - defaut : valeur par defaut si pas présente dans l'environnement\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+\r
+  Exemple d'appel :\r
+       [(#SAISIE{articles_originaux,articles,\r
+               label=<:plugin:label_articles:>,\r
+               multiple=oui})]\r
+]\r
+<select name="#ENV{nom}[(#ENV{multiple}|?{[(#VAL{&#91;&#93;}|html_entity_decode)]})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][(#ENV{multiple}|oui) multiple="multiple" size="#ENV{size,10}"][ (#ENV*{attributs})]>\r
+       [(#ENV{cacher_option_intro}|ou{#ENV{multiple}}|non)\r
+               <option value="0">[(#ENV{option_intro})]</option>]\r
+               <BOUCLE_articles_originaux_racine(ARTICLES){id_rubrique}{origine_traduction}>\r
+               [(#ENV{multiple}|oui)\r
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]>#TITRE</option>]\r
+               [(#ENV{multiple}|non)\r
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#TITRE</option>]\r
+               </BOUCLE_articles_originaux_racine>\r
+       <BOUCLE_articles_page(ARTICLES){id_secteur<1}{origine_traduction}>\r
+       [(#ENV{multiple}|oui)\r
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]>#TITRE</option>]\r
+               [(#ENV{multiple}|non)\r
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#TITRE</option>]\r
+       </BOUCLE_articles_page>\r
+       <BOUCLE_secteurs(RUBRIQUES){id_parent = #ENV{id_rubrique,0}}{par num titre, titre}{tout}>\r
+       <optgroup label="#TITRE">\r
+               <B_articles_originaux>\r
+               <BOUCLE_articles_originaux(ARTICLES){id_rubrique}{origine_traduction}>\r
+               [(#ENV{multiple}|oui)\r
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]>#TITRE</option>]\r
+               [(#ENV{multiple}|non)\r
+               <option value="#ID_ARTICLE"[(#ID_ARTICLE|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#TITRE</option>]\r
+               </BOUCLE_articles_originaux>\r
+               </B_articles_originaux>\r
+               [(#ENV{recursif}|oui)\r
+               <INCLURE{fond=prive/listes/articles_originaux_recursifs,valeur=#ENV{valeur_forcee,#ENV{valeur}},id_rubrique,multiple} />]\r
+       </optgroup>             \r
+       </BOUCLE_secteurs>\r
+</select>\r
diff --git a/www/plugins/saisies/saisies/auteurs.html b/www/plugins/saisies/saisies/auteurs.html
new file mode 100644 (file)
index 0000000..759b97c
--- /dev/null
@@ -0,0 +1,43 @@
+[(#REM)\r
+\r
+       Todo:\r
+                       Faire fonctionner les images de statut avec SPIP 3...\r
+                       Elles sont dans [(#CHEMIN_IMAGE{auteur-1comite-16.png})]\r
+       \r
+  Parametres :\r
+  - class : classe(s) css ajoutes au select\r
+  - multiple : si quelquechose est passe, le select est multiple, sinon, c'est un select simple\r
+       Dans le cas multiple, defaut et valeur doivent etre un array, sinon un int\r
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")\r
+    (seulement si non multiple)\r
+  - option_statut: si quelque chose est passe on insere un bonhomme de statut a cote du nom, sinon rien\r
+    (defaut = rien)\r
+  - cacher_option_intro : pas de premier option vide  (defaut:"")\r
+  - defaut : valeur par defaut si pas présente dans l'environnement\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+  - webmestre : si oui, ne selectionne que les webmestres\r
+  \r
+  Exemple d'appel :\r
+       [(#SAISIE{auteurs,auteurs_site,\r
+               label=<:plugin:auteurs_du_site:>,\r
+               multiple=oui\r
+               statut=0minirezo})]\r
+]\r
+#SET{bonhomme_statut,#ARRAY}\r
+[(#ENV{option_statut}|oui)\r
+       #SET{bonhomme_statut, #ARRAY{0minirezo, admin-12.gif, 1comite, redac-12.gif, 6forum, visit-12.gif}}\r
+]\r
+[(#ENV{multiple}|oui)\r
+       [(#SET{valeur,[(#ENV*{valeur}|is_array|?{[(#ENV*{valeur})],[(#ENV*{valeur}|explode{','})]})]})]\r
+]\r
+<select name="#ENV{nom}[(#ENV{multiple}|?{[(#VAL{&#91;&#93;}|html_entity_decode)]})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][(#ENV{multiple}|oui) multiple="multiple" size="#ENV{size,10}"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>\r
+       [(#ENV{cacher_option_intro}|ou{#ENV{multiple}}|non)\r
+               <option value="">[(#ENV{option_intro})]</option>]\r
+       <BOUCLE_auteurs(AUTEURS){par num nom, nom}{statut ?}{statut != 5poubelle}{webmestre ?}{tout}>\r
+               #SET{image_statut, #GET{bonhomme_statut}|table_valeur{#STATUT}}\r
+               [(#ENV{multiple}|oui)\r
+               <option value="#ID_AUTEUR"[(#ID_AUTEUR|in_array{#ENV{valeur_forcee,#GET{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"][(#GET{image_statut}|oui)[style="background:url((#CHEMIN{prive/images/#GET{image_statut}})) no-repeat left; padding-left: 20px;"]]>#NOM</option>]\r
+               [(#ENV{multiple}|non)\r
+               <option value="#ID_AUTEUR"[(#ID_AUTEUR|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"][(#GET{image_statut}|oui)[style="background:url((#CHEMIN{prive/images/#GET{image_statut}})) no-repeat left; padding-left: 20px;"]]>#NOM</option>]\r
+       </BOUCLE_auteurs>\r
+</select>\r
diff --git a/www/plugins/saisies/saisies/auteurs.yaml b/www/plugins/saisies/saisies/auteurs.yaml
new file mode 100644 (file)
index 0000000..7438f14
--- /dev/null
@@ -0,0 +1,122 @@
+
+titre: '<:saisies:saisie_auteurs_titre:>'
+description: '<:saisies:saisie_auteurs_explication:>'
+icone: 'images/saisies_auteurs.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'multiple'
+          label: '<:saisies:option_multiple_label:>'
+          explication: '<:saisies:option_multiple_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'option_statut'
+          label: '<:saisies:option_option_statut_label:>'      
+      -
+        saisie: 'input'
+        options:
+          nom: 'option_intro'
+          label: '<:saisies:option_option_intro_label:>'
+          size: 50
+      -
+        saisie: 'case'
+        options:
+          nom: 'cacher_option_intro'
+          label_case: '<:saisies:option_cacher_option_intro_label:>'
+          defaut: 'on'
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'size'
+          label: '<:saisies:option_size_label:>'
+          explication: '<:saisies:option_size_explication:>'
+        verifier:
+          type: 'entier'
+          options:
+            min: 1
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'obligatoire'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_auteurs_titre:>'
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/case.html b/www/plugins/saisies/saisies/case.html
new file mode 100644 (file)
index 0000000..5411e12
--- /dev/null
@@ -0,0 +1,20 @@
+[(#REM) 
+
+  Action :
+    - Rempli "on" si oui, "" si non.
+  
+  Parametres :
+    - label_case : pour un label a cote de la case (defaut:"")
+       - defaut : valeur par defaut si pas présente dans l'environnement
+    - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{case, afficher_liste,
+               label=<:plugin:afficher_liste:>,
+               label_case=<:plugin:activer:>,
+               explication=<:plugin:explication_afficher_liste:>})]
+]#SET{valeur,#ENV{valeur_forcee,#ENV{valeur}}|is_null|?{#ENV{defaut},#ENV{valeur_forcee,#ENV{valeur}}}}
+<div class="choix">
+       <input type="checkbox" name="#ENV{nom}" class="checkbox" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ (#GET{valeur}|=={#ENV{valeur_oui,on}}|oui)checked="checked"] value="#ENV{valeur_oui,on}" [ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][ (#ENV*{attributs})]/>
+       [<label for="champ_[(#ENV{nom}|saisie_nom2classe)]">[(#GET{valeur}|=={#ENV{valeur_oui,on}}|oui)<strong>](#ENV*{label_case})[(#GET{valeur}|=={#ENV{valeur_oui,on}}|oui)</strong>]</label>]
+</div>
diff --git a/www/plugins/saisies/saisies/case.yaml b/www/plugins/saisies/saisies/case.yaml
new file mode 100644 (file)
index 0000000..13af035
--- /dev/null
@@ -0,0 +1,102 @@
+
+titre: '<:saisies:saisie_case_titre:>'
+description: '<:saisies:saisie_case_explication:>'
+icone: 'images/saisies_case.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'label_case'
+          label: '<:saisies:option_label_case_label:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'readonly'
+          label: '<:saisies:option_readonly_label:>'
+          explication: '<:saisies:option_readonly_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'obligatoire'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_case_titre:>'
+    label_case: '<:saisies:saisie_case_titre:>'
+    # champs extras (definition du champ sql)
+    sql: "varchar(3) DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/checkbox.html b/www/plugins/saisies/saisies/checkbox.html
new file mode 100644 (file)
index 0000000..d8df21e
--- /dev/null
@@ -0,0 +1,52 @@
+[(#REM) 
+
+  ### /!\ boucle POUR (spip Bonux) ###
+  
+  Parametres :
+  - datas : tableau de donnees cle=>valeur
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{checkbox, criteres,
+               label=<:plugin:choisir_criteres:>,
+               defaut=#ARRAY{0,cle1,1,cle3}, 
+               defaut=cle2,
+               datas=#ARRAY{
+                       cle1,valeur1,
+                       cle2,valeur2,
+                       cle3,valeur3}})]
+]
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV*{datas}|saisies_chaine2tableau}
+
+[(#REM) defaut peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
+#SET{defaut, #ENV{defaut}|saisies_chaine2tableau}
+
+[(#REM) valeur doit être un tableau ! ]
+#SET{valeur, #ENV{valeur}|saisies_valeur2tableau}
+
+
+[(#REM) lorsque qu'on donne un 'disabled' qui est une chaine,
+       il faut la transformer en tableau. Ce tableau est vide si la chaine valait ''
+       sinon une clé 0 serait considérée disabled à tord
+]
+#SET{disabled,#ENV{disable}}
+[(#GET{disabled}|is_string|oui)
+       [(#GET{disabled}|strlen|non) #SET{disabled,#ARRAY} ]
+       [(#GET{disabled}|oui) #SET{disabled,#ARRAY|push{#GET{disabled}}} ]
+]
+[(#ENV{tout_selectionner}|oui)
+       <div class="[(#ENV{choix,choix})] none-nojs">
+               <input type="checkbox" name="#ENV{nom}_tout" class="checkbox" id="champ_[(#ENV{nom}|saisie_nom2classe)]_tout" value="on" onChange="if (jQuery(this).attr('checked')=='checked') jQuery(this).parent('div').parent().find('input').attr('checked','checked'); else jQuery(this).parent('div').parent().find('input').removeAttr('checked');"/>
+               <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_tout"><:saisies:tout_selectionner:></label>
+       </div>
+]
+
+<BOUCLE_checkbox(POUR){tableau #GET{datas}}>
+<div class="#ENV{choix,choix}[ (#ENV{choix,choix})_#CLE]">
+       <input type="checkbox" name="#ENV{nom}[]" class="checkbox" id="champ_[(#ENV{nom}|saisie_nom2classe)]_#COMPTEUR_BOUCLE"[ (#CLE|in_array{#ENV{valeur_forcee,#GET{valeur,#GET{defaut}}}}|oui)checked="checked"] value="#CLE"[(#CLE|in_array{#GET{disabled}}|oui) disabled="disabled"][ (#ENV*{attributs})] />
+       <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_#COMPTEUR_BOUCLE">[(#CLE|in_array{#ENV{valeur_forcee,#GET{valeur,#GET{defaut}}}}|oui)<strong>]#VALEUR[(#CLE|in_array{#ENV{valeur_forcee,#GET{valeur,#GET{defaut}}}}|oui)</strong>]</label>
+</div>
+</BOUCLE_checkbox>
diff --git a/www/plugins/saisies/saisies/checkbox.yaml b/www/plugins/saisies/saisies/checkbox.yaml
new file mode 100644 (file)
index 0000000..0be055d
--- /dev/null
@@ -0,0 +1,109 @@
+
+titre: '<:saisies:saisie_checkbox_titre:>'
+description: '<:saisies:saisie_checkbox_explication:>'
+icone: 'images/saisies_checkbox.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'datas'
+          label: '<:saisies:option_datas_label:>'
+          explication: '<:saisies:option_datas_explication:>'
+          rows: 10
+          cols: 50
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+          rows: 10
+          cols: 50
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'readonly'
+          label: '<:saisies:option_readonly_label:>'
+          explication: '<:saisies:option_readonly_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'obligatoire'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_checkbox_titre:>'
+    datas:
+      choix1: '<:saisies:saisie_radio_defaut_choix1:>'
+      choix2: '<:saisies:saisie_radio_defaut_choix2:>'
+      choix3: '<:saisies:saisie_radio_defaut_choix3:>'
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/choisir_objet.html b/www/plugins/saisies/saisies/choisir_objet.html
new file mode 100644 (file)
index 0000000..d773e69
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM)
+       Saisie spécifique à SPIP 3
+       qui permet de choisir un objet parmis les
+       objets éditoriaux éditables de SPIP,
+       les affichant dans un sélecteur
+
+
+  Exemple d'appel :
+       [(#SAISIE{choisir_objet, mon_objet,
+               label=<:plugin:quel_objet:>})]
+
+]
+
+[(#REM) Attention, la valeur ou la valeur forcée peut être une chaine vide. On doit donc tester avec is_null. ]
+#SET{valeur,#ENV{valeur_forcee}|is_null|?{#ENV{valeur}|is_null|?{#ENV{defaut},#ENV{valeur}},#ENV{valeur_forcee}}}
+
+<select name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ size="(#ENV{size})"][ (#ENV*{attributs})]>
+       [(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_objets(POUR){tableau #REM|lister_tables_objets_sql}{cle !IN #ENV{exclus,''}}>[(#VALEUR{editable}|oui)
+       <option value="#CLE"[(#CLE|=={#GET{valeur}}|oui)selected="selected"]>[(#VALEUR{texte_objets}|_T)]</option>
+]</BOUCLE_objets>
+</select>
+
diff --git a/www/plugins/saisies/saisies/choisir_objets.html b/www/plugins/saisies/saisies/choisir_objets.html
new file mode 100644 (file)
index 0000000..5caa781
--- /dev/null
@@ -0,0 +1,21 @@
+[(#REM)
+       Saisie spécifique à SPIP 3
+       qui permet de choisir parmis des
+       objets éditoriaux éditables de SPIP,
+       les affichant avec des checkbox
+
+
+  Exemple d'appel :
+       [(#SAISIE{choisir_objets, gis_objets,
+               label=<:gis:cfg_lbl_activer_objets:>,
+               exclus=spip_gis})]
+
+]
+
+[(#REM) defaut peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
+#SET{defaut, #ENV{defaut}|saisies_chaine2tableau}
+
+[(#REM) valeur doit être un tableau ! ]
+#SET{valeur, #ENV{valeur}|saisies_valeur2tableau}
+
+#INCLURE{fond=formulaires/inc-choisir-objets,name=#ENV{nom},selected=#GET{valeur},exclus=#ENV{exclus}}
diff --git a/www/plugins/saisies/saisies/couleur.html b/www/plugins/saisies/saisies/couleur.html
new file mode 100644 (file)
index 0000000..40b4d2d
--- /dev/null
@@ -0,0 +1,12 @@
+[(#REM)\r
+\r
+    ### /!\ En Couleur si plugin Palette ###\r
+       \r
+       Memes parametres que saisies/input, mais redefinit\r
+       size et class.\r
+]\r
+[(#INCLURE{fond=saisies/input,\r
+                       env,\r
+            type=#HTML5|?{color,text},\r
+            size=7,\r
+            class=[(#ENV{readonly}|?{[(#ENV{class}) ]text,[(#ENV{class}) ]palette})]})]\r
diff --git a/www/plugins/saisies/saisies/date.html b/www/plugins/saisies/saisies/date.html
new file mode 100644 (file)
index 0000000..392a817
--- /dev/null
@@ -0,0 +1,65 @@
+[(#REM) \r
+       Zone de saisie de date utilsant le dateur de Bonux si présent.\r
+       Sur les sites en HTML5, utilise type="date"\r
+       sur le input, et type="text" par défaut pour les autres.\r
+       Pour tous on utilise class="date" et class="heure" pour activer le dateur.\r
+       \r
+       La valeur fournie peut être :\r
+       - au format spip jj/mm/aaaa (date uniquement)\r
+       - au format SQL aaaa-mm-jj (date uniquement)\r
+       - au format SQL aaaa-mm-jj hh:mm:ss (date et heure)\r
+       - un tableau avec une entrée "date" et une entrée "heure" séparée, au format SQL (date et heure obligatoire)\r
+       \r
+       Pour utiliser les heures, il faut utiliser l'option "horaire=oui".\r
+       \r
+       La date est proposée à l'affichage au format jj/mm/aaaa.\r
+]\r
+\r
+[(#REM) Initialisation de la valeur ]\r
+#SET{valeur,#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}\r
+\r
+[(#REM) Regex de date SQL ]\r
+#SET{date_sql,"[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]( [0-9][0-9]:[0-9][0-9]:[0-9][0-9])?"}\r
+\r
+[(#REM) Si la valeur est un tableau, on considère que c'est date et heure dans un format déjà reconnu (j/m/a ou SQL) ]\r
+[(#GET{valeur}|is_array|oui)\r
+       #SET{date, #GET{valeur}|table_valeur{date}}\r
+       #SET{heure, #GET{valeur}|table_valeur{heure}}\r
+]\r
+\r
+[(#REM) Si la valeur est une chaîne, on regarde si SQL ]\r
+[(#GET{valeur}|is_string|oui)\r
+       [(#REM) Par défaut (date uniquement au format SPIP) la date c'est toute la valeur ]\r
+       #SET{date, #GET{valeur}}\r
+       #SET{heure, ''}\r
+       \r
+       [(#REM) Si c'est bien une date SQL ]\r
+       [(#GET{valeur}|match{#GET{date_sql}}|oui)\r
+               [(#REM) Si la date est complètement 0, on met des valeurs vides ]\r
+               [(#GET{valeur}|=={0000-00-00 00:00:00}|oui)\r
+                       #SET{date, ''}\r
+                       #SET{heure, ''}\r
+               ]\r
+               [(#GET{valeur}|=={0000-00-00 00:00:00}|non)\r
+                       #SET{date, #GET{valeur}|affdate{d/m/Y}}\r
+                       #SET{heure, #GET{valeur}|affdate{H:i}}\r
+               ]\r
+       ]\r
+]\r
+\r
+[(#INCLURE{fond=saisies/input,\r
+       env,\r
+       nom=#ENV{nom}[(#ENV{horaire}|?{&#91;date&#93;})],\r
+       valeur=#GET{date},\r
+       type=#HTML5|?{date,text},\r
+       class=[(#ENV{class}) ]date})]\r
+[(#ENV{horaire}|oui)\r
+[(#INCLURE{fond=saisies/input,\r
+       env,\r
+       nom=#ENV{nom}&#91;heure&#93;,\r
+       valeur=#GET{heure},\r
+       size=4,\r
+       maxlength=5,\r
+       class=[(#ENV{class}) ]heure})]\r
+]\r
+[(#ENV{disable}|non|et{#ENV{readonly}|non})[(#INCLURE{fond=formulaires/dateur/inc-dateur, heure_pas=#ENV{heure_pas,30}})]]\r
diff --git a/www/plugins/saisies/saisies/date.yaml b/www/plugins/saisies/saisies/date.yaml
new file mode 100644 (file)
index 0000000..1c7cef4
--- /dev/null
@@ -0,0 +1,132 @@
+\r
+titre: '<:saisies:saisie_date_titre:>'\r
+description: '<:saisies:saisie_date_explication:>'\r
+icone: 'images/saisies_date.png'\r
+options:\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'description'\r
+      label: '<:saisies:option_groupe_description:>'\r
+    saisies:\r
+      -\r
+        saisie: 'case'\r
+        options:\r
+          nom: 'horaire'\r
+          label: '<:saisies:option_horaire_label:>'\r
+          label_case: '<:saisies:option_horaire_label_case:>'\r
+          valeur_oui: 'oui'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'label'\r
+          label: '<:saisies:option_label_label:>'\r
+          explication: '<:saisies:option_label_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'defaut'\r
+          label: '<:saisies:option_defaut_label:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'explication'\r
+          label: '<:saisies:option_explication_label:>'\r
+          explication: '<:saisies:option_explication_explication:>'\r
+          size: 50\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'utilisation'\r
+      label: '<:saisies:option_groupe_utilisation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'selection'\r
+        options:\r
+          nom: 'heure_pas'\r
+          label: '<:saisies:option_heure_pas_label:>'\r
+          explication: '<:saisies:option_heure_pas_explication:>'\r
+          datas:\r
+            1: '1 minute'\r
+            2: '2 minutes'\r
+            5: '5 minutes'\r
+            15: '15 minutes'\r
+            30: '30 minutes'\r
+          defaut: 30\r
+        verifier:\r
+          type: 'entier'\r
+          options:\r
+            min: 1\r
+            max: 30\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable'\r
+          label: '<:saisies:option_disable_label:>'\r
+          explication: '<:saisies:option_disable_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable_avec_post'\r
+          label: '<:saisies:option_disable_avec_post_label:>'\r
+          explication: '<:saisies:option_disable_avec_post_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'readonly'\r
+          label: '<:saisies:option_readonly_label:>'\r
+          explication: '<:saisies:option_readonly_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'affichage'\r
+      label: '<:saisies:option_groupe_affichage:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'attention'\r
+          label: '<:saisies:option_attention_label:>'\r
+          explication: '<:saisies:option_attention_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'info_obligatoire'\r
+          label: '<:saisies:option_info_obligatoire_label:>'\r
+          explication: '<:saisies:option_info_obligatoire_explication:>'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'class'\r
+          label: '<:saisies:option_class_label:>'\r
+          size: 50\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'validation'\r
+      label: '<:saisies:option_groupe_validation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'obligatoire'\r
+          label: '<:saisies:option_obligatoire_label:>'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'erreur_obligatoire'\r
+          label: '<:saisies:option_erreur_obligatoire_label:>'\r
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'\r
+defaut:\r
+  options:\r
+    label: '<:saisies:saisie_date_titre:>'\r
+    size: 40\r
+    # champs extras (definition du champ sql)\r
+    sql: "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL"\r
+  verifier:\r
+    type: 'date'\r
+    options:\r
+      normaliser: 'datetime'\r
diff --git a/www/plugins/saisies/saisies/date_jour_mois_annee.html b/www/plugins/saisies/saisies/date_jour_mois_annee.html
new file mode 100644 (file)
index 0000000..d16e97f
--- /dev/null
@@ -0,0 +1,69 @@
+[(#REM)
+
+       /!\ Cette saisie nécessite du javascript pour fonctionner.
+               En absence de JS, seul un champ de saisie texte est affiché.
+       
+       Cette saisie cree 3 champs a partir d'une date au format datetime mysql.
+       A chaque modification, un champ cache est modifie, contenant la date au format datetime.
+
+       Options :
+       - label_(jour|mois|annee)
+       - size_(jour|mois|annee)
+       - maxlength_(jour|mois|annee)
+       
+       [(#SAISIE{date_jour_mois_annee, date_naissance,
+               label=Date de naissance
+       })]
+]
+#SET{valeur,#ENV{valeur,#ENV{defaut}}}
+[(#SET{id,[(#ENV**|md5|substr{0,6})]})]
+<input type='text' name="#ENV{nom}" id="#GET{id}" value="[(#GET{valeur}|sinon{0000-00-00 00:00:00})]" class='datetime' />
+
+                         
+<script type='text/javascript'>
+function activer_dateur_#GET{id}() {
+       jour = '\
+               <div class="choix">\
+                       [<label for="champ_#ENV{nom}_jour">(#ENV{label_jour,<:saisies:label_jour:>})</label>]\
+                       <input type="text" name="#ENV{nom}_jour" class="text date_jour[ (#ENV{class})]" id="champ_#ENV{nom}_jour"[ value="(#GET{valeur}|journum)"][ size="(#ENV{size_jour, 2})"][ maxlength="(#ENV{maxlength_jour, 2})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][(#ENV{obligatoire}|et{#HTML5}|oui) required="required"] onChange="changer_la_date(this);" />\
+               </div>\
+       ';
+               
+       mois = '\
+               <div class="choix">\
+                       [<label for="champ_#ENV{nom}_mois">(#ENV{label_mois,<:saisies:label_mois:>})</label>]\
+                       <input type="text" name="#ENV{nom}_mois" class="text date_mois[ (#ENV{class})]" id="champ_#ENV{nom}_mois"[ value="(#GET{valeur}|mois)"][ size="(#ENV{size_mois, 2})"][ maxlength="(#ENV{maxlength_mois, 2})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][(#ENV{obligatoire}|et{#HTML5}|oui) required="required"] onChange="changer_la_date(this);" />\
+               </div>\
+       ';
+       
+       annee = '\
+               <div class="choix">\
+                       [<label for="champ_#ENV{nom}_annee">(#ENV{label_annee,<:saisies:label_annee:>})</label>]\
+                       <input type="text" name="#ENV{nom}_annee" class="text date_annee[ (#ENV{class})]" id="champ_#ENV{nom}_annee"[ value="(#GET{valeur}|annee)"][ size="(#ENV{size_annee, 4})"][ maxlength="(#ENV{maxlength_annee, 4})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][(#ENV{obligatoire}|et{#HTML5}|oui) required="required"] onChange="changer_la_date(this);" />\
+               </div>\
+       ';
+
+       if(!$.browser.msie || parseInt($.browser.version) >= 9)
+               jQuery('##GET{id}')[0].type = 'hidden';
+       else
+               jQuery('##GET{id}').css({'height':'0px','width':'0px','border':'none'});
+       jQuery('##GET{id}').after(jour + mois + annee);
+}
+
+function changer_la_date(me) {
+       var li = jQuery(me).parents('li'),
+               jour = jQuery.trim(li.find('.date_jour').val()),
+               mois = jQuery.trim(li.find('.date_mois').val()),
+               annee = jQuery.trim(li.find('.date_annee').val()),
+               date = jQuery.trim(li.find('.datetime').val());
+       while(jour.length < 2) {jour = '0' + jour;}
+       while(mois.length < 2) {mois = '0' + mois;}
+       while(annee.length < 4) {annee = '0' + annee;}
+       date = annee + '-' + mois + '-' + jour + date.substring(10);
+       li.find('.datetime').attr('value',date);
+}
+
+jQuery(document).ready(function(){
+       activer_dateur_#GET{id}();
+});
+</script>
diff --git a/www/plugins/saisies/saisies/destinataires.html b/www/plugins/saisies/saisies/destinataires.html
new file mode 100644 (file)
index 0000000..f8d3900
--- /dev/null
@@ -0,0 +1,63 @@
+#SET{type_choix, #ENV{type_choix,tous}}
+#SET{choix_destinataires, #ENV*{choix_destinataires,#ARRAY}}
+#SET{erreurs,#ENV**{erreurs}|table_valeur{#ENV{nom}}}
+<BOUCLE_choix(CONDITION){si #GET{choix_destinataires}|count|<{2}|ou{#GET{type_choix}|=={tous}}}>
+<li class="editer editer_[(#ENV{nom})][ (#ENV{obligatoire})][ (#GET{erreurs}|oui)erreur][ (#ENV{li_class})][ saisie_(#ENV{type_saisie})]" [(#ENV{tout_afficher}|!={oui}|?{style="display:none;"})][ data-id="(#ENV{id_saisie})"]>
+       #ENV*{inserer_debut}
+       [<label for="champ_#ENV{nom}">(#ENV*{label})[<span class='obligatoire'>(#ENV{obligatoire}|oui)[(#ENV*{info_obligatoire}|is_null|?{<:info_obligatoire_02:>,#ENV*{info_obligatoire}})]</span>]</label>]
+       [<span class='erreur_message'>(#GET{erreurs})</span>]
+       [<p class='explication'>(#ENV*{explication})</p>]
+       [<em class='attention'>(#ENV*{attention})</em>]
+       [(#REM) Si 0 ou 1 destinataire possible ou si c'est tous, le destinataire est défini automatiquement ]
+       <BOUCLE_tous(AUTEURS){tous}{id_auteur IN #GET*{choix_destinataires}}{par num nom,nom}>
+       [(#ENV{tout_afficher}|!={oui}|oui)
+       <input type="hidden" name="#ENV{nom}&#91;&#93;" value="#ID_AUTEUR" />
+       ]
+       [(#ENV{tout_afficher}|!={oui}|non)
+       <div class="choix">
+               <input type="checkbox" name="#ENV{nom}&#91;&#93;" class="checkbox"
+                       readonly="readonly" checked="checked"
+                       id="champ_[(#ENV{nom}|saisie_nom2classe)]_destinataire#ID_AUTEUR"
+                       value="#ID_AUTEUR"[ (#ID_AUTEUR|in_array{#ENV{valeur_forcee,#ENV*{valeur,#ENV*{defaut,#ARRAY}}}}|oui)checked="checked"]
+               />
+               <label for="champ_#ENV{nom}_destinataire#ID_AUTEUR">#NOM</label>
+       </div>
+       ]
+       </BOUCLE_tous>
+       <input [(#ENV{tout_afficher}|!={oui}|?{type="hidden",type="text" readonly="readonly"})] name="#ENV{nom}[]" value="1" />
+       <//B_tous>
+       #ENV*{inserer_fin}
+</li>
+</BOUCLE_choix>
+<li class="editer editer_[(#ENV{nom})][ (#ENV{obligatoire})][ (#GET{erreurs}|oui)erreur][ (#ENV{li_class})][ saisie_(#ENV{type_saisie})]">
+       #ENV*{inserer_debut}
+       [<label[(#GET{type_choix}|=={un}|oui)for="champ_#ENV{nom}"]>(#ENV*{label})[<span class='obligatoire'>(#ENV{obligatoire}|oui)[(#ENV*{info_obligatoire}|is_null|?{<:info_obligatoire_02:>,#ENV*{info_obligatoire}})]</span>]</label>]
+       [<span class='erreur_message'>(#GET{erreurs})</span>]
+       [<p class='explication'>(#ENV*{explication})</p>]
+       [<em class='attention'>(#ENV*{attention})</em>]
+       [(#REM) Sinon on propose le choix, en select ou en checkbox suivant l'option "type_choix" ]
+       <B_destinataires>
+               [(#GET{type_choix}|=={un}|oui)
+                       <select name="#ENV{nom}&#91;&#93;" id="champ_[(#ENV{nom}|saisie_nom2classe)]">
+               ]
+               <BOUCLE_destinataires(AUTEURS){tous}{id_auteur IN #GET*{choix_destinataires}}{par num nom,nom}>
+                       [(#GET{type_choix}|=={plusieurs}|oui)
+                               <div class="choix">
+                                       <input type="checkbox" name="#ENV{nom}&#91;&#93;" class="checkbox"
+                                               id="champ_[(#ENV{nom}|saisie_nom2classe)]_destinataire#ID_AUTEUR"
+                                               value="#ID_AUTEUR"[ (#ID_AUTEUR|in_array{#ENV*{valeur_forcee,#ENV*{valeur,#ENV*{defaut,#ARRAY}}}}|oui)checked="checked"]
+                                       />
+                                       <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_destinataire#ID_AUTEUR">[(#ID_AUTEUR|in_array{#ENV*{valeur_forcee,#ENV*{valeur,#ENV*{defaut,#ARRAY}}}}|oui)<strong>]#NOM[(#ID_AUTEUR|in_array{#ENV*{valeur_forcee,#ENV*{valeur,#ENV*{defaut,#ARRAY}}}}|oui)</strong>]</label>
+                               </div>
+                       ]
+                       [(#GET{type_choix}|=={un}|oui)
+                               <option value="#ID_AUTEUR"[ (#ID_AUTEUR|in_array{#ENV{valeur_forcee,#ENV*{valeur,#ENV*{defaut,#ARRAY}}}}|oui)selected="selected"]>#NOM</option>
+                       ]
+               </BOUCLE_destinataires>
+               [(#GET{type_choix}|=={un}|oui)
+                       </select>
+               ]
+       </B_destinataires>
+       #ENV*{inserer_fin}
+</li>
+<//B_choix>
diff --git a/www/plugins/saisies/saisies/destinataires.yaml b/www/plugins/saisies/saisies/destinataires.yaml
new file mode 100644 (file)
index 0000000..b23103e
--- /dev/null
@@ -0,0 +1,83 @@
+
+titre: '<:saisies:saisie_destinataires_titre:>'
+description: '<:saisies:saisie_destinataires_explication:>'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'auteurs'
+        options:
+          nom: 'choix_destinataires'
+          label: '<:saisies:option_choix_destinataires_label:>'
+          explication: '<:saisies:option_choix_destinataires_explication:>'
+          multiple: 'oui'
+          option_statut: 'oui'
+      -
+        saisie: 'radio'
+        options:
+          nom: 'type_choix'
+          datas:
+            tous: '<:saisies:option_type_choix_tous:>'
+            un: '<:saisies:option_type_choix_un:>'
+            plusieurs: '<:saisies:option_type_choix_plusieurs:>'
+          defaut: 'tous'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'validation'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_destinataires_titre:>'
+    choix_destinataires: [1,2,3,4]
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/email.html b/www/plugins/saisies/saisies/email.html
new file mode 100644 (file)
index 0000000..35109c0
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM) \r
+               \r
+               Zone de saisie d'adresse mail. Sur les sites en HTML5, utilise type="email"\r
+               sur le input, et type="text" par défaut pour les autres.\r
+               Dans ce dernier cas, on renseigne quand même class="email".\r
+               \r
+][(#INCLURE{fond=saisies/input,\r
+                       env,\r
+            type=#HTML5|?{email,text},\r
+            class=[(#HTML5|?{[(#ENV{class}) ],[(#ENV{class}) ]email})]})]\r
diff --git a/www/plugins/saisies/saisies/explication.html b/www/plugins/saisies/saisies/explication.html
new file mode 100644 (file)
index 0000000..868fa0b
--- /dev/null
@@ -0,0 +1,5 @@
+<li class="explication[ explication_(#ENV{nom})][ (#ENV{li_class})][ saisie_(#ENV{type_saisie})]"[ data-id="(#ENV{id_saisie})"]>
+       #ENV*{inserer_debut}
+       [(#ENV*{texte}|propre)]
+       #ENV*{inserer_fin}
+</li>
diff --git a/www/plugins/saisies/saisies/explication.yaml b/www/plugins/saisies/saisies/explication.yaml
new file mode 100644 (file)
index 0000000..64d1e93
--- /dev/null
@@ -0,0 +1,38 @@
+
+titre: '<:saisies:saisie_explication_titre:>'
+description: '<:saisies:saisie_explication_explication:>'
+icone: 'images/saisies_explication.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'texte'
+          label: '<:saisies:saisie_explication_titre:>'
+          explication: '<:saisies:saisie_explication_explication:>'
+          class: 'inserer_barre_edition'
+          cols: 40
+          rows: 5
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'li_class'
+          label: '<:saisies:option_class_label:>'
+          size: 50
+defaut:
+  options:
+    texte: '<:saisies:saisie_explication_titre:>'
+    # champs extras (definition du champ sql)
+    # Non, cette saisie n'a rien à saisir en bdd !
+    # sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/fieldset.html b/www/plugins/saisies/saisies/fieldset.html
new file mode 100644 (file)
index 0000000..83c600a
--- /dev/null
@@ -0,0 +1,34 @@
+#SET{pliable,#ENV{pliable}|et{#ENV{pliable}|!={non}}|?{'pliable', ''}}
+#SET{plie,#ENV{plie}|et{#ENV{plie}|!={non}}|?{'plie', ''}}
+
+[(#REM) S'il y a des erreurs pour au moins un des champs internes, on ne plie pas ! ]
+#SET{champs_internes, #ENV{saisies}|saisies_lister_par_nom}
+#SET{erreurs, #ENV**{erreurs}|sinon{#ARRAY}}
+#SET{erreurs_fieldset, #GET{erreurs}|array_intersect_key{#GET{champs_internes}}}
+[(#GET{erreurs_fieldset}|oui)
+       #SET{plie, ''}
+]
+#SET{erreur_ici,#ENV**{erreurs}|table_valeur{#ENV{nom}}}
+
+<li class="fieldset[ fieldset_(#ENV{nom})][ (#ENV{li_class})][ saisie_(#ENV{type_saisie})][ (#GET{pliable})[ (#GET{plie})]]"[ data-id="(#ENV{id_saisie})"]> 
+       #ENV*{inserer_debut}
+       <fieldset>
+               [[(#GLOBALS{debut_intertitre,<h3>}|inserer_attribut{class,legend})]
+                       [(#ENV{icone}|oui)
+                               [(#REM) en SPIP 3 on cherche avant tout dans le chemin des images
+                               ]#SET{icone,''}[(#SPIP_VERSION|version_compare{2.9, >}|oui)#SET{icone,#CHEMIN_IMAGE{#ENV{icone}}]
+                               [<img src="(#GET{icone}|sinon{#CHEMIN{#ENV{icone}}}
+                                       |image_reduire{#ENV{taille_icone}|sinon{16}}
+                                       |extraire_attribut{src})" alt="#ENV*{label}" /> ]
+                       ]
+                       <span>(#ENV*{label})</span>#GLOBALS{fin_intertitre,</h3>}]
+               [<span class='erreur_message'>(#GET{erreur_ici})</span>]
+               [<p class='explication'>(#ENV*{explication})</p>]
+               [(#ENV{saisies}|is_array|oui)
+               <ul>
+                       #INCLURE{fond=#ENV{fond_generer,"inclure/generer_saisies"}, env, saisies=#ENV{saisies}, from_fieldset='on'}
+               </ul>
+               ]
+       </fieldset>
+       #ENV*{inserer_fin}
+</li>
diff --git a/www/plugins/saisies/saisies/fieldset.yaml b/www/plugins/saisies/saisies/fieldset.yaml
new file mode 100644 (file)
index 0000000..d2f9607
--- /dev/null
@@ -0,0 +1,56 @@
+
+titre: '<:saisies:saisie_fieldset_titre:>'
+description: '<:saisies:saisie_fieldset_explication:>'
+icone: 'images/saisies_fieldset.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'case'
+        options:
+          nom: 'pliable'
+          label: '<:saisies:option_pliable_label:>'
+          label_case: '<:saisies:option_pliable_label_case:>'
+      -
+        saisie: 'case'
+        options:
+          nom: 'plie'
+          label: '<:saisies:option_plie_label:>'
+          label_case: '<:saisies:option_plie_label_case:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'li_class'
+          label: '<:saisies:option_class_label:>'
+          size: 50
+defaut:
+  options:
+    label: '<:saisies:saisie_fieldset_titre:>'
+    # champs extras (definition du champ sql)
+    # Non, cette saisie n'a rien à saisir en bdd !
+    # sql: "text DEFAULT '' NOT NULL"
+  saisies: []
diff --git a/www/plugins/saisies/saisies/groupe_mots.html b/www/plugins/saisies/saisies/groupe_mots.html
new file mode 100644 (file)
index 0000000..f5cb85a
--- /dev/null
@@ -0,0 +1,31 @@
+[(#REM) 
+
+  Parametres :
+  - class : classe(s) css ajoutes au select
+  - multiple : si quelquechose est passe, le select est multiple, sinon, c'est un select simple
+       Dans le cas multiple, defaut et valeur doivent être un array, sinon un int
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+    (seulement si non multiple)
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - table_liaison : permet de ne lister que les groupes de mots liés à une table en particulier
+    (champs tables_liees de spip_groupes_mots)
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  - groupes_exclus : tableau de groupes exclus
+  
+  Exemple d'appel :
+       [(#SAISIE{groupe_mots,groupes,
+               label=<:plugin:secteur_region:>,
+               multiple=oui,
+               table_liaison=articles})] 
+]
+<select name="#ENV{nom}[(#ENV{multiple}|?{[(#VAL{&#91;&#93;}|html_entity_decode)]})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][(#ENV{multiple}|oui) multiple="multiple" size="#ENV{size,10}"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
+       [(#ENV{cacher_option_intro}|ou{#ENV{multiple}}|non)
+               <option value="0">[(#ENV{option_intro})]</option>]
+       <BOUCLE_groupes(GROUPES_MOTS){id_groupe !IN #ENV{groupes_exclus,#ARRAY}}{par num titre, titre}{tables_liees==#VAL{'(^|,)'}|concat{#ENV{table_liaison,.*},'($|,)'}}{tout}>
+               [(#ENV{multiple}|oui)
+               <option value="#ID_GROUPE"[(#ID_GROUPE|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]>#TITRE</option>]
+               [(#ENV{multiple}|non)
+               <option value="#ID_GROUPE"[(#ID_GROUPE|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#TITRE</option>]
+       </BOUCLE_groupes>
+</select>
diff --git a/www/plugins/saisies/saisies/hidden.html b/www/plugins/saisies/saisies/hidden.html
new file mode 100644 (file)
index 0000000..866c70a
--- /dev/null
@@ -0,0 +1,12 @@
+<li class="editer editer_[(#ENV{nom})][ (#ENV{li_class})][ saisie_(#ENV{type_saisie})]" [(#ENV{tout_afficher}|!={oui}|?{style="display:none;"})][ data-id="(#ENV{id_saisie})"]>
+       #ENV*{inserer_debut}
+       [(#ENV{tout_afficher}|!={oui}|oui)
+       <input type="hidden" name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]" value="#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}"[ (#ENV*{attributs})] />
+       ]
+       [(#ENV{tout_afficher}|!={oui}|non)
+       [<label for="champ_[(#ENV{nom}|saisie_nom2classe)]">(#ENV*{label})[<span class='obligatoire'>(#ENV{obligatoire}|oui)[(#ENV*{info_obligatoire}|is_null|?{<:info_obligatoire_02:>,#ENV*{info_obligatoire}})]</span>]</label>]
+       <input type="text" name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]" value="#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}" readonly="readonly" />
+       ]
+       
+       #ENV*{inserer_fin}
+</li>
diff --git a/www/plugins/saisies/saisies/hidden.yaml b/www/plugins/saisies/saisies/hidden.yaml
new file mode 100644 (file)
index 0000000..2120917
--- /dev/null
@@ -0,0 +1,29 @@
+
+titre: '<:saisies:saisie_hidden_titre:>'
+description: '<:saisies:saisie_hidden_explication:>'
+icone: 'images/saisies_hidden.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+          size: 50
+defaut:
+  options:
+    label: '<:saisies:saisie_hidden_titre:>'
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/input.html b/www/plugins/saisies/saisies/input.html
new file mode 100644 (file)
index 0000000..376618d
--- /dev/null
@@ -0,0 +1,48 @@
+[(#REM) \r
+\r
+  Parametres supplementaire :\r
+  - ** datas : tableau de donnees indice=>valeur\r
+  - defaut : valeur par defaut du parametre\r
+  - type : type de l'input (defaut: text)\r
+  - class : classe(s) css ajoutes a l'input\r
+  - size : taille du champ\r
+  - maxlength : nombre de caracteres maximum\r
+  - disable : champ insaisissable ? 'oui' (defaut : '')\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+  - autofocus : indique si le champ prend le focus a l'affichage (HTML5 requis)\r
+  \r
+  Exemple d'appel :\r
+       [(#SAISIE{input,couleur_foncee,\r
+               label=<:spa:couleur_foncee:>,\r
+               size=7,\r
+               datas=#ARRAY{\r
+                               0,valeur0,\r
+                               1,valeur1,\r
+                               2,valeur2}})]\r
+]\r
+\r
+#SET{type,#ENV{type,text}}\r
+\r
+[(#REM) datas peut être une chaine qu'on sait décomposer ]\r
+#SET{datas, #ENV*{datas}}\r
+#SET{datas, #GET{datas}|is_string|?{(#GET{datas}|saisies_chaine2tableau), #GET{datas}}}\r
+\r
+[(#REM) Pas de HTML5, pas de datas]\r
+#SET{datas, #HTML5|?{#GET{datas}}}\r
+\r
+[(#REM)  l'attribut autocomplete ne peut avoir pour valeur que on ou off ]\r
+#SET{val_autocomplete, #ARRAY}\r
+#SET{val_autocomplete, #GET{val_autocomplete}|push{on}}\r
+#SET{val_autocomplete, #GET{val_autocomplete}|push{off}}\r
+\r
+[(#REM) permettre de donner un identifiant de list specifique en option de la saisie\r
+]#SET{list_id,#ENV{list}}\r
+<B_selection>\r
+[(#SET{list_id,[(#GET{list_id,[champ_(#ENV{nom})_datas]})]})]\r
+<datalist id="#GET{list_id}">\r
+<BOUCLE_selection(POUR){tableau #GET{datas}}\r
+>[     <option value="(#VALEUR|attribut_html)"></option>\r
+]</BOUCLE_selection>\r
+</datalist>\r
+</B_selection>\r
+<input type="#GET{type}" name="#ENV{nom}" class="#GET{type}[ (#ENV{class})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ list="(#GET{list_id})"][ value="(#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}})"][ size="(#ENV{size})"][ maxlength="(#ENV{maxlength})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][ placeholder="(#ENV{placeholder})"][(#ENV{obligatoire}|et{#ENV{obligatoire}!={non}}|et{#HTML5}|oui) required="required"][(#ENV{autofocus}|et{#ENV{autofocus}!={non}}|et{#HTML5}|oui) autofocus="autofocus"][(#GET{val_autocomplete}|find{#ENV{autocomplete}}|oui) autocomplete="#ENV{autocomplete}"][ (#ENV*{attributs})] />\r
diff --git a/www/plugins/saisies/saisies/input.yaml b/www/plugins/saisies/saisies/input.yaml
new file mode 100644 (file)
index 0000000..cda5ffd
--- /dev/null
@@ -0,0 +1,144 @@
+\r
+titre: '<:saisies:saisie_input_titre:>'\r
+description: '<:saisies:saisie_input_explication:>'\r
+icone: 'images/saisies_input.png'\r
+options:\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'description'\r
+      label: '<:saisies:option_groupe_description:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'label'\r
+          label: '<:saisies:option_label_label:>'\r
+          explication: '<:saisies:option_label_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'defaut'\r
+          label: '<:saisies:option_defaut_label:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'explication'\r
+          label: '<:saisies:option_explication_label:>'\r
+          explication: '<:saisies:option_explication_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'radio'\r
+        options:\r
+          nom: 'type'\r
+          label: '<:saisies:option_type_label:>'\r
+          explication: '<:saisies:option_type_explication:>'\r
+          datas:\r
+            text: '<:saisies:option_type_text:>'\r
+            password: '<:saisies:option_type_password:>'\r
+          defaut: 'text'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'utilisation'\r
+      label: '<:saisies:option_groupe_utilisation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'maxlength'\r
+          label: '<:saisies:option_maxlength_label:>'\r
+          explication: '<:saisies:option_maxlength_explication:>'\r
+        verifier:\r
+          type: 'entier'\r
+          options:\r
+            min: 1\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable'\r
+          label: '<:saisies:option_disable_label:>'\r
+          explication: '<:saisies:option_disable_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable_avec_post'\r
+          label: '<:saisies:option_disable_avec_post_label:>'\r
+          explication: '<:saisies:option_disable_avec_post_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'readonly'\r
+          label: '<:saisies:option_readonly_label:>'\r
+          explication: '<:saisies:option_readonly_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'affichage'\r
+      label: '<:saisies:option_groupe_affichage:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'attention'\r
+          label: '<:saisies:option_attention_label:>'\r
+          explication: '<:saisies:option_attention_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'info_obligatoire'\r
+          label: '<:saisies:option_info_obligatoire_label:>'\r
+          explication: '<:saisies:option_info_obligatoire_explication:>'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'class'\r
+          label: '<:saisies:option_class_label:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'size'\r
+          label: '<:saisies:option_size_label:>'\r
+          explication: '<:saisies:option_size_explication:>'\r
+        verifier:\r
+          type: 'entier'\r
+          options:\r
+            min: 1\r
+      -\r
+        saisie: 'radio'\r
+        options:\r
+          nom: 'autocomplete'\r
+          label: '<:saisies:option_autocomplete_label:>'\r
+          explication: '<:saisies:option_autocomplete_explication:>' \r
+          datas:\r
+            defaut: '<:saisies:option_autocomplete_defaut:>'\r
+            on: '<:saisies:option_autocomplete_on:>'\r
+            off: '<:saisies:option_autocomplete_off:>'\r
+          defaut: 'defaut'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'validation'\r
+      label: '<:saisies:option_groupe_validation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'obligatoire'\r
+          label: '<:saisies:option_obligatoire_label:>'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'erreur_obligatoire'\r
+          label: '<:saisies:option_erreur_obligatoire_label:>'\r
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'\r
+defaut:\r
+  options:\r
+    label: '<:saisies:saisie_input_titre:>'\r
+    size: 40\r
+    # champs extras (definition du champ sql)\r
+    sql: "text DEFAULT '' NOT NULL"\r
diff --git a/www/plugins/saisies/saisies/mot.html b/www/plugins/saisies/saisies/mot.html
new file mode 100644 (file)
index 0000000..c8b6191
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM) 
+
+  Parametres :
+  - class : classe(s) css ajoutes au select
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - id_groupe : groupe des mots clés à afficher
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{mot, en_region,
+               label=<:plugin:en_region:>})]
+]
+
+<select name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ value="(#ENV{valeur_forcee,#ENV{valeur}})"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
+[(#ENV{cacher_option_intro}|non)
+       <option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_mots(MOTS){par id_groupe, num titre, titre}{id_groupe ?}>
+       [<optgroup label="(#TYPE|unique|attribut_html)" />]
+       <option value="#ID_MOT" [(#ID_MOT|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#TITRE</option>
+</BOUCLE_mots>
+</select>
diff --git a/www/plugins/saisies/saisies/oui_non.html b/www/plugins/saisies/saisies/oui_non.html
new file mode 100644 (file)
index 0000000..8d7281f
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM) 
+
+  Action :
+  - Rempli "on" si oui, "" si non.
+  
+  Parametres :
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{oui_non, afficher_liste,
+               label=<:plugin:afficher_liste:>,
+               explication=<:plugin:explication_afficher_liste:>})]
+]
+#SET{valeur,#ENV{valeur_forcee,#ENV{valeur}}|is_null|?{#ENV{defaut},#ENV{valeur_forcee,#ENV{valeur}}}}
+<div class="choix">
+       <input type="radio" name="#ENV{nom}" class="radio" id="champ_[(#ENV{nom}|saisie_nom2classe)]_oui"[ (#GET{valeur}|=={#ENV{valeur_oui,on}}|oui)checked="checked"] value="#ENV{valeur_oui,on}" [ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"] />
+       <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_oui">[(#GET{valeur}|=={#ENV{valeur_oui,on}}|oui)<strong>]<:item_oui:>[(#GET{valeur}|=={#ENV{valeur_oui,on}}|oui)</strong>]</label>
+</div>
+<div class="choix">
+       <input type="radio" name="#ENV{nom}" class="radio" id="champ_[(#ENV{nom}|saisie_nom2classe)]_non"[ (#GET{valeur}|=={#ENV{valeur_non,''}}|ou{#GET{valeur}|non})checked="checked"] value="#ENV{valeur_non,''}" [ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"] />
+       <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_non">[(#GET{valeur}|=={#ENV{valeur_non,''}}|ou{#GET{valeur}|non})<strong>]<:item_non:>[(#GET{valeur}|=={#ENV{valeur_non,''}}|ou{#GET{valeur}|non})</strong>]</label>
+</div>
diff --git a/www/plugins/saisies/saisies/oui_non.yaml b/www/plugins/saisies/saisies/oui_non.yaml
new file mode 100644 (file)
index 0000000..6f11db1
--- /dev/null
@@ -0,0 +1,95 @@
+
+titre: '<:saisies:saisie_oui_non_titre:>'
+description: '<:saisies:saisie_oui_non_explication:>'
+icone: 'images/saisies_oui_non.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'readonly'
+          label: '<:saisies:option_readonly_label:>'
+          explication: '<:saisies:option_readonly_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'obligatoire'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_oui_non_titre:>'
+    # champs extras (definition du champ sql)
+    sql: "varchar(3) DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/pays.html b/www/plugins/saisies/saisies/pays.html
new file mode 100644 (file)
index 0000000..e5d2976
--- /dev/null
@@ -0,0 +1,21 @@
+[(#REM) 
+
+  ### /!\ table GEO_PAYS (geographie) ###
+       
+  Parametres :
+  - class : classe(s) css ajoutes au select
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{pays, pays,
+               label=<:plugin:info_pays:>})] 
+]
+<select name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_pays(GEO_PAYS){par multi nom}>
+       <option value="#ID_PAYS"[(#ID_PAYS|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#NOM</option>
+</BOUCLE_pays>
+</select>
diff --git a/www/plugins/saisies/saisies/police.html b/www/plugins/saisies/saisies/police.html
new file mode 100644 (file)
index 0000000..8cfbf51
--- /dev/null
@@ -0,0 +1,22 @@
+[(#REM) 
+
+  ### /!\ boucle POUR ###
+  
+  Parametres :
+  - class : classe(s) css ajoutes au select
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{police, couleur_foncee, 
+               label=<:spa:couleur_foncee:>, 
+               obligatoire=non})] 
+]
+<select name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
+       [(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+       <BOUCLE_police(POUR){tableau #VAL{polices/}|find_all_in_path{\w+\.ttf}}{par cle}>
+               <option value="#CLE"[ (#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}|=={#CLE}|oui)selected="selected"]>#CLE</option>
+       </BOUCLE_police>
+</select>
diff --git a/www/plugins/saisies/saisies/position_construire_formulaire.html b/www/plugins/saisies/saisies/position_construire_formulaire.html
new file mode 100644 (file)
index 0000000..5801fc0
--- /dev/null
@@ -0,0 +1,46 @@
+<select name="#ENV{nom}" id="champ_#ENV{nom}">
+       #SET{tab,#ENV{formulaire}}
+       #SET{tab_par_nom,#ENV{formulaire}|saisies_lister_par_nom}
+       #SET{padding,0}
+       #SET{liste_parents,#ARRAY{0,''}}
+       <BOUCLE_parcours(POUR){tableau #GET{tab}}>
+       #SET{saisie,#VALEUR}
+       <option value="[(#GET{saisie}|table_valeur{options}|table_valeur{nom})]" style="padding-left:#GET{padding}px" [(#ENV{valeur,#ENV{saisie_a_positionner}}|=={#GET{saisie}|table_valeur{options}|table_valeur{nom}}|oui)selected="selected"]>
+               [(#GET{saisie}|table_valeur{options}|table_valeur{label}
+                       |sinon{#GET{saisie}|table_valeur{options}|table_valeur{nom}}
+                       |couper{60})]
+       </option>
+               <BOUCLE_test_enfants(CONDITION){si #GET{saisie}|table_valeur{options}|table_valeur{nom}|!={#ENV{saisie_a_positionner}}|et{#GET{saisie}|table_valeur{saisies}|is_array}}>
+               #SET{tab,#GET{saisie}|table_valeur{saisies}}
+               #SET{padding,#GET{padding}|plus{20}}
+               #SET_PUSH{liste_parents,#GET{saisie}|table_valeur{options}|table_valeur{nom}}
+               <BOUCLE_parcours_recursif(BOUCLE_parcours)/>
+               #SET{padding,#GET{padding}|moins{20}}
+               #SET{liste_parents,#GET{liste_parents}|array_slice{0,-1}}
+               </BOUCLE_test_enfants>
+       </BOUCLE_parcours>
+       #SET{parent, #GET{liste_parents}|table_valeur{#GET{liste_parents}|count|moins{1}}}
+       <option value="[#GET{parent}]" style="padding-left:#GET{padding}px; font-style:italic;">
+               [(#GET{parent}|non)
+                       <:saisies:construire_position_fin_formulaire:>
+               ]
+               [(#GET{parent}|oui)
+                       #SET{groupe,#GET{tab_par_nom}|table_valeur{#GET{parent}}}
+                       #SET{groupe,#GET{groupe}|table_valeur{options}|table_valeur{label}|sinon{#GET{groupe}|table_valeur{options}|table_valeur{nom}}|couper{60}}
+                       <:saisies:construire_position_fin_groupe{groupe=#GET{groupe}}:>
+               ]
+       </option>
+       </B_parcours>
+       #SET{parent, #GET{liste_parents}|table_valeur{#GET{liste_parents}|count|moins{1}}}
+       <option value="[#GET{parent}]" style="padding-left:#GET{padding}px; font-style:italic;">
+               [(#GET{parent}|non)
+                       <:saisies:construire_position_fin_formulaire:>
+               ]
+               [(#GET{parent}|oui)
+                       #SET{groupe,#GET{tab_par_nom}|table_valeur{#GET{parent}}}
+                       #SET{groupe,#GET{groupe}|table_valeur{options}|table_valeur{label}|sinon{#GET{groupe}|table_valeur{options}|table_valeur{nom}}|couper{60}}
+                       <:saisies:construire_position_fin_groupe{groupe=#GET{groupe}}:>
+               ]
+       </option>
+       <//B_parcours>
+</select>
diff --git a/www/plugins/saisies/saisies/radio.html b/www/plugins/saisies/saisies/radio.html
new file mode 100644 (file)
index 0000000..a8fdb47
--- /dev/null
@@ -0,0 +1,29 @@
+[(#REM) 
+
+  ### /!\ boucle POUR (spip Bonux) ###
+  
+  Parametres :
+  - datas : tableau de donnees cle=>valeur
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{radio, afficher_liste,
+               label=<:plugin:afficher_liste:>,
+               explication=<:plugin:explication_afficher_liste:>,
+               datas=#ARRAY{
+                       cle1,valeur1,
+                       cle2,valeur2,
+                       cle3,valeur3}})]
+]
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV*{datas}}
+#SET{datas, #GET{datas}|is_string|?{(#GET{datas}|saisies_chaine2tableau), #GET{datas}}}
+
+<BOUCLE_radio(POUR){tableau #GET{datas}}>
+<div class="#ENV{choix,choix}[ (#ENV{choix,choix})_#CLE]">
+       <input type="radio" name="#ENV{nom}" class="radio" id='champ_[(#ENV{nom}|saisie_nom2classe)]_#COMPTEUR_BOUCLE'[ (#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}|=={#CLE}|oui)checked='checked'] value='#CLE' [ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"] />
+       <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_#COMPTEUR_BOUCLE">[(#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}|=={#CLE}|oui)<strong>]#VALEUR[(#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}|=={#CLE}|oui)</strong>]</label>
+</div>
+</BOUCLE_radio>
diff --git a/www/plugins/saisies/saisies/radio.yaml b/www/plugins/saisies/saisies/radio.yaml
new file mode 100644 (file)
index 0000000..c898090
--- /dev/null
@@ -0,0 +1,108 @@
+
+titre: '<:saisies:saisie_radio_titre:>'
+description: '<:saisies:saisie_radio_explication:>'
+icone: 'images/saisies_radio.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'datas'
+          label: '<:saisies:option_datas_label:>'
+          explication: '<:saisies:option_datas_explication:>'
+          rows: 10
+          cols: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+          size: 50
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'readonly'
+          label: '<:saisies:option_readonly_label:>'
+          explication: '<:saisies:option_readonly_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'obligatoire'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_radio_titre:>'
+    datas:
+      choix1: '<:saisies:saisie_radio_defaut_choix1:>'
+      choix2: '<:saisies:saisie_radio_defaut_choix2:>'
+      choix3: '<:saisies:saisie_radio_defaut_choix3:>'
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/recherche.html b/www/plugins/saisies/saisies/recherche.html
new file mode 100644 (file)
index 0000000..5ccf0d9
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM) \r
+               Zone de recherche. Sur les sites en HTML5, utilise type="search"\r
+               sur le input, et type="text" par défaut pour les autres.\r
+               Dans ce dernier cas, on renseigne quand même class="search"\r
+               ("recherche" serait mieux, mais la saisie input utilise automatiquement\r
+               la valeur de #ENV{type}).\r
+][(#INCLURE{fond=saisies/input,\r
+                       env,\r
+            type=#HTML5|?{search,text},\r
+            class=[(#HTML5|?{[(#ENV{class})],[(#ENV{class}) ]search})]})]\r
diff --git a/www/plugins/saisies/saisies/secteur.html b/www/plugins/saisies/saisies/secteur.html
new file mode 100644 (file)
index 0000000..824e3db
--- /dev/null
@@ -0,0 +1,30 @@
+[(#REM) \r
+\r
+  Parametres :\r
+  - class : classe(s) css ajoutes au select\r
+  - multiple : si quelquechose est passe, le select est multiple, sinon, c'est un select simple\r
+       Dans le cas multiple, defaut et valeur doivent etre un array, sinon un int\r
+  - recursif : si oui liste les rubriques de facon recursive, et pas uniquement les secteurs\r
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")\r
+    (seulement si non multiple)\r
+  - cacher_option_intro : pas de premier option vide  (defaut:"")\r
+  - defaut : valeur par defaut si pas présente dans l'environnement\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+        \r
+  Exemple d'appel :\r
+       [(#SAISIE{secteur,secteur_region,\r
+               label=<:plugin:secteur_region:>,\r
+               multiple=oui})] \r
+]\r
+<select name="#ENV{nom}[(#ENV{multiple}|?{[(#VAL{&#91;&#93;}|html_entity_decode)]})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][(#ENV{multiple}|oui) multiple="multiple"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>\r
+       [(#ENV{cacher_option_intro}|ou{#ENV{multiple}}|non)\r
+               <option value="">[(#ENV{option_intro})]</option>]\r
+       <BOUCLE_secteurs(RUBRIQUES){racine}{par num titre, titre}{tout}>\r
+               [(#ENV{multiple}|oui)\r
+               <option value="#ID_RUBRIQUE"[(#ID_RUBRIQUE|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]>#TITRE</option>]\r
+               [(#ENV{multiple}|non)\r
+               <option value="#ID_RUBRIQUE"[(#ID_RUBRIQUE|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#TITRE</option>]\r
+               [(#ENV{recursif}|oui)\r
+               <INCLURE{fond=prive/listes/rubriques_recursives,valeur=#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}},id_rubrique=#ID_RUBRIQUE,multiple} />]\r
+       </BOUCLE_secteurs>\r
+</select>\r
diff --git a/www/plugins/saisies/saisies/selecteur.html b/www/plugins/saisies/saisies/selecteur.html
new file mode 100644 (file)
index 0000000..01d8e89
--- /dev/null
@@ -0,0 +1,16 @@
+
+[(#REM) Attention ! Nécessite SPIP 3 ! ]
+
+[(#SET{val,#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}})]
+
+[(#INCLURE{fond=formulaires/selecteur/generique,
+       selected=#GET{val},
+       name=#ENV{nom},
+       afficher_langue=#ENV{afficher_langue,''},
+       select=[(#ENV{multiple}|?{'',' '})],
+       whitelist=#ENV{whitelist,#ARRAY},
+       blacklist=#ENV{blacklist,#ARRAY},
+       racine=#ENV{racine},
+       objet=#ENV{objet,racine},
+       id_objet=#ENV{id_objet,0},
+       env})]
diff --git a/www/plugins/saisies/saisies/selecteur_article.html b/www/plugins/saisies/saisies/selecteur_article.html
new file mode 100644 (file)
index 0000000..dc4a183
--- /dev/null
@@ -0,0 +1,41 @@
+[(#REM) \r
+         \r
+  ### /!\ selecteur (spip Bonux) ###\r
+         Attention, ce qui est retourne est un tableau :\r
+         _request($name) = array('article|3', 'article|9', 'rubrique|10');\r
+         Une fonction de SPIP Bonux permet de récupérer un tableau d'identifiants par type d'objet "picker_selected" :\r
+         (picker_selected est dans prive/formulaires/selecteur/generique_fonctions.php de SPIP 3)\r
+         Cette fonction peut etre pratique dans une boucle en utilisant le critere IN\r
+         \r
+  Parametres :\r
+  - multiple : si oui, on peut selectionner plusieurs articles\r
+  - afficher_langue : si oui, on affiche la langue de l'objet selectionne\r
+  - afficher_art_dans_langue_interface : si oui, on n'affiche que les articles de la langue de l'interface\r
+  - limite_branche : branche dans laquelle on limite le selecteur\r
+  - defaut : valeur par defaut si pas présente dans l'environnement\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+        \r
+  Exemple d'appel :\r
+       [(#SAISIE{selecteur_article,id_article,\r
+               label=<:plugin:article_en_une:>})] \r
+]\r
+[(#SET{val,#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}})]\r
+\r
+[(#SET{filtrer_langue_article,[(#ENV{afficher_art_dans_langue_interface,0}|oui) #ENV{lang}]})]\r
+\r
+[(#REM) input necessaire au tag label for \r
+       Mais si on le garde, la saisie enregistree en base, n'est pas correcte\r
+   On pourrait rajouter l'id dans le input cree par Bonux, mais du coup manque la chaine "champ_"\r
+   Comme ca a l'air un peu tordu tout ca, tant pis pour l'erreur HTML\r
+   Yffic\r
+]\r
+[(#REM) Donner a manger a CFG ou CVT-configurer si aucune valeur definie ]\r
+<!--keepme: <input type="hidden" name="[(#ENV{nom,id_item})][]" value="" />-->\r
+[(#INCLURE{fond=formulaires/selecteur/articles,\r
+       selected=#GET{val},\r
+       name=#ENV{nom},\r
+       afficher_langue=#ENV{afficher_langue,''},\r
+       filtrer_langue_article=#GET{filtrer_langue_article,''},\r
+       select=[(#ENV{multiple}|?{0,1})],\r
+       limite_branche=#ENV{limite_branche,''},\r
+       rubriques=0})]\r
diff --git a/www/plugins/saisies/saisies/selecteur_article.yaml b/www/plugins/saisies/saisies/selecteur_article.yaml
new file mode 100644 (file)
index 0000000..4efb105
--- /dev/null
@@ -0,0 +1,108 @@
+\r
+titre: '<:saisies:saisie_selecteur_article_titre:>'\r
+description: '<:saisies:saisie_selecteur_article:>'\r
+icone: 'images/saisies_selecteur_article.png'\r
+options:\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'description'\r
+      label: '<:saisies:option_groupe_description:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'label'\r
+          label: '<:saisies:option_label_label:>'\r
+          explication: '<:saisies:option_label_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'explication'\r
+          label: '<:saisies:option_explication_label:>'\r
+          explication: '<:saisies:option_explication_explication:>'\r
+          size: 50\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'utilisation'\r
+      label: '<:saisies:option_groupe_utilisation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'multiple'\r
+          label: '<:saisies:option_multiple_label:>'\r
+          explication: '<:saisies:option_multiple_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'afficher_langue'\r
+          label: '<:saisies:option_aff_langue_label:>'\r
+          explication: '<:saisies:option_aff_langue_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'afficher_art_dans_langue_interface'\r
+          label: '<:saisies:option_aff_art_interface_label:>'\r
+          explication: '<:saisies:option_aff_art_interface_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable'\r
+          label: '<:saisies:option_disable_label:>'\r
+          explication: '<:saisies:option_disable_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable_avec_post'\r
+          label: '<:saisies:option_disable_avec_post_label:>'\r
+          explication: '<:saisies:option_disable_avec_post_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'readonly'\r
+          label: '<:saisies:option_readonly_label:>'\r
+          explication: '<:saisies:option_readonly_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'affichage'\r
+      label: '<:saisies:option_groupe_affichage:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'attention'\r
+          label: '<:saisies:option_attention_label:>'\r
+          explication: '<:saisies:option_attention_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'info_obligatoire'\r
+          label: '<:saisies:option_info_obligatoire_label:>'\r
+          explication: '<:saisies:option_info_obligatoire_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'obligatoire'\r
+      label: '<:saisies:option_groupe_validation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'obligatoire'\r
+          label: '<:saisies:option_obligatoire_label:>'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'erreur_obligatoire'\r
+          label: '<:saisies:option_erreur_obligatoire_label:>'\r
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'\r
+defaut:\r
+  options:\r
+    label: '<:saisies:saisie_selecteur_article_titre:>'\r
+    # champs extras (definition du champ sql)\r
+    sql: "text DEFAULT '' NOT NULL"\r
diff --git a/www/plugins/saisies/saisies/selecteur_document.html b/www/plugins/saisies/saisies/selecteur_document.html
new file mode 100644 (file)
index 0000000..51dbc28
--- /dev/null
@@ -0,0 +1,83 @@
+[(#REM) 
+
+  Parametres supplementaire :
+  - defaut : valeur par defaut du parametre
+  - class : classe(s) css ajoutes a l'input
+  - size : taille du champ
+  - maxlength : nombre de caracteres maximum
+  - disable : champ insaisissable ? 'oui' (defaut : '')
+  - media : pour restreindre la modalboxe a un type de media particulier
+  - extension : pour restreindre a un type de fichier
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Note : dans les options, il faut definir 'env' a 'oui' pour que le selecteur puisse recuperer id_article, id_rubrique ou id_breve.
+  Note 2 : si on appelle le selecteur depuis une modalbox, il faut alors lui passer _modalbox_retour qui correspond a l'url de retour
+  apres selection du document. L'id du document sera alors passe par URL.
+]
+
+<input type="text" name="#ENV{nom}" class="text[ (#ENV{class})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ value="(#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}})"][ size="(#ENV{size})"][ maxlength="(#ENV{maxlength})"][ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][(#ENV{obligatoire}|et{#HTML5}|oui) required="required"] />
+
+[(#REM) Si la mediatheque est presente ]
+[(#PLUGIN{medias}|oui)
+
+[(#SET{exec,[(#PLUGIN{medias,version}|<{2}|?{'portfolio','popin-choisir_document'})]})]
+[(#SET{zajax,[(#PLUGIN{medias,version}|<{2}|?{'','var_zajax=contenu&'})]})]
+[(#SET{mod_fn,#ENV{_modalbox_retour}|?{'2','1'}})]
+
+[(#REM) Parcourir les documents de l'article ]
+[(#ENV{id_article}|oui)
+<p class='boutons'><input class='submit' type="button" name="parcourir" value="<:saisies:bouton_parcourir_docs_article:>"
+       onclick="jQuery.modalboxload(
+               '[(#URL_ECRIRE{#GET{exec},#GET{zajax}selectfunc=mediaselect#GET{mod_fn}_#ENV{nom}&id_article=#ENV{id_article}[&media=(#ENV{media})][&extension=(#ENV{extension})]})]',
+               {autoResize: true}
+       );"
+/></p>
+]
+
+[(#REM) Parcourir les documents de la rubrique ]
+[(#ENV{id_rubrique}|oui)
+<p class='boutons'><input class='submit' type="button" name="parcourir" value="<:saisies:bouton_parcourir_docs_rubrique:>"
+       onclick="jQuery.modalboxload(
+               '[(#URL_ECRIRE{#GET{exec},#GET{zajax}selectfunc=mediaselect#GET{mod_fn}_#ENV{nom}&id_rubrique=#ENV{id_rubrique}[&media=(#ENV{media})][&extension=(#ENV{extension})]})]',
+               {autoResize: true}
+       );"
+/></p>
+]
+
+[(#REM) Parcourir les documents de la breve ]
+[(#ENV{id_breve}|oui)
+<p class='boutons'><input class='submit' type="button" name="parcourir" value="<:saisies:bouton_parcourir_docs_breve:>"
+       onclick="jQuery.modalboxload(
+               '[(#URL_ECRIRE{#GET{exec},#GET{zajax}selectfunc=mediaselect#GET{mod_fn}_#ENV{nom}&id_breve=#ENV{id_breve}[&media=(#ENV{media})][&extension=(#ENV{extension})]})]',
+               {autoResize: true}
+       );"
+/></p>
+]
+
+[(#REM) Parcourir toute la mediatheque ]
+<p class='boutons'><input class='submit' type="button" name="parcourir" value="<:saisies:bouton_parcourir_mediatheque:>"
+       onclick="jQuery.modalboxload(
+               '[(#URL_ECRIRE{#GET{exec},#GET{zajax}selectfunc=mediaselect#GET{mod_fn}_#ENV{nom}[&media=(#ENV{media})][&extension=(#ENV{extension})]})]',
+               {autoResize: true}
+       );"
+/></p>
+
+[(#ENV{_modalbox_retour}|non)
+<script type="text/javascript">
+       function mediaselect1_#ENV{nom}(id){
+               jQuery.modalboxclose();
+               jQuery("#champ_#ENV{nom}").attr('value',id).focus();
+       };
+</script>
+]
+
+[(#ENV{_modalbox_retour}|oui)
+<script type="text/javascript">
+       function mediaselect2_#ENV{nom}(id){
+               jQuery.modalboxload('#ENV**{_modalbox_retour}&#ENV{nom}='+id);
+       };
+</script>
+]
+
+]
diff --git a/www/plugins/saisies/saisies/selecteur_langue.html b/www/plugins/saisies/saisies/selecteur_langue.html
new file mode 100644 (file)
index 0000000..aedaa47
--- /dev/null
@@ -0,0 +1,20 @@
+[(#REM) 
+       
+  Parametres :
+  - class : classe(s) css ajoutes au select
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{selecteur_langue,lang,
+               label=<:plugin:info_langue:>})] 
+]
+[(#SET{valeur,[(#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,''}}})]})]
+[(#SET{langues,[(#VAL{changer_lang}|liste_options_langues{#GET{valeur}})]})]
+<select name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
+<BOUCLE_si_spip2(CONDITION){si (#GET{langues}|is_array|non)}>
+#GET{langues}
+</BOUCLE_si_spip2>
+[(#INCLURE{fond=prive/formulaires/inc-options-langues,name=changer_lang,default=#GET{valeur,#LANG}})]
+<//B_si_spip2>
+</select>
diff --git a/www/plugins/saisies/saisies/selecteur_rubrique.html b/www/plugins/saisies/saisies/selecteur_rubrique.html
new file mode 100644 (file)
index 0000000..1590ab2
--- /dev/null
@@ -0,0 +1,40 @@
+[(#REM) \r
+         \r
+  ### /!\ selecteur (spip Bonux) ###\r
+         Attention, ce qui est retourne est un tableau :\r
+         _request($name) = array('article|3', 'article|9', 'rubrique|10');\r
+         Une fonction de SPIP Bonux permet de récupérer un tableau d'identifiants par type d'objet :\r
+         [(#CHAMP|picker_selected{article})]\r
+         Cette fonction peut etre pratique dans une boucle en utilisant le critere IN\r
+         \r
+  Parametres :\r
+  - multiple : si oui, on peut selectionner plusieurs rubriques\r
+  - afficher_langue : si oui, on affiche la langue de l'objet selectionne\r
+  - afficher_rub_dans_langue_interface : si oui, on n'affiche que les rubriques de la langue de l'interface\r
+  - defaut : valeur par defaut si pas présente dans l'environnement\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+  \r
+  Exemple d'appel :\r
+       [(#SAISIE{selecteur_rubrique,rubriques_menu,\r
+               multiple=oui,\r
+               label=<:plugin:article_en_une:>})] \r
+]\r
+\r
+[(#SET{val,#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}})]\r
+\r
+[(#SET{filtrer_langue_rubrique,[(#ENV{afficher_rub_dans_langue_interface,0}|oui) #ENV{lang}]})]\r
+\r
+[(#REM) input necessaire au tag label for \r
+       Mais si on le garde, la saisie enregistree en base, n'est pas correcte\r
+   On pourrait rajouter l'id dans le input cree par Bonux, mais du coup manque la chaine "champ_"\r
+   Comme ca a l'air un peu tordu tout ca, tant pis pour l'erreur HTML\r
+   Yffic\r
+]\r
+[(#REM) Donner a manger a CFG ou CVT-configurer si aucune valeur definie ]\r
+<!--keepme: <input type="hidden" name="[(#ENV{nom,id_item})][]" id="[champ_(#ENV{nom,id_item})]" value="" />-->\r
+[(#INCLURE{fond=formulaires/selecteur/rubriques,\r
+       selected=#GET{val},\r
+       name=#ENV{nom},\r
+       afficher_langue=#ENV{afficher_langue,''},\r
+       filtrer_langue_rubrique=#GET{filtrer_langue_rubrique,''},\r
+       select=[(#ENV{multiple}|?{0,1})]})]\r
diff --git a/www/plugins/saisies/saisies/selecteur_rubrique.yaml b/www/plugins/saisies/saisies/selecteur_rubrique.yaml
new file mode 100644 (file)
index 0000000..304b103
--- /dev/null
@@ -0,0 +1,108 @@
+\r
+titre: '<:saisies:saisie_selecteur_rubrique_titre:>'\r
+description: '<:saisies:saisie_selecteur_rubrique:>'\r
+icone: 'images/saisies_selecteur_rubrique.png'\r
+options:\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'description'\r
+      label: '<:saisies:option_groupe_description:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'label'\r
+          label: '<:saisies:option_label_label:>'\r
+          explication: '<:saisies:option_label_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'explication'\r
+          label: '<:saisies:option_explication_label:>'\r
+          explication: '<:saisies:option_explication_explication:>'\r
+          size: 50\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'utilisation'\r
+      label: '<:saisies:option_groupe_utilisation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'multiple'\r
+          label: '<:saisies:option_multiple_label:>'\r
+          explication: '<:saisies:option_multiple_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'afficher_langue'\r
+          label: '<:saisies:option_aff_langue_label:>'\r
+          explication: '<:saisies:option_aff_langue_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'afficher_rub_dans_langue_interface'\r
+          label: '<:saisies:option_aff_rub_interface_label:>'\r
+          explication: '<:saisies:option_aff_rub_interface_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable'\r
+          label: '<:saisies:option_disable_label:>'\r
+          explication: '<:saisies:option_disable_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable_avec_post'\r
+          label: '<:saisies:option_disable_avec_post_label:>'\r
+          explication: '<:saisies:option_disable_avec_post_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'readonly'\r
+          label: '<:saisies:option_readonly_label:>'\r
+          explication: '<:saisies:option_readonly_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'affichage'\r
+      label: '<:saisies:option_groupe_affichage:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'attention'\r
+          label: '<:saisies:option_attention_label:>'\r
+          explication: '<:saisies:option_attention_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'info_obligatoire'\r
+          label: '<:saisies:option_info_obligatoire_label:>'\r
+          explication: '<:saisies:option_info_obligatoire_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'obligatoire'\r
+      label: '<:saisies:option_groupe_validation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'obligatoire'\r
+          label: '<:saisies:option_obligatoire_label:>'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'erreur_obligatoire'\r
+          label: '<:saisies:option_erreur_obligatoire_label:>'\r
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'\r
+defaut:\r
+  options:\r
+    label: '<:saisies:saisie_selecteur_rubrique_titre:>'\r
+    # champs extras (definition du champ sql)\r
+    sql: "text DEFAULT '' NOT NULL"\r
diff --git a/www/plugins/saisies/saisies/selecteur_rubrique_article.html b/www/plugins/saisies/saisies/selecteur_rubrique_article.html
new file mode 100644 (file)
index 0000000..16607d9
--- /dev/null
@@ -0,0 +1,45 @@
+[(#REM) \r
+         \r
+  ### /!\ selecteur (spip Bonux) ###\r
+         Attention, ce qui est retourne est un tableau :\r
+         _request($name) = array('article|3', 'article|9', 'rubrique|10');\r
+         Une fonction de SPIP Bonux permet de récupérer un tableau d'identifiants par type d'objet :\r
+         [(#CHAMP|picker_selected{article})]\r
+         Cette fonction peut etre pratique dans une boucle en utilisant le critere IN\r
+         \r
+  Parametres :\r
+  - multiple : si oui, on peut selectionner plusieurs rubriques\r
+  - afficher_langue : si oui, on affiche la langue de l'objet selectionne\r
+  - afficher_art_dans_langue_interface : si oui, on n'affiche que les articles de la langue de l'interface\r
+  - afficher_rub_dans_langue_interface : si oui, on n'affiche que les rubriques de la langue de l'interface\r
+  - defaut : valeur par defaut si pas présente dans l'environnement\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+        \r
+  Exemple d'appel :\r
+       [(#SAISIE{selecteur_rubrique_article,menu,\r
+               multiple=1,\r
+               label=<:plugin:choisir_le_menu:>})] \r
+]\r
+[(#SET{val,#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}})]\r
+\r
+[(#SET{filtrer_langue_article,[(#ENV{afficher_art_dans_langue_interface,0}|oui) #ENV{lang}]})]\r
+[(#SET{filtrer_langue_rubrique,[(#ENV{afficher_rub_dans_langue_interface,0}|oui) #ENV{lang}]})]\r
+\r
+[(#REM) input necessaire au tag label for \r
+       Mais si on le garde, la saisie enregistree en base, n'est pas correcte\r
+   On pourrait rajouter l'id dans le input cree par Bonux, mais du coup manque la chaine "champ_"\r
+   Comme ca a l'air un peu tordu tout ca, tant pis pour l'erreur HTML\r
+   Yffic\r
+]\r
+[(#REM) Donner a manger a CFG ou CVT-configurer si aucune valeur definie ]\r
+<!--keepme: <input type="hidden" name="[(#ENV{nom,id_item})][]" id="[champ_(#ENV{nom,id_item})]" value="" /> -->\r
+\r
+[(#INCLURE{fond=formulaires/selecteur/articles,\r
+       selected=#GET{val},\r
+       name=#ENV{nom},\r
+       afficher_langue=#ENV{afficher_langue,''},\r
+       filtrer_langue_article=#GET{filtrer_langue_article,''},\r
+       filtrer_langue_rubrique=#GET{filtrer_langue_rubrique,''},\r
+       select=[(#ENV{multiple}|?{0,1})],\r
+       rubriques=1})]\r
+\r
diff --git a/www/plugins/saisies/saisies/selecteur_rubrique_article.yaml b/www/plugins/saisies/saisies/selecteur_rubrique_article.yaml
new file mode 100644 (file)
index 0000000..79dafc2
--- /dev/null
@@ -0,0 +1,114 @@
+\r
+titre: '<:saisies:saisie_selecteur_rubrique_article_titre:>'\r
+description: '<:saisies:saisie_selecteur_rubrique_article:>'\r
+icone: 'images/saisies_selecteur_rubrique_article.png'\r
+options:\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'description'\r
+      label: '<:saisies:option_groupe_description:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'label'\r
+          label: '<:saisies:option_label_label:>'\r
+          explication: '<:saisies:option_label_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'explication'\r
+          label: '<:saisies:option_explication_label:>'\r
+          explication: '<:saisies:option_explication_explication:>'\r
+          size: 50\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'utilisation'\r
+      label: '<:saisies:option_groupe_utilisation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'multiple'\r
+          label: '<:saisies:option_multiple_label:>'\r
+          explication: '<:saisies:option_multiple_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'afficher_langue'\r
+          label: '<:saisies:option_aff_langue_label:>'\r
+          explication: '<:saisies:option_aff_langue_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'afficher_art_dans_langue_interface'\r
+          label: '<:saisies:option_aff_art_interface_label:>'\r
+          explication: '<:saisies:option_aff_art_interface_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'afficher_rub_dans_langue_interface'\r
+          label: '<:saisies:option_aff_rub_interface_label:>'\r
+          explication: '<:saisies:option_aff_rub_interface_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable'\r
+          label: '<:saisies:option_disable_label:>'\r
+          explication: '<:saisies:option_disable_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'disable_avec_post'\r
+          label: '<:saisies:option_disable_avec_post_label:>'\r
+          explication: '<:saisies:option_disable_avec_post_explication:>'\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'readonly'\r
+          label: '<:saisies:option_readonly_label:>'\r
+          explication: '<:saisies:option_readonly_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'affichage'\r
+      label: '<:saisies:option_groupe_affichage:>'\r
+    saisies:\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'attention'\r
+          label: '<:saisies:option_attention_label:>'\r
+          explication: '<:saisies:option_attention_explication:>'\r
+          size: 50\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'info_obligatoire'\r
+          label: '<:saisies:option_info_obligatoire_label:>'\r
+          explication: '<:saisies:option_info_obligatoire_explication:>'\r
+  -\r
+    saisie: 'fieldset'\r
+    options:\r
+      nom: 'obligatoire'\r
+      label: '<:saisies:option_groupe_validation:>'\r
+    saisies:\r
+      -\r
+        saisie: 'oui_non'\r
+        options:\r
+          nom: 'obligatoire'\r
+          label: '<:saisies:option_obligatoire_label:>'\r
+      -\r
+        saisie: 'input'\r
+        options:\r
+          nom: 'erreur_obligatoire'\r
+          label: '<:saisies:option_erreur_obligatoire_label:>'\r
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'\r
+defaut:\r
+  options:\r
+    label: '<:saisies:saisie_selecteur_rubrique_article_titre:>'\r
+    # champs extras (definition du champ sql)\r
+    sql: "text DEFAULT '' NOT NULL"\r
diff --git a/www/plugins/saisies/saisies/selecteur_site.html b/www/plugins/saisies/saisies/selecteur_site.html
new file mode 100644 (file)
index 0000000..371bf5c
--- /dev/null
@@ -0,0 +1,33 @@
+[(#REM)\r
+\r
+Saisies qui liste les sites syndiques\r
+Par défaut ne liste que ceux des rubriques à la racine (secteurs)\r
+\r
+  Parametres :\r
+  - class : classe(s) css ajoutes au select\r
+  - multiple : si quelquechose est passe, le select est multiple, sinon, c'est un select simple\r
+    Dans le cas multiple, defaut et valeur doivent etre un array, sinon un int\r
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")\r
+    (seulement si non multiple)\r
+  - cacher_option_intro : pas de premier option vide  (defaut:"")\r
+  - syndication : 'oui' ou 'non' (sélectionner uniquement les sites avec ou sans syndication)\r
+  - defaut : valeur par defaut si pas présente dans l'environnement\r
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement\r
+\r
+]\r
+<select name="#ENV{nom}[(#ENV{multiple}|?{[(#VAL{&#91;&#93;}|html_entity_decode)]})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][(#ENV{multiple}|oui) multiple="multiple" size="#ENV{size,10}"][ (#ENV*{attributs})]>\r
+       [(#ENV{cacher_option_intro}|ou{#ENV{multiple}}|non)\r
+               <option value="0">[(#ENV{option_intro})]</option>]\r
+       <BOUCLE_secteurs(RUBRIQUES){racine}{par num titre, titre}{tout}>\r
+       <B_sites>\r
+       <optgroup label="#TITRE">\r
+               <BOUCLE_sites(SITES){id_secteur}{par nom_site}{syndication ?}>\r
+               [(#ENV{multiple}|oui)\r
+               <option value="#ID_SYNDIC"[(#ID_SYNDIC|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]>#NOM_SITE</option>]\r
+               [(#ENV{multiple}|non)\r
+               <option value="#ID_SYNDIC"[(#ID_SYNDIC|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#NOM_SITE</option>]\r
+               </BOUCLE_sites>\r
+       </optgroup>\r
+       </B_sites>\r
+       </BOUCLE_secteurs>\r
+</select>\r
diff --git a/www/plugins/saisies/saisies/selection.html b/www/plugins/saisies/saisies/selection.html
new file mode 100644 (file)
index 0000000..ff466e3
--- /dev/null
@@ -0,0 +1,54 @@
+[(#REM) 
+
+  ### /!\ boucle POUR (spip Bonux) ###
+       
+  Parametres :
+  - ** datas : tableau de donnees
+               liste simple : cle=>valeur
+               liste avec groupes :  cle=> tableau (cle=>valeur)
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - class : classe(s) css ajoutes au select
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemples d'appels
+  pour une liste simple :
+       [(#SAISIE{selection,produits,
+               label=<:plugin:info_produits:>,
+               datas=#ARRAY{
+                       cle1,valeur1,
+                       cle2,valeur2,
+                       cle3,valeur3}})]
+  pour une liste avec groupes :
+       [(#SAISIE{selection,produits,
+               label=<:plugin:info_produits:>,
+               datas=#ARRAY{
+                       cle1,#ARRAY{
+                               cle1,valeur1,
+                               cle2,valeur2},
+                       cle2,#ARRAY{
+                               cle1,valeur1,
+                               cle2,valeur2}}})] 
+]
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV*{datas}}
+#SET{datas, #GET{datas}|is_string|?{(#GET{datas}|saisies_chaine2tableau), #GET{datas}}}
+[(#REM) Attention, la valeur ou la valeur forcée peut être une chaine vide. On doit donc tester avec is_null. ]
+#SET{valeur,#ENV{valeur_forcee}|is_null|?{#ENV{valeur}|is_null|?{#ENV{defaut},#ENV{valeur}},#ENV{valeur_forcee}}}
+
+<select name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ size="(#ENV{size})"][ (#ENV*{attributs})]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_selection(POUR){tableau #GET{datas}}>
+       <B_cond>
+       <optgroup label="#CLE">
+       <BOUCLE_cond(CONDITION){si #VALEUR|is_array}><BOUCLE_optgroup(POUR){tableau #VALEUR}>
+               <option value="#CLE"[(#CLE|=={#GET{valeur}}|oui)selected="selected"]>#VALEUR</option>
+       </BOUCLE_optgroup></BOUCLE_cond>
+       </optgroup>
+       </B_cond>
+       <option value="#CLE"[(#CLE|=={#GET{valeur}}|oui)selected="selected"]>#VALEUR</option>
+       <//B_cond>
+</BOUCLE_selection>
+</select>
diff --git a/www/plugins/saisies/saisies/selection.yaml b/www/plugins/saisies/saisies/selection.yaml
new file mode 100644 (file)
index 0000000..9a79b32
--- /dev/null
@@ -0,0 +1,123 @@
+
+titre: '<:saisies:saisie_selection_titre:>'
+description: '<:saisies:saisie_selection_explication:>'
+icone: 'images/saisies_selection.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'datas'
+          label: '<:saisies:option_datas_label:>'
+          explication: '<:saisies:option_datas_explication:>'
+          rows: 10
+          cols: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+          size: 50
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'option_intro'
+          label: '<:saisies:option_option_intro_label:>'
+          size: 50
+      -
+        saisie: 'case'
+        options:
+          nom: 'cacher_option_intro'
+          label_case: '<:saisies:option_cacher_option_intro_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'size'
+          label: '<:saisies:option_size_label:>'
+          explication: '<:saisies:option_size_explication:>'
+        verifier:
+          type: 'entier'
+          options:
+            min: 1
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'obligatoire'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_selection_titre:>'
+    datas:
+      choix1: '<:saisies:saisie_radio_defaut_choix1:>'
+      choix2: '<:saisies:saisie_radio_defaut_choix2:>'
+      choix3: '<:saisies:saisie_radio_defaut_choix3:>'
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/selection_multiple.html b/www/plugins/saisies/saisies/selection_multiple.html
new file mode 100755 (executable)
index 0000000..3121495
--- /dev/null
@@ -0,0 +1,36 @@
+[(#REM) 
+
+  ### /!\ boucle POUR (spip Bonux) ###
+       
+  Parametres :
+  - datas : tableau de donnees cle=>valeur
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - class : classe(s) css ajoutes au select
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{selection_multiple,produits,
+               label=<:plugin:info_produits:>,
+               datas=#ARRAY{
+                       cle1,valeur1,
+                       cle2,valeur2,
+                       cle3,valeur3}})] 
+]
+
+[(#REM) datas peut être une chaine qu'on sait décomposer ]
+#SET{datas, #ENV{datas}|saisies_chaine2tableau}
+
+[(#REM) defaut peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
+#SET{defaut, #ENV{defaut}|saisies_chaine2tableau}
+
+[(#REM) valeur peut être une chaine (plusieurs valeurs ou pas) qu'on sait décomposer ]
+#SET{valeur, #ENV{valeur}|saisies_valeur2tableau}
+
+<select name="#ENV{nom}[]" id="champ_[(#ENV{nom}|saisie_nom2classe)]" multiple="multiple"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ size="(#ENV{size,10})"][ (#ENV*{attributs})]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_selection(POUR){tableau #GET{datas}}>
+       <option value="#CLE" [(#CLE|in_array{#ENV{valeur_forcee,#GET{valeur,#GET{defaut}}}}|oui) selected="selected"]>#VALEUR</option>
+</BOUCLE_selection>
+</select>
diff --git a/www/plugins/saisies/saisies/selection_multiple.yaml b/www/plugins/saisies/saisies/selection_multiple.yaml
new file mode 100644 (file)
index 0000000..ecaa51d
--- /dev/null
@@ -0,0 +1,125 @@
+
+titre: '<:saisies:saisie_selection_multiple_titre:>'
+description: '<:saisies:saisie_selection_multiple_explication:>'
+icone: 'images/saisies_selection_multiple.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'datas'
+          label: '<:saisies:option_datas_label:>'
+          explication: '<:saisies:option_datas_explication:>'
+          rows: 10
+          cols: 50
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+          rows: 10
+          cols: 50
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'option_intro'
+          label: '<:saisies:option_option_intro_label:>'
+          size: 50
+      -
+        saisie: 'case'
+        options:
+          nom: 'cacher_option_intro'
+          label_case: '<:saisies:option_cacher_option_intro_label:>'
+          defaut: 'on'
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'size'
+          label: '<:saisies:option_size_label:>'
+          explication: '<:saisies:option_size_explication:>'
+        verifier:
+          type: 'entier'
+          options:
+            min: 1
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'obligatoire'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_selection_multiple_titre:>'
+    datas:
+      choix1: '<:saisies:saisie_radio_defaut_choix1:>'
+      choix2: '<:saisies:saisie_radio_defaut_choix2:>'
+      choix3: '<:saisies:saisie_radio_defaut_choix3:>'
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/selection_par_groupe.html b/www/plugins/saisies/saisies/selection_par_groupe.html
new file mode 100644 (file)
index 0000000..d87d60b
--- /dev/null
@@ -0,0 +1,35 @@
+[(#REM) 
+
+  ### /!\ boucle POUR (spip Bonux) ###
+       
+  Parametres :
+  - ** datas : tableau de donnees groupe=>array(cle=>valeur)
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - class : classe(s) css ajoutes au select
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{selection_par_groupe,produits,
+               label=<:plugin:info_produits:>,
+               datas=#ARRAY{
+                       groupe 1,#ARRAY{
+                               cle1,valeur1,
+                               cle2,valeur2,
+                               cle3,valeur3},
+                       groupe 2,#ARRAY{
+                               cle4,valeur1,
+                               cle5,valeur2,
+                               cle6,valeur3}}})] 
+]
+<select name="#ENV{nom}" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
+[(#ENV{cacher_option_intro}|non)<option value="">[(#ENV{option_intro})]</option>]
+<BOUCLE_groupes(POUR){tableau #ENV{datas}}>
+       <optgroup label="[(#CLE|attribut_html)]">
+               <BOUCLE_selection(POUR){tableau #VALEUR}>
+                       <option value="#CLE" [(#CLE|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]>#VALEUR</option>
+               </BOUCLE_selection>
+       </optgroup>
+</BOUCLE_groupes>
+</select>
diff --git a/www/plugins/saisies/saisies/statuts_auteurs.html b/www/plugins/saisies/saisies/statuts_auteurs.html
new file mode 100644 (file)
index 0000000..56a84c6
--- /dev/null
@@ -0,0 +1,43 @@
+[(#REM)
+
+  Parametres :
+  - class : classe(s) css ajoutes au select
+  - multiple : si quelquechose est passe, le select est multiple, sinon, c'est un select simple
+       Dans le cas multiple, defaut et valeur doivent être un array, sinon un int
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+    (seulement si non multiple)
+  - cacher_option_intro : pas de premier option vide  (defaut:"")
+  - afficher_tous : permet d'afficher une option de valeur "tous" correspondant à tous les utilisateurs
+  - poubelle : permet d'afficher le statut poubelle
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  - size : dans le cas d'un select multiple, limite le nombre de lignes au chiffre passé
+  
+  Exemple d'appel :
+       [(#SAISIE{statuts_auteurs,statuts,
+               label=<:plugin:statuts_des_auteurs:>,
+               multiple=oui})]
+]
+
+<select name="#ENV{nom}[(#ENV{multiple}|?{[(#VAL{&#91;&#93;}|html_entity_decode)]})]" id="champ_[(#ENV{nom}|saisie_nom2classe)]"[ class="(#ENV{class})"][(#ENV{multiple}|oui) multiple="multiple" size="[(#ENV{size,#ENV{afficher_tous}|?{4,3}})]"][ disabled="(#ENV{disable})"][ (#ENV*{attributs})]>
+       [(#ENV{cacher_option_intro}|ou{#ENV{multiple}}|non)
+               <option value="">[(#ENV{option_intro})]</option>]
+       [(#ENV{multiple}|oui)
+               <option value="0minirezo"[(#VAL{0minirezo}|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]><:info_administrateurs:></option>
+               <option value="1comite"[(#VAL{1comite}|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]><:info_redacteurs:></option>
+               <option value="6forum"[(#VAL{6forum}|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]><:info_visiteurs:></option>
+               [(#ENV{poubelle}|oui)
+               <option value="5poubelle"[(#VAL{5poubelle}|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]><:texte_statut_poubelle:></option>]
+               [(#ENV{afficher_tous}|oui)
+               <option value="tous"[(#VAL{tous}|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]><:saisies:tous_visiteurs:></option>]  ]
+       [(#ENV{multiple}|non)
+               <option value="0minirezo"[(#VAL{0minirezo}|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]><:info_administrateurs:></option>
+               <option value="1comite"[(#VAL{1comite}|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]><:info_redacteurs:></option>
+               <option value="6forum"[(#VAL{6forum}|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]><:info_visiteurs:></option>
+               [(#ENV{poubelle}|oui)
+                       <option value="5poubelle"[(#VAL{5poubelle}|=={#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}|oui) selected="selected"]><:texte_statut_poubelle:></option>]
+               [(#ENV{afficher_tous}|oui)
+               <option value="tous"[(#VAL{tous}|in_array{#ENV{valeur_forcee,#ENV{valeur,#ENV{defaut,#ARRAY}}}}|oui) selected="selected"]><:saisies:tous_visiteurs:></option>]
+       ]
+</select>
+
diff --git a/www/plugins/saisies/saisies/telephone.html b/www/plugins/saisies/saisies/telephone.html
new file mode 100644 (file)
index 0000000..2c52797
--- /dev/null
@@ -0,0 +1,12 @@
+[(#REM) \r
+\r
+               Zone de saisie de numero de telephone. Sur les sites en HTML5,\r
+               utilise type="tel" sur le input (et donc class="tel"); et\r
+               type="text" par défaut pour les autres (et donc class="text").\r
+               Dans ce dernier cas, on renseigne quand même class="tel" pour\r
+               avoir une classe cohérente avec ou sans HTML5.\r
+\r
+][(#INCLURE{fond=saisies/input,\r
+                       env,\r
+            type=#HTML5|?{tel,text},\r
+            class=[(#HTML5|?{[(#ENV{class})],[(#ENV{class}) ]tel})]})]\r
diff --git a/www/plugins/saisies/saisies/textarea.html b/www/plugins/saisies/saisies/textarea.html
new file mode 100644 (file)
index 0000000..182b2cd
--- /dev/null
@@ -0,0 +1,21 @@
+[(#REM)
+
+  Parametres :
+  - class : classe(s) css ajoutes au textarea
+  - rows : nombre de ligne, par defaut : 20 
+  - cols : nombre de caracteres de large, par defaut : 40 (cela depend aussi et surtout du CSS)
+  - inserer_barre : barre d'outils du porte plume à insérer (forum ou edition par défaut)
+  - previsualisation : si égale à 'oui', ajoute l'onglet de prévisualisation
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+
+  Exemple d'appel :
+       [(#SAISIE{textarea, couleur_foncee,
+               label=<:spa:couleur_foncee:>,
+               obligatoire=non})]
+]
+
+[(#REM) Si la valeur est un tableau, le plugin sait le transformer en chaine, plutôt que d'afficher "Array" ]
+#SET{valeur, #ENV{valeur_forcee,#ENV{valeur,#ENV{defaut}}}}
+#SET{valeur, #GET{valeur}|is_array|?{(#GET{valeur}|saisies_tableau2chaine), #GET{valeur}}}
+<textarea name="#ENV{nom}" class="[(#ENV{class}) ][inserer_barre_(#ENV{inserer_barre}) ][(#ENV{previsualisation}|oui)inserer_previsualisation]" id="champ_[(#ENV{nom}|saisie_nom2classe)]" rows="[(#ENV{rows,20})]" cols="[(#ENV{cols,40})]"[ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"][(#ENV{obligatoire}|et{#ENV{obligatoire}!={non}}|et{#HTML5}|oui) required="required"][ (#ENV*{attributs})]>#GET{valeur}</textarea>
diff --git a/www/plugins/saisies/saisies/textarea.yaml b/www/plugins/saisies/saisies/textarea.yaml
new file mode 100644 (file)
index 0000000..e0cd046
--- /dev/null
@@ -0,0 +1,140 @@
+
+titre: '<:saisies:saisie_textarea_titre:>'
+description: '<:saisies:saisie_textarea_explication:>'
+icone: 'images/saisies_textarea.png'
+options:
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'description'
+      label: '<:saisies:option_groupe_description:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'label'
+          label: '<:saisies:option_label_label:>'
+          explication: '<:saisies:option_label_explication:>'
+          size: 50
+      -
+        saisie: 'textarea'
+        options:
+          nom: 'defaut'
+          label: '<:saisies:option_defaut_label:>'
+          rows: 4
+      -
+        saisie: 'input'
+        options:
+          nom: 'explication'
+          label: '<:saisies:option_explication_label:>'
+          explication: '<:saisies:option_explication_explication:>'
+          size: 50
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'utilisation'
+      label: '<:saisies:option_groupe_utilisation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable'
+          label: '<:saisies:option_disable_label:>'
+          explication: '<:saisies:option_disable_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'disable_avec_post'
+          label: '<:saisies:option_disable_avec_post_label:>'
+          explication: '<:saisies:option_disable_avec_post_explication:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'readonly'
+          label: '<:saisies:option_readonly_label:>'
+          explication: '<:saisies:option_readonly_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'affichage'
+      label: '<:saisies:option_groupe_affichage:>'
+    saisies:
+      -
+        saisie: 'input'
+        options:
+          nom: 'attention'
+          label: '<:saisies:option_attention_label:>'
+          explication: '<:saisies:option_attention_explication:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'info_obligatoire'
+          label: '<:saisies:option_info_obligatoire_label:>'
+          explication: '<:saisies:option_info_obligatoire_explication:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'class'
+          label: '<:saisies:option_class_label:>'
+          size: 50
+      -
+        saisie: 'input'
+        options:
+          nom: 'rows'
+          label: '<:saisies:option_rows_label:>'
+          explication: '<:saisies:option_rows_explication:>'
+        verifier:
+          type: 'entier'
+          options:
+            min: 1
+      -
+        saisie: 'input'
+        options:
+          nom: 'cols'
+          label: '<:saisies:option_cols_label:>'
+          explication: '<:saisies:option_cols_explication:>'
+        verifier:
+          type: 'entier'
+          options:
+            min: 1
+      -
+        saisie: 'selection'
+        options:
+          nom: 'inserer_barre'
+          label: '<:saisies:option_inserer_barre_label:>'
+          explication: '<:saisies:option_inserer_barre_explication:>'
+          option_intro: <:item_non:>
+          datas:
+            edition: '<:saisies:option_inserer_barre_choix_edition:>'
+            forum: '<:saisies:option_inserer_barre_choix_forum:>'
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'previsualisation'
+          label: '<:saisies:option_previsualisation_label:>'
+          explication: '<:saisies:option_previsualisation_explication:>'
+  -
+    saisie: 'fieldset'
+    options:
+      nom: 'validation'
+      label: '<:saisies:option_groupe_validation:>'
+    saisies:
+      -
+        saisie: 'oui_non'
+        options:
+          nom: 'obligatoire'
+          label: '<:saisies:option_obligatoire_label:>'
+      -
+        saisie: 'input'
+        options:
+          nom: 'erreur_obligatoire'
+          label: '<:saisies:option_erreur_obligatoire_label:>'
+          explication: '<:saisies:option_erreur_obligatoire_explication:>'
+defaut:
+  options:
+    label: '<:saisies:saisie_textarea_titre:>'
+    cols: 40
+    rows: 5
+    # champs extras (definition du champ sql)
+    sql: "text DEFAULT '' NOT NULL"
diff --git a/www/plugins/saisies/saisies/true_false.html b/www/plugins/saisies/saisies/true_false.html
new file mode 100644 (file)
index 0000000..ebb3496
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM) 
+
+  Action :
+  - Rempli "true" si oui, "false" si non.
+  
+  Parametres :
+  - defaut : valeur par defaut si pas présente dans l'environnement
+  - valeur_forcee : valeur utilisee meme si une valeur est dans l'environnement
+  
+  Exemple d'appel :
+       [(#SAISIE{true_false, afficher_liste,
+               label=<:plugin:afficher_liste:>,
+               explication=<:plugin:explication_afficher_liste:>})]
+]
+#SET{valeur,#ENV{valeur_forcee,#ENV{valeur}}|is_null|?{#ENV{defaut},#ENV{valeur_forcee,#ENV{valeur}}}}
+<div class="choix">
+       <input type="radio" name="#ENV{nom}" class="radio" id='champ_[(#ENV{nom}|saisie_nom2classe)]_true'[ (#GET{valeur}|=={true}|oui)checked='checked'] value='true' [ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"] />
+       <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_true">[(#GET{valeur}|=={true}|oui)<strong>]<:item_oui:>[(#GET{valeur}|=={true}|oui)</strong>]</label>
+</div>
+<div class="choix">
+       <input type="radio" name="#ENV{nom}" class="radio" id='champ_[(#ENV{nom}|saisie_nom2classe)]_false'[ (#GET{valeur}|=={false}|oui)checked='checked'] value='false' [ disabled="(#ENV{disable})"][ readonly="(#ENV{readonly})"] />
+       <label for="champ_[(#ENV{nom}|saisie_nom2classe)]_false">[(#GET{valeur}|=={false}|oui)<strong>]<:item_non:>[(#GET{valeur}|=={false}|oui)</strong>]</label>
+</div>
diff --git a/www/plugins/saisies/saisies/url.html b/www/plugins/saisies/saisies/url.html
new file mode 100644 (file)
index 0000000..6ec595a
--- /dev/null
@@ -0,0 +1,12 @@
+[(#REM) \r
+               \r
+               Zone de saisie d'URL. Sur les sites en HTML5, utilise type="url"\r
+               sur le input (et donc class="url"), et type="text" par défaut\r
+               pour les autres (et donc class="text"). Dans ce dernier cas, on\r
+               renseigne quand même class="url" pour avoir une classe cohérente\r
+               avec ou sans HTML5.\r
+               \r
+][(#INCLURE{fond=saisies/input,\r
+                       env,\r
+            type=#HTML5|?{url,text},\r
+            class=[(#HTML5|?{[(#ENV{class}) ],[(#ENV{class}) ]url})]})]\r
diff --git a/www/plugins/saisies/saisies_fonctions.php b/www/plugins/saisies/saisies_fonctions.php
new file mode 100644 (file)
index 0000000..b022955
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+include_spip('inc/saisies');
+include_spip('balise/saisie');
+// picker_selected (spip 3)
+include_spip('formulaires/selecteur/generique_fonctions');
+
+
+/**
+ * Passer un nom en une valeur compatible avec une classe css
+ * toto => toto,
+ * toto/truc => toto_truc,
+ * toto[truc] => toto_truc,
+**/
+function saisie_nom2classe($nom) {
+       return str_replace(array('/', '[', ']', '&#91;', '&#93;'), array('_', '_', '', '_', ''), $nom);
+}
+
+/**
+ * Passer un nom en une valeur compatible avec un name de formulaire
+ * toto => toto,
+ * toto/truc => toto[truc],
+ * toto[truc] => toto[truc],
+**/
+function saisie_nom2name($nom) {
+       if (false === strpos($nom, '/')) {
+               return $nom;
+       }
+       $nom = explode('/', $nom);
+       $premier = array_shift($nom);
+       $nom = implode('][', $nom);
+       return $premier . '[' . $nom . ']';
+}
+
+/**
+ * Balise beurk #GLOBALS{debut_intertitre}
+ * qui retourne la globale PHP du même nom si elle existe
+ *
+ * @param array $p
+ *             Pile au niveau de la balise
+ * @return array
+ *             Pile complétée du code php de la balise.
+**/
+function balise_GLOBALS_dist($p) {
+       if (function_exists('balise_ENV'))
+               return balise_ENV($p, '$GLOBALS');
+       else
+               return balise_ENV_dist($p, '$GLOBALS');
+}
+
+/**
+ * Liste les éléments du sélecteur générique triés
+ *
+ * Les éléments sont triés par objets puis par identifiants
+ * 
+ * @example
+ *     L'entrée :
+ *     'rubrique|3,rubrique|5,article|2'
+ *     Retourne :
+ *     array(
+ *        0 => array('objet'=>'article', 'id_objet' => 2),
+ *        1 => array('objet'=>'rubrique', 'id_objet' => 3),
+ *        2 => array('objet'=>'rubrique', 'id_objet' => 5),
+ *     )
+ *
+ * @param string $selected
+ *     Liste des objets sélectionnés
+ * @return array
+ *     Liste des objets triés
+**/
+function picker_selected_par_objet($selected) {
+       $res = array();
+       $liste = picker_selected($selected);
+       // $liste : la sortie dans le désordre
+       if (!$liste) {
+               return $res;
+       }
+
+       foreach ($liste as $l) {
+               if (!isset($res[ $l['objet'] ])) {
+                       $res[ $l['objet'] ] = array();
+               }
+               $res[$l['objet']][] = $l['id_objet'];
+       }
+       // $res est trié par objet, puis par identifiant
+       ksort($res);
+       foreach ($res as $objet => $ids) {
+               sort($res[$objet]);
+       }
+
+       // on remet tout en file
+       $liste = array();
+       foreach ($res as $objet=>$ids) {
+               foreach ($ids as $id) {
+                       $liste[] = array('objet' => $objet, 'id_objet' => $id);
+               }
+       }
+
+       return $liste;
+}
+?>
diff --git a/www/plugins/saisies/saisies_options.php b/www/plugins/saisies/saisies_options.php
new file mode 100644 (file)
index 0000000..fa2590f
--- /dev/null
@@ -0,0 +1,48 @@
+<?php
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/*
+ * une fonction qui regarde si $texte est une chaine de langue
+ * de la forme <:qqch:>
+ * si oui applique _T()
+ * si non applique typo() suivant le mode choisi
+ *
+ * @param mixed $valeur
+ *     Une valeur à tester. Si c'est un tableau, la fonction s'appliquera récursivement dessus.
+ * @param string $mode_typo
+ *     Le mode d'application de la fonction typo(), avec trois valeurs possibles "toujours", "jamais" ou "multi".
+ * @return mixed
+ *     Retourne la valeur éventuellement modifiée.
+ */
+if (!function_exists('_T_ou_typo')){
+       function _T_ou_typo($valeur, $mode_typo='toujours') {
+               // Si la valeur est bien une chaine (et pas non plus un entier déguisé)
+               if (is_string($valeur) and !intval($valeur)){
+                       // Si la chaine est du type <:truc:> on passe à _T()
+                       if (preg_match('/^\<:(.*?):\>$/', $valeur, $match)) 
+                               $valeur = _T($match[1]);
+                       // Sinon on la passe a typo()
+                       else {
+                               if (!in_array($mode_typo, array('toujours', 'multi', 'jamais')))
+                                       $mode_typo = 'toujours';
+                       
+                               if ($mode_typo == 'toujours' or ($mode_typo == 'multi' and strpos($valeur, '<multi>') !== false)){
+                                       include_spip('inc/texte');
+                                       $valeur = typo($valeur);
+                               }
+                       }
+               }
+               // Si c'est un tableau, on reapplique la fonction récursivement
+               elseif (is_array($valeur)){
+                       foreach ($valeur as $cle => $valeur2){
+                               $valeur[$cle] = _T_ou_typo($valeur2, $mode_typo);
+                       }
+               }
+
+               return $valeur;
+       }
+}
+
+?>
diff --git a/www/plugins/saisies/saisies_pipelines.php b/www/plugins/saisies/saisies_pipelines.php
new file mode 100644 (file)
index 0000000..bccdea0
--- /dev/null
@@ -0,0 +1,92 @@
+<?php\r
+\r
+// Sécurité\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+function saisies_header_prive($flux){\r
+       $js = find_in_path('javascript/saisies.js');\r
+       $flux .= "\n<script type='text/javascript' src='$js'></script>\n";\r
+       $css = generer_url_public('saisies.css');\r
+       $flux .= "\n<link rel='stylesheet' href='$css' type='text/css' media='all' />\n";\r
+       $css_constructeur = find_in_path('css/formulaires_constructeur.css');\r
+       $flux .= "\n<link rel='stylesheet' href='$css_constructeur' type='text/css' />\n";\r
+       return $flux;\r
+}\r
+\r
+function saisies_affichage_final($flux){\r
+       if (($p = strpos($flux,"<!--!inserer_saisie_editer-->"))!==false){\r
+               // On insère la CSS devant le premier <link> trouvé\r
+               if (!$pi = strpos($flux, "<link") AND !$pi=strpos($flux, '</head'))\r
+                       $pi = $p; // si pas de <link inserer comme un goret entre 2 <li> de saisies\r
+               $css = generer_url_public('saisies.css');\r
+               $ins_css = "\n<link rel='stylesheet' href='$css' type='text/css' media='all' />\n";\r
+               $flux = substr_replace($flux, $ins_css, $pi, 0);\r
+               \r
+               // On insère le JS à la fin du <head>\r
+               $pos_head = strpos($flux, '</head');\r
+               $js = find_in_path('javascript/saisies.js');\r
+               $ins_js = "\n<script type='text/javascript' src='$js'></script>\n";\r
+               $flux = substr_replace($flux, $ins_js, $pos_head, 0);\r
+       }\r
+       return $flux;\r
+}\r
+\r
+// Déclaration des pipelines\r
+function saisies_saisies_autonomes($flux) { return $flux; }\r
+function saisies_formulaire_saisies($flux) { return $flux; }\r
+\r
+// Déclarer automatiquement les champs d'un CVT si on les trouve dans un tableau de saisies et s'ils ne sont pas déjà déclarés\r
+function saisies_formulaire_charger($flux){\r
+       // Si le flux data est inexistant, on quitte : Le CVT d'origine a décidé de ne pas continuer\r
+       if (!is_array($flux['data'])){\r
+               return $flux;\r
+       }\r
+       \r
+       // Il faut que la fonction existe et qu'elle retourne bien un tableau\r
+       if (include_spip('inc/saisies')\r
+               and $saisies = saisies_chercher_formulaire($flux['args']['form'], $flux['args']['args'])\r
+       ){\r
+               // On ajoute au contexte les champs à déclarer\r
+               $contexte = saisies_lister_valeurs_defaut($saisies);\r
+               $flux['data'] = array_merge($contexte, $flux['data']);\r
+\r
+               // On ajoute le tableau complet des saisies\r
+               $flux['data']['_saisies'] = $saisies;\r
+       }\r
+       return $flux;\r
+}\r
+\r
+// Aiguiller CVT vers un squelette propre à Saisies lorsqu'on a déclaré des saisies et qu'il n'y a pas déjà un HTML\r
+function saisies_styliser($flux){\r
+       // Si on cherche un squelette de formulaire\r
+       if (strncmp($flux['args']['fond'],'formulaires/',12)==0\r
+               // Et qu'il y a des saisies dans le contexte\r
+               and isset($flux['args']['contexte']['_saisies'])\r
+               // Et que le fichier choisi est vide ou n'existe pas\r
+               and include_spip('inc/flock')\r
+               and $ext = $flux['args']['ext']\r
+               and lire_fichier($flux['data'].'.'.$ext, $contenu_squelette)\r
+               and !trim($contenu_squelette)\r
+       ){\r
+               $flux['data'] = preg_replace("/\.$ext$/", '', find_in_path("formulaires/inc-saisies-cvt.$ext"));\r
+       }\r
+       \r
+       return $flux;\r
+}\r
+\r
+// Ajouter les vérifications déclarées dans la fonction "saisies" du CVT\r
+function saisies_formulaire_verifier($flux){\r
+       // Il faut que la fonction existe et qu'elle retourne bien un tableau\r
+       if (include_spip('inc/saisies') and $saisies = saisies_chercher_formulaire($flux['args']['form'], $flux['args']['args'])){\r
+               // On ajoute au contexte les champs à déclarer\r
+               $erreurs = saisies_verifier($saisies);\r
+               if ($erreurs and !isset($erreurs['message_erreur']))\r
+                       $erreurs['message_erreur'] = _T('saisies:erreur_generique');\r
+               $flux['data'] = array_merge($erreurs, $flux['data']);\r
+       }\r
+\r
+\r
+       return $flux;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/saisies/svn.revision b/www/plugins/saisies/svn.revision
new file mode 100644 (file)
index 0000000..87cc17d
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/saisies
+Revision: 73152
+Dernier commit: 2013-06-01 05:45:11 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/saisies</origine>
+<revision>73152</revision>
+<commit>2013-06-01 05:45:11 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/saisies/test/configurer_saisie.html b/www/plugins/saisies/test/configurer_saisie.html
new file mode 100644 (file)
index 0000000..aa3cb37
--- /dev/null
@@ -0,0 +1,51 @@
+<html>
+<head>
+       <title>Test de configuration de saisie</title>
+       [<link rel="stylesheet" href="(#CHEMIN{spip_formulaires.css})" type="text/css" media="all" title="formulaires" charset="utf-8" />]
+       <style type="text/css">
+               .formulaire_spip{
+                       width:40%;
+                       border:1px solid black;
+                       -moz-border-radius:10px;
+                       -webkit-border-radius:10px;
+                       border-radius:10px;
+               }
+               .formulaire_spip ul li{
+                       padding:0.5em;
+               }
+               .formulaire_spip li.fieldset{
+                       padding:0;
+               }
+               .formulaire_spip li.obligatoire{
+                       background:#ffcfcf;
+               }
+               .formulaire_spip .fieldset .legend{
+                       margin:0;
+                       font-style:italic;
+               }
+       </style>
+</head>
+<body>
+       <h1>Test pour générer le formulaire de configuration d'une saisie</h1>
+       
+       <h2>Par defaut, sans configuration du nom du champ</h2>
+       <form class="formulaire_spip" action="#SELF" method="post">
+               <ul>
+                       #CONFIGURER_SAISIE{#ENV{saisie, input}}
+                       <li class="boutons">
+                               <input type="submit" class="submit" />
+                       </li>
+               </ul>
+       </form>
+       
+       <h2>En forçant la configuration du nom</h2>
+       <form class="formulaire_spip" action="#SELF" method="post">
+               <ul>
+                       #CONFIGURER_SAISIE{#ENV{saisie, input}, avec_nom=oui}
+                       <li class="boutons">
+                               <input type="submit" class="submit" />
+                       </li>
+               </ul>
+       </form>
+</body>
+</html>
diff --git a/www/plugins/saisies/test/generer_saisies.html b/www/plugins/saisies/test/generer_saisies.html
new file mode 100644 (file)
index 0000000..4398eb6
--- /dev/null
@@ -0,0 +1,152 @@
+<html>
+<head>
+       <title>Test de génération de saisies</title>
+       [<link rel="stylesheet" href="(#CHEMIN{spip_formulaires.css})" type="text/css" media="all" title="formulaires" charset="utf-8" />]
+       <style type="text/css">
+               .formulaire_spip{
+                       width:40%;
+                       border:1px solid black;
+                       -moz-border-radius:10px;
+                       -webkit-border-radius:10px;
+                       border-radius:10px;
+               }
+               .formulaire_spip ul li{
+                       padding:0.5em;
+               }
+               .formulaire_spip li.fieldset{
+                       padding:0;
+               }
+               .formulaire_spip li.obligatoire{
+                       background:#ffcfcf;
+               }
+               .formulaire_spip .fieldset .legend{
+                       margin:0;
+                       font-style:italic;
+               }
+       </style>
+</head>
+<body>
+       <h1>Test pour générer des saisies à partir d'une description</h1>
+
+       <h2>Génération d'une seule saisie</h2>
+       #SET{champ,
+               #ARRAY{
+                       saisie, input,
+                       options, #ARRAY{
+                               nom, test,
+                               label, Une sorte de titre,
+                               explication, Un sorte d'explication,
+                               obligatoire, oui
+                       }
+               }
+       }
+       <form class="formulaire_spip" action="#SELF" method="post">
+               <ul>
+                       [(#GET{champ}|saisies_generer_html{#ENV**|unserialize})]
+                       <li class="boutons">
+                               <input type="submit" class="submit" />
+                       </li>
+               </ul>
+       </form>
+
+       <h2>Génération complète du contenu (l'intérieur) d'un formulaire</h2>
+       #SET{saisies,
+               #ARRAY{
+                       0,#ARRAY{
+                               saisie, destinataires,
+                               options, #ARRAY{
+                                       nom, destinataires,
+                                       label, Destinataires,
+                                       choix_destinataires, #ARRAY{0,1,1,2},
+                                       type_choix, plusieurs,
+                                       obligatoire, oui
+                               }
+                       },
+                       1,#ARRAY{
+                               saisie, input,
+                               options, #ARRAY{
+                                       nom, prenom,
+                                       label, Prénom,
+                               }
+                       },
+                       2,#ARRAY{
+                               saisie, input,
+                               options, #ARRAY{
+                                       nom, nom,
+                                       label, Nom,
+                                       obligatoire, oui
+                               }
+                       },
+                       3,#ARRAY{
+                               saisie, input,
+                               options, #ARRAY{
+                                       nom, courriel,
+                                       label, Courriel,
+                                       obligatoire, oui
+                               },
+                               verifier, #ARRAY{
+                                       type, email
+                               }
+                       },
+                       4,#ARRAY{
+                               saisie, case,
+                               options, #ARRAY{
+                                       nom, case,
+                                       label, Une sorte de case à cocher,
+                                       label_case, Check la vibes
+                               }
+                       },
+                       5,#ARRAY{
+                               saisie, fieldset,
+                               options, #ARRAY{
+                                       nom, adresse,
+                                       label, Adresse
+                               },
+                               saisies, #ARRAY{
+                                       1,#ARRAY{
+                                               saisie, textarea,
+                                               options, #ARRAY{
+                                                       nom, voie,
+                                                       label, Voie,
+                                                       obligatoire, non,
+                                               }
+                                       },
+                                       2,#ARRAY{
+                                               saisie, input,
+                                               options, #ARRAY{
+                                                       nom, code_postal,
+                                                       label, Code postal,
+                                                       obligatoire, oui
+                                               }
+                                       },
+                                       3,#ARRAY{
+                                               saisie, input,
+                                               options, #ARRAY{
+                                                       nom, ville,
+                                                       label, Ville,
+                                                       obligatoire, oui
+                                               }
+                                       }
+                               }
+                       },
+                       6,#ARRAY{
+                               saisie, oui_non,
+                               options, #ARRAY{
+                                       nom, peutetre,
+                                       label, Tu veux ou tu veux pas ?,
+                                       obligatoire, oui,
+                                       info_obligatoire, " / obligatoire"
+                               }
+                       },
+               }
+       }
+       <form class="formulaire_spip" action="#SELF" method="post">
+               <ul>
+                       #GENERER_SAISIES{#GET{saisies}}
+                       <li class="boutons">
+                               <input type="submit" class="submit" />
+                       </li>
+               </ul>
+       </form>
+</body>
+</html>
diff --git a/www/plugins/saisies/test/saisie.html b/www/plugins/saisies/test/saisie.html
new file mode 100644 (file)
index 0000000..899d81a
--- /dev/null
@@ -0,0 +1,11 @@
+Version PHP : <?php echo phpversion(); ?>
+
+
+<h1>Input</h1>
+[(#SAISIE{input,titre})]
+
+<h1>Textarea</h1>
+[(#SAISIE{textarea,texte})]
+
+<h1>Input obligatoire et label</h1>
+[(#SAISIE{input,titre,obligatoire=oui,label=Un vrai titre})]
diff --git a/www/plugins/saisies/test/voir_saisie.html b/www/plugins/saisies/test/voir_saisie.html
new file mode 100644 (file)
index 0000000..d72f830
--- /dev/null
@@ -0,0 +1,10 @@
+<h1>Input et label</h1>
+[(#VOIR_SAISIE{input,titre,label=Un vrai titre,valeur=TRUC})]
+
+<h1>Textarea</h1>
+[(#VOIR_SAISIE{textarea,texte,valeur=Un super long texte<br/>sur plusieurs ligne})]
+
+<h1>Destinataires</h1>
+[(#VOIR_SAISIE{destinataires,destinataires, label=Destinataires,valeur=#ARRAY{0,1,1,2}})]
+
+
diff --git a/www/plugins/saisies/test/voir_saisies.html b/www/plugins/saisies/test/voir_saisies.html
new file mode 100644 (file)
index 0000000..3d7c50f
--- /dev/null
@@ -0,0 +1,147 @@
+<html>
+<head>
+       <title>Test de génération des vues de saisies</title>
+       [<link rel="stylesheet" href="(#CHEMIN{spip_formulaires.css})" type="text/css" media="all" title="formulaires" charset="utf-8" />]
+       <style type="text/css">
+               .formulaire_spip{
+                       width:40%;
+                       border:1px solid black;
+                       -moz-border-radius:10px;
+                       -webkit-border-radius:10px;
+                       border-radius:10px;
+               }
+               .formulaire_spip ul li{
+                       padding:0.5em;
+               }
+               .formulaire_spip li.fieldset{
+                       padding:0;
+               }
+               .formulaire_spip li.obligatoire{
+                       background:#ffcfcf;
+               }
+               .formulaire_spip .fieldset .legend{
+                       margin:0;
+                       font-style:italic;
+               }
+       </style>
+</head>
+<body>
+       <h1>Générer des vues de saisie</h1>
+
+       #SET{saisies,
+               #ARRAY{
+                       0,#ARRAY{
+                               saisie, destinataires,
+                               options, #ARRAY{
+                                       nom, destinataires,
+                                       label, Destinataires,
+                                       choix_destinataires, #ARRAY{0,1,1,2},
+                                       type_choix, plusieurs,
+                                       obligatoire, oui
+                               }
+                       },
+                       1,#ARRAY{
+                               saisie, input,
+                               options, #ARRAY{
+                                       nom, prenom,
+                                       label, Prénom,
+                               }
+                       },
+                       2,#ARRAY{
+                               saisie, input,
+                               options, #ARRAY{
+                                       nom, nom,
+                                       label, Nom,
+                                       obligatoire, oui
+                               }
+                       },
+                       3,#ARRAY{
+                               saisie, input,
+                               options, #ARRAY{
+                                       nom, courriel,
+                                       label, Courriel,
+                                       obligatoire, oui
+                               },
+                               verifier, #ARRAY{
+                                       type, email
+                               }
+                       },
+                       4,#ARRAY{
+                               saisie, case,
+                               options, #ARRAY{
+                                       nom, case,
+                                       label, Une sorte de case à cocher,
+                                       label_case, Check la vibes
+                               }
+                       },
+                       5,#ARRAY{
+                               saisie, fieldset,
+                               options, #ARRAY{
+                                       nom, adresse,
+                                       label, Adresse
+                               },
+                               saisies, #ARRAY{
+                                       1,#ARRAY{
+                                               saisie, textarea,
+                                               options, #ARRAY{
+                                                       nom, voie,
+                                                       label, Voie,
+                                                       obligatoire, non,
+                                               }
+                                       },
+                                       2,#ARRAY{
+                                               saisie, input,
+                                               options, #ARRAY{
+                                                       nom, code_postal,
+                                                       label, Code postal,
+                                                       obligatoire, oui
+                                               }
+                                       },
+                                       3,#ARRAY{
+                                               saisie, input,
+                                               options, #ARRAY{
+                                                       nom, ville,
+                                                       label, Ville,
+                                                       obligatoire, oui
+                                               }
+                                       }
+                               }
+                       },
+                       6,#ARRAY{
+                               saisie, oui_non,
+                               options, #ARRAY{
+                                       nom, peutetre,
+                                       label, Tu veux ou tu veux pas ?,
+                                       obligatoire, oui,
+                                       info_obligatoire, " / obligatoire"
+                               }
+                       },
+               }
+       }
+
+       <h2>Formulaire auquel on doit répondre</h2>
+       <div class="formulaire_spip">
+       <ul>
+       #GENERER_SAISIES{#GET{saisies}}
+       </ul>
+       </div>
+
+
+       #SET{valeurs,
+               #ARRAY{
+                       case, on,
+                       peutetre, '',
+                       prenom, Jean-Paul,
+                       code_postal, 22222,
+                       nom, Fitousi,
+                       ville, Deuville,
+                       courriel, robert@menard.com,
+                       destinataires, #ARRAY{1,1},
+                       voie, 2 rue du Deux,
+               }
+       }
+
+       <h2>Réponse à ce formulaire</h2>
+       #VOIR_SAISIES{#GET{saisies}, #GET{valeurs}}
+</body>
+</html>
diff --git a/www/plugins/seo-v1/action/editer_seo.php b/www/plugins/seo-v1/action/editer_seo.php
new file mode 100644 (file)
index 0000000..62d741a
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * @return array
+ */
+function action_editer_seo_dist(){
+       include_spip('inc/autoriser');
+       $err = "";
+
+       // si id_article n'est pas un nombre, c'est une creation 
+       // mais on verifie qu'on a toutes les donnees qu'il faut.
+       if (!$id_objet = _request('id_objet') OR !$objet = _request('objet')){
+               $err = "Pas d'objet ou id_objet";
+       } else {
+               if (!autoriser('modifier', $objet, $id_objet)){
+                       $err = "Error auth :(";
+               } else {
+                       $meta_tags = array('title', 'description', 'author', 'keywords', 'copyright', 'robots');
+                       sql_delete("spip_seo", "id_objet = " . intval($id_objet) . " AND objet =" . sql_quote($objet));
+                       foreach ($meta_tags as $tag){
+                               if (($value = _request($tag)) && (strlen($value)>0)){
+                                       sql_insertq('spip_seo', array('id_objet' => $id_objet, 'objet' => $objet, 'meta_name' => $tag, 'meta_content' => $value));
+                               }
+                       }
+               }
+       }
+
+       if ($err)
+               spip_log("echec editeur seo: $err", _LOG_ERREUR);
+
+       return array(array($objet, $id_objet), $err);
+}
+
+?>
diff --git a/www/plugins/seo-v1/base/seo_tables.php b/www/plugins/seo-v1/base/seo_tables.php
new file mode 100644 (file)
index 0000000..1f9337f
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function seo_declarer_tables_interfaces($interface){
+       $interface['table_des_tables']['seo'] = 'seo';
+
+       return $interface;
+}
+
+function seo_declarer_tables_principales($tables_principales){
+       //-- Table SEO -----------------------------------------------------
+       $seo = array(
+               'id_objet' => "int(11) NOT NULL",
+               'objet' => "varchar(10) NOT NULL",
+               'meta_name' => "varchar(20) NOT NULL",
+               'meta_content' => "text NOT NULL"
+       );
+
+       $seo_cles = array(
+               "PRIMARY KEY" => "id_objet, objet, meta_name"
+       );
+
+       $tables_principales['spip_seo'] = array(
+               'field' => &$seo,
+               'key' => &$seo_cles
+       );
+
+       return $tables_principales;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/exec/seo_config.php b/www/plugins/seo-v1/exec/seo_config.php
new file mode 100644 (file)
index 0000000..94ff0eb
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+/**
+ * BouncingOrange SPIP SEO plugin
+ *
+ * @category   SEO
+ * @package    SPIP_SEO
+ * @author     Pierre ROUSSET (p.rousset@gmail.com)
+ * @copyright  Copyright (c) 2009 BouncingOrange (http://www.bouncingorange.com)
+ * @license    http://opensource.org/licenses/gpl-2.0.php  General Public License (GPL 2.0)
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+function exec_seo_config(){
+
+       if (!autoriser('configurer', 'configuration')){
+               include_spip('inc/minipres');
+               echo minipres();
+               exit();
+       }
+
+       ///// PAGE /////
+
+       $titre_page = _T('icone_configuration_site');
+       $rubrique = 'configuration';
+       $sous_rubrique = 'seo';
+
+       $commencer_page = charger_fonction('commencer_page', 'inc');
+       echo($commencer_page(_T('seo:seo') . ' - ' . $titre_page, $rubrique, $sous_rubrique));
+
+       $page_result = ''
+               . '<br /><br /><br />'
+               . gros_titre(_T('titre_page_config_contenu'), '', false)
+               . barre_onglets($rubrique, $sous_rubrique)
+               . debut_gauche($rubrique, true)
+               . pipeline('affiche_gauche', array('args' => array('exec' => 'seo_config'), 'data' => ''))
+               . creer_colonne_droite($rubrique, true)
+               . pipeline('affiche_droite', array('args' => array('exec' => 'seo_config'), 'data' => ''))
+               . debut_droite($rubrique, true);
+
+       // Insert Head //
+
+       // Meta tag //
+
+       // Canonical URL //
+
+       // Google Webmaster Tools //
+
+       // Google Analytics //
+
+       $page_result .= recuperer_fond('prive/configurer_seo');
+
+       echo $page_result, pipeline('affiche_milieu', array('args' => array('exec' => $sous_rubrique), 'data' => '')), fin_gauche(), fin_page();
+}
+
+?>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_alexa.html b/www/plugins/seo-v1/formulaires/configurer_seo_alexa.html
new file mode 100644 (file)
index 0000000..f5f1c19
--- /dev/null
@@ -0,0 +1,36 @@
+<div class="formulaire_spip formulaire_config formulaire_#FORM">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <h3 class="legend">[(#CHEMIN{img_pack/alexa-24.png}|image_reduire{0,24})] <:seo:alexa:></h3>
+                               <ul>
+                                       <li class="editer editer_alexa_activate">
+                                               <label for="alexa_activate"><:seo:alexa_activate:></label>
+                                               <input type="checkbox" value="yes" name="activate" id="alexa_activate"[(#ENV{activate}|=={yes}|oui)checked="checked"] onChange="active_alexa(jQuery(this), jQuery('.editer_alexa_id'))"/>
+                                       </li>
+                                       <li class="editer editer_alexa_id">
+                                               <label for="alexa_id"><:seo:alexa_id:></label>
+                                               <input type="text" name="alexa_id" value="#ENV{alexa_id}" id="alexa_id" class="text" />
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+</form>
+<script type="text/javascript">
+       function active_alexa(checkbox, form) {
+               checkbox.is(':checked') ? form.slideDown()  : form.slideUp();
+       }
+       [(#ENV{activate}|=={yes}|non)
+       jQuery('.editer_alexa_id').hide();]
+</script>
+</div>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_alexa.php b/www/plugins/seo-v1/formulaires/configurer_seo_alexa.php
new file mode 100644 (file)
index 0000000..9911534
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+function formulaires_configurer_seo_alexa_charger_dist(){
+
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $valeurs = isset($config['alexa']) ? $config['alexa'] : array('id' => '');
+       $valeurs['alexa_id'] = $valeurs['id'];
+       
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('configurer', 'configuration')) {
+               $valeurs['editable'] = false;
+       }
+       
+       return $valeurs;
+}
+
+function formulaires_configurer_seo_alexa_traiter_dist(){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (!isset($config['alexa'])) {
+               $config['alexa'] = array();
+       }
+       $config['alexa']['activate'] = _request('activate','no');
+       $config['alexa']['id'] = _request('alexa_id',''); 
+       $config = serialize($config);
+       ecrire_meta('seo',$config);
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+       return array('message_ok'=>_T('config_info_enregistree'),'editable'=>true);
+}
+?>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_bing.html b/www/plugins/seo-v1/formulaires/configurer_seo_bing.html
new file mode 100644 (file)
index 0000000..1817feb
--- /dev/null
@@ -0,0 +1,36 @@
+<div class="formulaire_spip formulaire_config formulaire_#FORM">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <h3 class="legend">[(#CHEMIN{img_pack/bing-24.png}|image_reduire{0,24})] <:seo:bing_webmaster:></h3>
+                               <ul>
+                                       <li class="editer editer_bing_activate">
+                                               <label for="bing_activate"><:seo:bing_webmaster_activate:></label>
+                                               <input type="checkbox" value="yes" name="activate" id="bing_activate"[(#ENV{activate}|=={yes}|oui)checked="checked"] onchange="active_bing(jQuery(this), jQuery('.editer_bing_id'))"/>
+                                       </li>
+                                       <li class="editer editer_bing_id">
+                                               <label for="bing_id"><:seo:bing_webmaster_id:></label>
+                                               <input type="text" name="bing_id" value="#ENV{bing_id}" id="bing_id" class="text" />
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+</form>
+<script type="text/javascript">
+       function active_bing(checkbox, form) {
+               jQuery(checkbox).is(':checked') ? form.slideDown()  : form.slideUp();
+       }
+       [(#ENV{activate}|=={yes}|non)
+       jQuery('.editer_bing_id').hide();]
+</script>
+</div>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_bing.php b/www/plugins/seo-v1/formulaires/configurer_seo_bing.php
new file mode 100644 (file)
index 0000000..3775148
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+function formulaires_configurer_seo_bing_charger_dist(){
+
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $valeurs = isset($config['bing']) ? $config['bing'] : array('id' => '');
+       $valeurs['bing_id'] = $valeurs['id'];
+       
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('configurer', 'configuration'))
+               $valeurs['editable'] = false;
+
+       return $valeurs;
+}
+
+function formulaires_configurer_seo_bing_traiter_dist(){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (!isset($config['bing']))
+               $config['bing'] = array();
+       $config['bing']['activate'] = _request('activate','no');
+       $config['bing']['id'] = _request('bing_id',''); 
+       $config = serialize($config);
+       ecrire_meta('seo',$config);
+       
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+       
+       return array('message_ok'=>_T('config_info_enregistree'),'editable'=>true);
+}
+?>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_ganalytics.html b/www/plugins/seo-v1/formulaires/configurer_seo_ganalytics.html
new file mode 100644 (file)
index 0000000..cb77d22
--- /dev/null
@@ -0,0 +1,36 @@
+<div class="formulaire_spip formulaire_config formulaire_#FORM">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <h3 class="legend">[(#CHEMIN{img_pack/google_analytics-24.png}|image_reduire{0,24})] <:seo:google_analytics:></h3>
+                               <ul>
+                                       <li class="editer editer_analytics_activate">
+                                               <label for="analytics_activate"><:seo:google_analytics_activate:></label>
+                                               <input type="checkbox" value="yes" name="activate" id="analytics_activate"[(#ENV{activate}|=={yes}|oui)checked="checked"] onChange="active_analytics(jQuery(this), jQuery('.editer_analytics_id'))"/>
+                                       </li>
+                                       <li class="editer editer_analytics_id">
+                                               <label for="analytics_id"><:seo:google_analytics_id:></label>
+                                               <input type="text" name="analytics_id" value="#ENV{analytics_id}" id="analytics_id" class="text" />
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+</form>
+<script type="text/javascript">
+       function active_analytics(checkbox, form) {
+               checkbox.is(':checked') ? form.slideDown()  : form.slideUp();
+       }
+       [(#ENV{activate}|=={yes}|non)
+       jQuery('.editer_analytics_id').hide();]
+</script>
+</div>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_ganalytics.php b/www/plugins/seo-v1/formulaires/configurer_seo_ganalytics.php
new file mode 100644 (file)
index 0000000..eafdf03
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+function formulaires_configurer_seo_ganalytics_charger_dist(){
+
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $valeurs = isset($config['analytics']) ? $config['analytics'] : array('id' => '') ;
+       $valeurs['analytics_id'] = $valeurs['id'];
+       
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('configurer', 'configuration')) {
+               $valeurs['editable'] = false;
+       }
+       
+       return $valeurs;
+}
+
+function formulaires_configurer_seo_ganalytics_traiter_dist(){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (!isset($config['analytics'])) {
+               $config['analytics'] = array();
+       }
+       $config['analytics']['activate'] = _request('activate','no');
+       $config['analytics']['id'] = _request('analytics_id',''); 
+       $config = serialize($config);
+       ecrire_meta('seo',$config);
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+       return array('message_ok'=>_T('config_info_enregistree'),'editable'=>true);
+}
+?>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_insert_head.html b/www/plugins/seo-v1/formulaires/configurer_seo_insert_head.html
new file mode 100644 (file)
index 0000000..0d9e647
--- /dev/null
@@ -0,0 +1,31 @@
+<div class="formulaire_spip formulaire_config formulaire_#FORM">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <h3 class="legend"><:seo:insert_head:></h3>
+                               <ul>
+                                       <li class="editer editer_insert_head_activate">
+                                               <p class="explication"><:seo:insert_head_descriptif:></p>
+                                               <label for="insert_head_activate"><:seo:insert_head_activate:></label>
+                                               <input type="checkbox" value="yes" name="activate" id="insert_head_activate"[(#ENV{activate}|=={yes}|oui)checked="checked"] />
+                                       </li>
+                                       <li class="editer editer_forcer_squelette">
+                                               <p class="explication"><:seo:forcer_squelette_descriptif:></p>
+                                               <label for="forcer_squelette"><:seo:forcer_squelette_label:></label>
+                                               <input type="checkbox" value="yes" name="forcer_squelette" id="forcer_squelette"[(#ENV{forcer_squelette}|=={yes}|oui)checked="checked"] />
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+</form>
+</div>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_insert_head.php b/www/plugins/seo-v1/formulaires/configurer_seo_insert_head.php
new file mode 100644 (file)
index 0000000..f0a1884
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+function formulaires_configurer_seo_insert_head_charger_dist(){
+
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $valeurs = $config['insert_head'];
+       $valeurs['forcer_squelette'] = $config['forcer_squelette'];
+
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('configurer', 'configuration')) {
+               $valeurs['editable'] = false;
+       }
+       
+       return $valeurs;
+}
+
+function formulaires_configurer_seo_insert_head_traiter_dist(){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (!isset($config['insert_head'])) {
+               $config['insert_head'] = array();
+       }
+       $config['insert_head']['activate'] = _request('activate','no');
+       $config['forcer_squelette'] = _request('forcer_squelette','no');
+       $config = serialize($config);
+       ecrire_meta('seo',$config);
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+       return array('message_ok'=>_T('config_info_enregistree'),'editable'=>true);
+}
+?>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_metas.html b/www/plugins/seo-v1/formulaires/configurer_seo_metas.html
new file mode 100644 (file)
index 0000000..d9fef1f
--- /dev/null
@@ -0,0 +1,132 @@
+<div class="formulaire_spip formulaire_config formulaire_#FORM">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <h3 class="legend">[(#CHEMIN{img_pack/meta_tags-24.png}|image_reduire{0,24})] <:seo:meta_tags:></h3>
+                               <ul>
+                                       <li class="editer editer_meta_tags_activate">
+                                               <label for="meta_tags_activate"><:seo:meta_tags_activate:></label>
+                                               <input type="checkbox" value="yes" name="activate" id="meta_tags_activate"[(#ENV{activate}|=={yes}|oui)checked="checked"] onChange="active_metas(jQuery(this), jQuery('#fieldset_activate_editing,#fieldset_sommaire,#fieldset_default'))"/>
+                                       </li>
+                                       <li class="fieldset" id="fieldset_activate_editing">
+                                               <h3 class="legend"><:seo:meta_tags_editing:></h3>
+                                               <ul>
+                                                       <li class="editer editer_meta_tags_activate_editing">
+                                                               <div class="choix">
+                                                               <input type="checkbox" value="yes" name="activate_editing" id="meta_tags_activate_editing"[(#ENV{activate_editing}|=={yes}|oui)checked="checked"] />
+                                                               <label for="meta_tags_activate_editing"><:seo:meta_tags_edit_activate:></label>
+                                                               </div>
+                                                       </li>
+                                               </ul>
+                                       </li>
+                                       <li class="fieldset" id="fieldset_sommaire">
+                                               <h3 class="legend"><:seo:meta_tags_sommaire:></h3>
+                                               <ul>
+                                                       <li class="editer editer_sommaire_title">
+                                                               <label for="title"><:seo:meta_title:></label>
+                                                               <input type="text" name="title" value="#ENV{title}" id="title" class="text" />
+                                                       </li>
+                                                       <li class="editer editer_sommaire_description">
+                                                               <label for="description"><:seo:meta_description:></label>
+                                                               <textarea name="description" id="description" type="text" class="text" rows="5">#ENV{description}</textarea>
+                                                       </li>
+                                                       <li class="editer editer_sommaire_keywords">
+                                                               <label for="keywords"><:seo:meta_keywords:></label>
+                                                               <input type="text" name="keywords" value="#ENV{keywords}" id="keywords" class="text" />
+                                                       </li>
+                                                       <li class="editer editer_sommaire_copyright">
+                                                               <label for="copyright"><:seo:meta_copyright:></label>
+                                                               <input type="text" name="copyright" value="#ENV{copyright}" id="copyright" class="text" />
+                                                       </li>
+                                                       <li class="editer editer_sommaire_auteur">
+                                                               <label for="author"><:seo:meta_author:></label>
+                                                               <input type="text" name="author" value="#ENV{author}" id="author" class="text" />
+                                                       </li>
+                                                       <li class="editer editer_sommaire_robots">
+                                                               <label for="robots"><:seo:meta_robots:></label>
+                                                               <select name="robots" id="robots" class="text">
+                                                                       <option #ENV{robots}|=={''}|oui)selected="selected"] value=""></option>
+                                                                       <option #ENV{robots}|=={'INDEX, FOLLOW'}|oui)selected="selected"] value="INDEX, FOLLOW">INDEX, FOLLOW</option>
+                                                                       <option #ENV{robots}|=={'INDEX, NOFOLLOW'}|oui)selected="selected"] value="INDEX, NOFOLLOW">INDEX, NOFOLLOW</option>
+                                                                       <option #ENV{robots}|=={'NOINDEX, FOLLOW'}|oui)selected="selected"] value="NOINDEX, FOLLOW">NOINDEX, FOLLOW</option>
+                                                                       <option #ENV{robots}|=={'NOINDEX, NOFOLLOW'}|oui)selected="selected"] value="NOINDEX, NOFOLLOW">NOINDEX, NOFOLLOW</option>
+                                                                       <option #ENV{robots}|=={'INDEX, FOLLOW, NOARCHIVE'}|oui)selected="selected"] value="INDEX, FOLLOW, NOARCHIVE">INDEX, FOLLOW, NOARCHIVE</option>
+                                                                       <option #ENV{robots}|=={'INDEX, NOFOLLOW, NOARCHIVE'}|oui)selected="selected"] value="INDEX, NOFOLLOW, NOARCHIVE">INDEX, NOFOLLOW, NOARCHIVE</option>
+                                                                       <option #ENV{robots}|=={'NOINDEX, NOFOLLOW, NOARCHIVE'}|oui)selected="selected"] value="NOINDEX, NOFOLLOW, NOARCHIVE">NOINDEX, NOFOLLOW, NOARCHIVE</option>
+                                                               </select>
+                                                       </li>
+                                               </ul>
+                                       </li>
+                                       <li class="fieldset" id="fieldset_default">
+                                               <h3 class="legend"><:seo:meta_tags_default:></h3>
+                                               <ul>
+                                                       <li class="editer editer_default_title">
+                                                               <label for="default_title"><:seo:meta_title:></label>
+                                                               <select name="default_title" id="default_title" class="text">
+                                                                       <option[(#ENV{default_title}|=={''}|oui)selected="selected"] value=""></option>'
+                                                                       <option[(#ENV{default_title}|=={'page'}|oui)selected="selected"] value="page"><:seo:meta_page_title_value:></option>
+                                                                       <option[(#ENV{default_title}|=={'sommaire'}|oui)selected="selected"] value="sommaire"><:seo:meta_sommaire_value:></option>
+                                                                       <option[(#ENV{default_title}|=={'page_sommaire'}|oui)selected="selected"] value="page_sommaire"><:seo:meta_page_title_sommaire_value:></option>
+                                                               </select>
+                                                       </li>
+                                                       <li class="editer editer_default_description">
+                                                               <label for="default_description"><:seo:meta_description:></label>
+                                                               <select name="default_description" id="default_description" class="text">
+                                                                       <option[(#ENV{default_description}|=={''}|oui)selected="selected"] value=""></option>'
+                                                                       <option[(#ENV{default_description}|=={'page'}|oui)selected="selected"] value="page"><:seo:meta_page_description_value:></option>
+                                                                       <option[(#ENV{default_description}|=={'sommaire'}|oui)selected="selected"] value="sommaire"><:seo:meta_sommaire_value:></option>
+                                                                       <option[(#ENV{default_description}|=={'page_sommaire'}|oui)selected="selected"] value="page_sommaire"><:seo:meta_page_description_sommaire_value:></option>
+                                                               </select>
+                                                       </li>
+                                                       <li class="editer editer_default_keywords">
+                                                               <label for="default_keywords"><:seo:meta_keywords:></label>
+                                                               <select name="default_keywords" id="default_keywords" class="text">
+                                                                       <option[(#ENV{default_keywords}|=={''}|oui)selected="selected"] value=""></option>'
+                                                                       <option[(#ENV{default_keywords}|=={'sommaire'}|oui)selected="selected"] value="sommaire"><:seo:meta_sommaire_value:></option>
+                                                               </select>
+                                                       </li>
+                                                       <li class="editer editer_default_copyright">
+                                                               <label for="default_copyright"><:seo:meta_copyright:></label>
+                                                               <select name="default_copyright" id="default_copyright" class="text">
+                                                                       <option[(#ENV{default_copyright}|=={''}|oui)selected="selected"] value=""></option>
+                                                                       <option[(#ENV{default_copyright}|=={'sommaire'}|oui)selected="selected"] value="sommaire"><:seo:meta_sommaire_value:></option>
+                                                               </select>
+                                                       </li>
+                                                       <li class="editer editer_default_author">
+                                                               <label for="default_author"><:seo:meta_author:></label>
+                                                               <select name="default_author" id="default_author" class="text">
+                                                                       <option[(#ENV{default_author}|=={''}|oui)selected="selected"] value=""></option>
+                                                                       <option[(#ENV{default_author}|=={'sommaire'}|oui)selected="selected"] value="sommaire"><:seo:meta_sommaire_value:></option>
+                                                               </select>
+                                                       </li>
+                                                       <li class="editer editer_default_robots">
+                                                               <label for="default_robots"><:seo:meta_robots:></label>
+                                                               <select name="default_robots" id="default_robots" class="text">
+                                                                       <option[(#ENV{default_robots}|=={''}|oui)selected="selected"] value=""></option>
+                                                                       <option[(#ENV{default_robots}|=={'sommaire'}|oui)selected="selected"] value="sommaire"><:seo:meta_sommaire_value:></option>
+                                                               </select>
+                                                       </li>
+                                               </ul>
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+</form>
+<script type="text/javascript">
+       function active_metas(checkbox, form) {
+               checkbox.is(':checked') ? form.slideDown()  : form.slideUp();
+       }
+       [(#ENV{activate}|=={yes}|non)
+       jQuery('#fieldset_activate_editing,#fieldset_sommaire,#fieldset_default').hide();]
+</script>
+</div>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_metas.php b/www/plugins/seo-v1/formulaires/configurer_seo_metas.php
new file mode 100644 (file)
index 0000000..0014040
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+function formulaires_configurer_seo_metas_charger_dist(){
+
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $valeurs = isset($config['meta_tags']) ? $config['meta_tags'] : array();
+       if(isset($valeurs['tag']) and is_array($valeurs['tag'])){
+               foreach($valeurs['tag'] as $tag => $val){
+                       $valeurs[$tag] = $val;
+                       unset($valeurs['tag'][$tag]);
+               }
+       }
+       if(isset($valeurs['default']) and is_array($valeurs['default'])){
+               foreach($valeurs['default'] as $tag => $val){
+                       $valeurs['default_'.$tag] = $val;
+                       unset($valeurs['default'][$tag]);
+               }
+       }
+       unset($valeurs['tag']);
+       unset($valeurs['default']);
+
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('configurer', 'configuration')) {
+               $valeurs['editable'] = false;
+       }
+       
+       return $valeurs;
+}
+
+function formulaires_configurer_seo_metas_traiter_dist(){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (!isset($config['meta_tags'])) {
+               $config['meta_tags'] = array();
+       }
+       $config['meta_tags']['activate'] = _request('activate','no');
+       $config['meta_tags']['activate_editing'] = _request('activate','no');
+       
+       $config['meta_tags']['tag']['title'] = _request('title');
+       $config['meta_tags']['tag']['description'] = _request('description');
+       $config['meta_tags']['tag']['keywords'] = _request('keywords');
+       $config['meta_tags']['tag']['copyright'] = _request('copyright');
+       $config['meta_tags']['tag']['author'] = _request('author');
+       $config['meta_tags']['tag']['robots'] = _request('robots');
+       
+       $config['meta_tags']['default']['title'] = _request('default_title');
+       $config['meta_tags']['default']['description'] = _request('default_description');
+       $config['meta_tags']['default']['keywords'] = _request('default_keywords');
+       $config['meta_tags']['default']['copyright'] = _request('default_copyright');
+       $config['meta_tags']['default']['author'] = _request('default_author');
+       $config['meta_tags']['default']['robots'] = _request('default_robots');
+       
+       $config = serialize($config);
+       ecrire_meta('seo',$config);
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+       return array('message_ok'=>_T('config_info_enregistree'),'editable'=>true);
+}
+?>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_urls_canoniques.html b/www/plugins/seo-v1/formulaires/configurer_seo_urls_canoniques.html
new file mode 100644 (file)
index 0000000..09819e6
--- /dev/null
@@ -0,0 +1,25 @@
+<div class="formulaire_spip formulaire_config formulaire_#FORM">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <h3 class="legend">[(#CHEMIN{img_pack/canonical_url-24.png}|image_reduire{0,24})] <:seo:canonical_url:></h3>
+                               <ul>
+                                       <li class="editer editer_canonical_url_activate">
+                                               <label for="canonical_url_activate"><:seo:canonical_url_activate:></label>
+                                               <input type="checkbox" value="yes" name="activate" id="canonical_url_activate"[(#ENV{activate}|=={yes}|oui)checked="checked"] />
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+</form>
+</div>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_urls_canoniques.php b/www/plugins/seo-v1/formulaires/configurer_seo_urls_canoniques.php
new file mode 100644 (file)
index 0000000..5f6cc87
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+function formulaires_configurer_seo_urls_canoniques_charger_dist(){
+
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $valeurs = isset($config['canonical_url']) ? $config['canonical_url'] : array();
+       
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('configurer', 'configuration')) {
+               $valeurs['editable'] = false;
+       }
+       
+       return $valeurs;
+}
+
+function formulaires_configurer_seo_urls_canoniques_traiter_dist(){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (!isset($config['canonical_url'])) {
+               $config['canonical_url'] = array();
+       }
+       $config['canonical_url']['activate'] = _request('activate','no');
+       $config = serialize($config);
+       ecrire_meta('seo',$config);
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+       return array('message_ok'=>_T('config_info_enregistree'),'editable'=>true);
+}
+?>
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_webmaster_tools.html b/www/plugins/seo-v1/formulaires/configurer_seo_webmaster_tools.html
new file mode 100644 (file)
index 0000000..113b541
--- /dev/null
@@ -0,0 +1,36 @@
+<div class="formulaire_spip formulaire_config formulaire_#FORM">
+
+[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+<form method="post" action="#ENV{action}">
+       <div>
+               #ACTION_FORMULAIRE{#ENV{action}}
+               <ul>
+                       <li class="fieldset">
+                               <h3 class="legend">[(#CHEMIN{img_pack/google_webmaster-24.png}|image_reduire{0,24})] <:seo:google_webmaster_tools:></h3>
+                               <ul>
+                                       <li class="editer editer_webmaster_tools_activate">
+                                               <label for="webmaster_tools_activate"><:seo:google_webmaster_tools_activate:></label>
+                                               <input type="checkbox" value="yes" name="activate" id="webmaster_tools_activate"[(#ENV{activate}|=={yes}|oui)checked="checked"] onChange="active_webmaster_tools(jQuery(this), jQuery('.editer_webmaster_tools_id'))"/>
+                                       </li>
+                                       <li class="editer editer_webmaster_tools_id">
+                                               <label for="webmaster_tools_id"><:seo:google_webmaster_tools_id:></label>
+                                               <input type="text" name="webmaster_tools_id" value="#ENV{webmaster_tools_id}" id="webmaster_tools_id" class="text" />
+                                       </li>
+                               </ul>
+                       </li>
+               </ul>
+               <p class="boutons">
+                       <input type="submit" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div>
+</form>
+<script type="text/javascript">
+       function active_webmaster_tools(checkbox, form) {
+               checkbox.is(':checked') ? form.slideDown()  : form.slideUp();
+       }
+       [(#ENV{activate}|=={yes}|non)
+       jQuery('.editer_webmaster_tools_id').hide();]
+</script>
+</div>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/formulaires/configurer_seo_webmaster_tools.php b/www/plugins/seo-v1/formulaires/configurer_seo_webmaster_tools.php
new file mode 100644 (file)
index 0000000..a6df97d
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+function formulaires_configurer_seo_webmaster_tools_charger_dist(){
+
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $valeurs = isset($config['webmaster_tools']) ? $config['webmaster_tools'] : array('id' => '');
+       $valeurs['webmaster_tools_id'] = $valeurs['id'];
+       
+       $valeurs['editable'] = true;
+       
+       if (!autoriser('configurer', 'configuration')) {
+               $valeurs['editable'] = false;
+       }
+
+       return $valeurs;
+}
+
+function formulaires_configurer_seo_webmaster_tools_traiter_dist(){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (!isset($config['webmaster_tools'])) {
+               $config['webmaster_tools'] = array();
+       }
+       $config['webmaster_tools']['activate'] = _request('activate','no');
+       $config['webmaster_tools']['id'] = _request('webmaster_tools_id',''); 
+       $config = serialize($config);
+       ecrire_meta('seo',$config);
+       include_spip('inc/invalideur');
+       suivre_invalideur('1');
+       return array('message_ok'=>_T('config_info_enregistree'),'editable'=>true);
+}
+?>
diff --git a/www/plugins/seo-v1/formulaires/editer_seo.html b/www/plugins/seo-v1/formulaires/editer_seo.html
new file mode 100644 (file)
index 0000000..2c980f2
--- /dev/null
@@ -0,0 +1,46 @@
+<div class="formulaire_spip formulaire_editer formulaire_editer_seo formulaire_editer_seo-#ENV{objet}-#ENV{id_objet}">
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+       [(#ENV{editable})
+       <form method='post' action='#ENV{action}'><div>
+               [(#REM) declarer les hidden qui declencheront le service du formulaire 
+               parametre : url d'action ]
+               #ACTION_FORMULAIRE{#ENV{action}}
+         <input type='hidden' name='id_objet' value='#ENV{id_objet}' />
+         <input type='hidden' name='objet' value='#ENV{objet}' />
+         <ul>
+           <li class="editer editer_title[ (#ENV**{erreurs}|table_valeur{title}|oui)erreur]">
+               <label for="title"><:seo:meta_title:></label>[
+               <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{title})</span>
+               ]<input type='text' class='text' name='title' id='title' value="[(#ENV**{title,''})]" />
+           </li>
+           [<li class="editer editer_description[ (#ENV**{erreurs}|table_valeur{description}|oui)erreur]">(#ENV**{description}|match{^=,Uis}|non)
+                       <label for="description"><:seo:meta_description:></label>[
+                       <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{description})</span>
+                       ]<textarea name='description' id='description' rows='3' cols='40'>[(#ENV**{description})]</textarea>
+               </li>]
+           <li class="editer editer_keywords[ (#ENV**{erreurs}|table_valeur{keywords}|oui)erreur]">
+               <label for="keywords"><:seo:meta_keywords:></label>[
+               <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{keywords})</span>
+               ]<input type='text' class='text' name='keywords' id='keywords' value="[(#ENV**{keywords,''})]" />
+           </li>
+           <li class="editer editer_copyright[ (#ENV**{erreurs}|table_valeur{copyright}|oui)erreur]">
+               <label for="copyright"><:seo:meta_copyright:></label>[
+               <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{copyright})</span>
+               ]<input type='text' class='text' name='copyright' id='copyright' value="[(#ENV**{copyright,''})]" />
+           </li>
+           <li class="editer editer_author[ (#ENV**{erreurs}|table_valeur{author}|oui)erreur]">
+               <label for="author"><:seo:meta_author:></label>[
+               <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{author})</span>
+               ]<input type='text' class='text' name='author' id='author' value="[(#ENV**{author,''})]" />
+           </li>
+         </ul>
+
+         [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
+         <!--extra-->
+         <p class='boutons'>
+               <input type='submit' class='submit' value='<:bouton_enregistrer:>' />
+         </p>
+       </div></form>
+       ]
+</div>
diff --git a/www/plugins/seo-v1/formulaires/editer_seo.php b/www/plugins/seo-v1/formulaires/editer_seo.php
new file mode 100644 (file)
index 0000000..fa47632
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+include_spip('inc/actions');
+include_spip('inc/editer');
+
+function formulaires_editer_seo_charger($objet, $id_objet, $retour=''){
+       $valeurs = array();
+       $valeurs['objet'] = $objet;
+       $valeurs['id_objet'] = $id_objet;
+       $metas = sql_select("*", "spip_seo", "id_objet =".intval($id_objet)." AND objet =".sql_quote($objet));
+       while($meta = sql_fetch($metas)){
+               $valeurs[$meta['meta_name']] = $meta['meta_content'];
+       }
+       $valeurs['editable'] = true;
+       return $valeurs;
+}
+
+/**
+ * Identifier le formulaire en faisant abstraction des parametres qui
+ * ne representent pas l'objet edite
+ */
+function formulaires_editer_seo_identifier_dist($objet, $id_objet, $retour=''){
+       return serialize(array(intval($id_objet),$objet));
+}
+
+function formulaires_editer_seo_verifier($objet, $id_objet, $retour=''){
+       $erreurs = array();
+       return $erreurs;
+}
+
+function formulaires_editer_seo_traiter($objet, $id_objet, $retour=''){
+       $editer_seo = charger_fonction('editer_seo','action');
+       $editer_seo();
+       
+       return;
+       //return formulaires_editer_objet_traiter('seo',$id_objet,$objet,$lier_trad,$retour,$config_fonc,$row,$hidden);
+}
+
+?>
diff --git a/www/plugins/seo-v1/img_pack/alexa-24.png b/www/plugins/seo-v1/img_pack/alexa-24.png
new file mode 100644 (file)
index 0000000..c270b69
Binary files /dev/null and b/www/plugins/seo-v1/img_pack/alexa-24.png differ
diff --git a/www/plugins/seo-v1/img_pack/bing-24.png b/www/plugins/seo-v1/img_pack/bing-24.png
new file mode 100644 (file)
index 0000000..54e1ae9
Binary files /dev/null and b/www/plugins/seo-v1/img_pack/bing-24.png differ
diff --git a/www/plugins/seo-v1/img_pack/canonical_url-24.png b/www/plugins/seo-v1/img_pack/canonical_url-24.png
new file mode 100644 (file)
index 0000000..43f34b4
Binary files /dev/null and b/www/plugins/seo-v1/img_pack/canonical_url-24.png differ
diff --git a/www/plugins/seo-v1/img_pack/google_analytics-24.png b/www/plugins/seo-v1/img_pack/google_analytics-24.png
new file mode 100644 (file)
index 0000000..a334a47
Binary files /dev/null and b/www/plugins/seo-v1/img_pack/google_analytics-24.png differ
diff --git a/www/plugins/seo-v1/img_pack/google_webmaster-24.png b/www/plugins/seo-v1/img_pack/google_webmaster-24.png
new file mode 100644 (file)
index 0000000..e27175d
Binary files /dev/null and b/www/plugins/seo-v1/img_pack/google_webmaster-24.png differ
diff --git a/www/plugins/seo-v1/img_pack/meta_tags-24.png b/www/plugins/seo-v1/img_pack/meta_tags-24.png
new file mode 100644 (file)
index 0000000..1ab847a
Binary files /dev/null and b/www/plugins/seo-v1/img_pack/meta_tags-24.png differ
diff --git a/www/plugins/seo-v1/img_pack/seo-24.png b/www/plugins/seo-v1/img_pack/seo-24.png
new file mode 100644 (file)
index 0000000..c9f08ad
Binary files /dev/null and b/www/plugins/seo-v1/img_pack/seo-24.png differ
diff --git a/www/plugins/seo-v1/lang/paquet-seo.xml b/www/plugins/seo-v1/lang/paquet-seo.xml
new file mode 100644 (file)
index 0000000..ed623da
--- /dev/null
@@ -0,0 +1,11 @@
+<traduction module="paquet-seo" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/seo/lang/" reference="fr">
+       <langue code="en" />
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-seo?lang_cible=ru">
+               <traducteur nom="nazar" lien="http://trad.spip.net/auteur/nazar" />
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-seo?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/seo-v1/lang/paquet-seo_en.php b/www/plugins/seo-v1/lang/paquet-seo_en.php
new file mode 100644 (file)
index 0000000..8bfea58
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-seo?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'seo_description' => 'SEO is a plugin who add the possibility to insert in the head of your website: meta tags, canoical URL, Google webmaster tools Meta Code and Google Analytics javascript code. It is fully configurable in the SPIP configuration page and in each article or rubrique page for meta tags.',
+       'seo_nom' => 'SEO',
+       'seo_slogan' => 'Search Engine Optimisation'
+);
+
+?>
diff --git a/www/plugins/seo-v1/lang/paquet-seo_fr.php b/www/plugins/seo-v1/lang/paquet-seo_fr.php
new file mode 100644 (file)
index 0000000..fd4b5ae
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/seo/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'seo_description' => 'SEO est un plugin qui ajoute la possibilité d\'insérer dans la partie head de votre site web : meta tags, URL canonique, Google webmaster tools Meta Code et Google Analytics javascript. Il est configurable dans la page de configuration de SPIP ainsi que dans chaque rubrique et article pour les meta tags.',
+       'seo_nom' => 'SEO',
+       'seo_slogan' => 'Search Engine Optimisation'
+);
+
+?>
diff --git a/www/plugins/seo-v1/lang/paquet-seo_ru.php b/www/plugins/seo-v1/lang/paquet-seo_ru.php
new file mode 100644 (file)
index 0000000..4cda1a8
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-seo?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'seo_description' => 'Этот плагин предоставляет возможность вставлять в шапку вашего сайта мета теги, канонический вид URL, Google webmaster tools, Meta Code, и Google Analytics javascript code. Каждой статье и каждому разделу вы можете придавать уникальные мета теги.',
+       'seo_nom' => 'SEO',
+       'seo_slogan' => 'Поисковая оптимизация (SEO)'
+);
+
+?>
diff --git a/www/plugins/seo-v1/lang/paquet-seo_sk.php b/www/plugins/seo-v1/lang/paquet-seo_sk.php
new file mode 100644 (file)
index 0000000..9abc22b
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-seo?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'seo_description' => 'SEO je zásuvný modul, ktorý ponúka možnosť vložiť do hlavičky stránky meta tagy, kanonickú podobu internetových adries, meta kód nástrojov pre webmasterov od spoločnosti Google a javaskript z Google Analytics. Meta tagy sa dajú nastaviť na stránke s nastaveniami SPIPu, ako aj v každej rubrike a v každom článku.',
+       'seo_nom' => 'SEO',
+       'seo_slogan' => 'Optimalizácia pre vyhľadávače'
+);
+
+?>
diff --git a/www/plugins/seo-v1/lang/seo.xml b/www/plugins/seo-v1/lang/seo.xml
new file mode 100644 (file)
index 0000000..4720173
--- /dev/null
@@ -0,0 +1,13 @@
+<traduction module="seo" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/seo/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/seo?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/seo?lang_cible=ru">
+               <traducteur nom="nazar" lien="http://trad.spip.net/auteur/nazar" />
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/seo?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/seo-v1/lang/seo_en.php b/www/plugins/seo-v1/lang/seo_en.php
new file mode 100644 (file)
index 0000000..dd145c0
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/seo?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'S.E.O' => 'SEO',
+
+       // A
+       'alexa' => 'Alexa',
+       'alexa_activate' => 'Activate Alexa',
+       'alexa_id' => 'Website Alexa\'s ID',
+
+       // B
+       'bing_webmaster' => 'Bing Webmaster Tools',
+       'bing_webmaster_activate' => 'Enable Bing Webmaster Tools',
+       'bing_webmaster_id' => 'Meta Code verification',
+
+       // C
+       'canonical_url' => 'Canonical URL',
+       'canonical_url_activate' => 'Activate Canonical URL',
+
+       // F
+       'forcer_squelette_descriptif' => 'SEO metas are prioritary to the one generated by the skeleton',
+       'forcer_squelette_label' => 'Load metas for all skeletons',
+
+       // G
+       'google_analytics' => 'Google Analytics',
+       'google_analytics_activate' => 'Activate Analytics',
+       'google_analytics_id' => 'Google Analytics web property ID',
+       'google_webmaster_tools' => 'Google Webmaster Tools',
+       'google_webmaster_tools_activate' => 'Activate Webmaster Tools',
+       'google_webmaster_tools_id' => 'Meta Code verification',
+
+       // I
+       'insert_head' => 'Automatic insertion in #INSERT_HEAD',
+       'insert_head_activate' => 'Activate automatic insertion',
+       'insert_head_descriptif' => 'Automatic insertion of SEO configuration in &lt;header&gt;',
+
+       // M
+       'meta_author' => 'Author:',
+       'meta_copyright' => 'Copyright:',
+       'meta_description' => 'Description:',
+       'meta_keywords' => 'Keywords:',
+       'meta_page_description_sommaire_value' => 'Page Description Value + Home Page Meta Value',
+       'meta_page_description_value' => 'Page Description Value',
+       'meta_page_title_sommaire_value' => 'Page Title Value + Home Page Meta Value',
+       'meta_page_title_value' => 'Page Title Value',
+       'meta_robots' => 'Robots:',
+       'meta_sommaire_value' => 'Home Page Meta Value',
+       'meta_tags' => 'Meta Tags',
+       'meta_tags_activate' => 'Activate meta tags',
+       'meta_tags_default' => 'Defaults Meta Tag (for Articles and Sections)',
+       'meta_tags_edit_activate' => 'Activate meta tags editing in sections and articles',
+       'meta_tags_editing' => 'Meta Tags Editing',
+       'meta_tags_sommaire' => 'Home Page Meta Tags',
+       'meta_title' => 'Title:',
+
+       // S
+       'seo' => 'Search Engine Optimisation'
+);
+
+?>
diff --git a/www/plugins/seo-v1/lang/seo_fr.php b/www/plugins/seo-v1/lang/seo_fr.php
new file mode 100644 (file)
index 0000000..3fe76d0
--- /dev/null
@@ -0,0 +1,65 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/seo/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'S.E.O' => 'SEO',
+
+       // A
+       'alexa' => 'Alexa',
+       'alexa_activate' => 'Activer Alexa',
+       'alexa_id' => 'Identifiant du site pour Alexa',
+
+       // B
+       'bing_webmaster' => 'Bing Webmaster Tools',
+       'bing_webmaster_activate' => 'Activer Bing Webmaster Tools',
+       'bing_webmaster_id' => 'Meta code de vérification',
+
+       // C
+       'canonical_url' => 'URL Canoniques',
+       'canonical_url_activate' => 'Activer les URL Canoniques',
+
+       // F
+       'forcer_squelette_descriptif' => 'Les metas SEO sont prioritaires aux meta générées par les squelettes',
+       'forcer_squelette_label' => 'Charger les metas pour tous squelettes',
+
+       // G
+       'google_analytics' => 'Google Analytics',
+       'google_analytics_activate' => 'Activer Analytics',
+       'google_analytics_id' => 'Google Analytics web property ID',
+       'google_webmaster_tools' => 'Google Webmaster Tools',
+       'google_webmaster_tools_activate' => 'Activer Webmaster Tools',
+       'google_webmaster_tools_id' => 'Meta code de vérification',
+
+       // I
+       'insert_head' => 'Insertion automatique dans #INSERT_HEAD',
+       'insert_head_activate' => 'Activer l\'insertion automatique',
+       'insert_head_descriptif' => 'Insertion automatique de la configuration SEO dans le &lt;header&gt;',
+
+       // M
+       'meta_author' => 'Auteur :',
+       'meta_copyright' => 'Copyright :',
+       'meta_description' => 'Description :',
+       'meta_keywords' => 'Mots Clefs :',
+       'meta_page_description_sommaire_value' => 'Valeur de la Description de la Page + Valeur Meta du Sommaine',
+       'meta_page_description_value' => 'Valeur de la Description de la Page',
+       'meta_page_title_sommaire_value' => 'Valeur du Titre de la Page + Valeur Meta du Sommaire',
+       'meta_page_title_value' => 'Valeur du Titre de la Page',
+       'meta_robots' => 'Robots :',
+       'meta_sommaire_value' => 'Valeur de la Meta du Sommaire',
+       'meta_tags' => 'Meta Tags',
+       'meta_tags_activate' => 'Activer les meta tags',
+       'meta_tags_default' => 'Valeur des Meta Tags par Défaut (pour les Articles et les Rubriques)',
+       'meta_tags_edit_activate' => 'Activer l\'édition des meta tags dans les rubriques et les articles',
+       'meta_tags_editing' => 'Edition des Meta Tags',
+       'meta_tags_sommaire' => 'Valeur des Meta Tags du Sommaire (page d\'accueil)',
+       'meta_title' => 'Titre :',
+
+       // S
+       'seo' => 'Search Engine Optimisation'
+);
+
+?>
diff --git a/www/plugins/seo-v1/lang/seo_ru.php b/www/plugins/seo-v1/lang/seo_ru.php
new file mode 100644 (file)
index 0000000..b8fe400
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/seo?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'S.E.O' => 'SEO',
+
+       // A
+       'alexa' => 'Alexa',
+       'alexa_activate' => 'Включить Alexa',
+       'alexa_id' => 'Сайт идентификатор для Alexa',
+
+       // B
+       'bing_webmaster' => 'Bing Webmaster Tools',
+       'bing_webmaster_activate' => 'Включить Bing Webmaster Tools',
+       'bing_webmaster_id' => 'Проверочный мета код',
+
+       // C
+       'canonical_url' => 'Канонические URL',
+       'canonical_url_activate' => 'Включить канонические URL',
+
+       // F
+       'forcer_squelette_descriptif' => 'Мета теги, заданные в плагине, имеют больший приоритет, чем теги, указанные в шаблонах.',
+       'forcer_squelette_label' => 'Подключать мета теги во все шаблоны',
+
+       // G
+       'google_analytics' => 'Google Analytics',
+       'google_analytics_activate' => 'Включить Analytics',
+       'google_analytics_id' => 'Google Analytics ID',
+       'google_webmaster_tools' => 'Google Webmaster Tools',
+       'google_webmaster_tools_activate' => 'Включить Webmaster Tools',
+       'google_webmaster_tools_id' => 'Проверка Meta code ',
+
+       // I
+       'insert_head' => 'Подключать автоматически в #INSERT_HEAD',
+       'insert_head_activate' => 'Включить',
+       'insert_head_descriptif' => 'Автоматическая вставка мета-тегов в &lt;header&gt;',
+
+       // M
+       'meta_author' => 'Автор :',
+       'meta_copyright' => 'Copyright:',
+       'meta_description' => 'Описание:',
+       'meta_keywords' => 'Ключевые слова :',
+       'meta_page_description_sommaire_value' => 'Значение Description страницы + значение Meta главной',
+       'meta_page_description_value' => 'Значение Description страницы',
+       'meta_page_title_sommaire_value' => 'Title страницы + значение Meta главной',
+       'meta_page_title_value' => 'Title страницы',
+       'meta_robots' => 'Роботы :',
+       'meta_sommaire_value' => 'Значение Meta главной страницы',
+       'meta_tags' => 'Mета Теги',
+       'meta_tags_activate' => 'Включить',
+       'meta_tags_default' => 'Сгенерировать Mета Теги по умолчанию (для статей и разделов)',
+       'meta_tags_edit_activate' => 'Включить возможность редактирования мета тегов для разделов и статей',
+       'meta_tags_editing' => 'Редактирование мета-тегов',
+       'meta_tags_sommaire' => 'Мета теги главной страницы',
+       'meta_title' => 'Title :',
+
+       // S
+       'seo' => 'Поисковая оптимизация'
+);
+
+?>
diff --git a/www/plugins/seo-v1/lang/seo_sk.php b/www/plugins/seo-v1/lang/seo_sk.php
new file mode 100644 (file)
index 0000000..089e1c3
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/seo?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'S.E.O' => 'SEO',
+
+       // A
+       'alexa' => 'Alexa',
+       'alexa_activate' => 'Aktivovať Alexu',
+       'alexa_id' => 'Identifikátor stránky na Alexu',
+
+       // B
+       'bing_webmaster' => 'Bing Webmaster Tools', # NEW
+       'bing_webmaster_activate' => 'Activer Bing Webmaster Tools', # NEW
+       'bing_webmaster_id' => 'Meta code de vérification', # NEW
+
+       // C
+       'canonical_url' => 'Kanonická podoba adries',
+       'canonical_url_activate' => 'Aktivovať kanonickú podobu adries',
+
+       // F
+       'forcer_squelette_descriptif' => 'Hlavičky meta zo SEO majú prednosť pred hlavičkami meta, ktoré vygenerujú šablóny',
+       'forcer_squelette_label' => 'Nahrať hlavičky meta pre všetky šablóny',
+
+       // G
+       'google_analytics' => 'Google Analytics',
+       'google_analytics_activate' => 'Aktivovať Google Analytics',
+       'google_analytics_id' => 'ID webového objektu Google Analytics ',
+       'google_webmaster_tools' => 'Nástroje Google Webmaster Tools',
+       'google_webmaster_tools_activate' => 'Aktivovať Nástroje pre webmastera',
+       'google_webmaster_tools_id' => 'Kontrolný kód',
+
+       // I
+       'insert_head' => 'Automatické vkladanie do #INSERT_HEAD',
+       'insert_head_activate' => 'Aktivovať automatické vkladanie',
+       'insert_head_descriptif' => 'Automatické vkladanie nastavenia SEO do &lt;hlavičky&gt;',
+
+       // M
+       'meta_author' => 'Autor(ka):',
+       'meta_copyright' => 'Autorské práva:',
+       'meta_description' => 'Popis:',
+       'meta_keywords' => 'Kľúčové slová:',
+       'meta_page_description_sommaire_value' => 'Hodnota popisu stránky + hodnota tagu zhrnutie',
+       'meta_page_description_value' => 'Hodnota popisu stránky',
+       'meta_page_title_sommaire_value' => 'Hodnota nadpisu stránky + hodnota tagu Zhrnutie',
+       'meta_page_title_value' => 'Hodnota nadpisu stránky',
+       'meta_robots' => 'Roboty:',
+       'meta_sommaire_value' => 'Hodnota tagu Zhrnutie',
+       'meta_tags' => 'Meta tagy',
+       'meta_tags_activate' => 'Aktivovať meta tagy',
+       'meta_tags_default' => 'Predvolená hodnota meta tagov (pre články a rubriky)',
+       'meta_tags_edit_activate' => 'Aktivovať úpravu meta tagov v rubrikách a článkoch',
+       'meta_tags_editing' => 'Úprava meta tagov',
+       'meta_tags_sommaire' => 'Hodnota meta tagov zhrnutia (úvodná stránka)',
+       'meta_title' => 'Nadpis:',
+
+       // S
+       'seo' => 'Optimalizácia pre vyhľadávače'
+);
+
+?>
diff --git a/www/plugins/seo-v1/paquet.xml b/www/plugins/seo-v1/paquet.xml
new file mode 100644 (file)
index 0000000..b270737
--- /dev/null
@@ -0,0 +1,30 @@
+<paquet
+       prefix="seo"
+       categorie="statistique"
+       version="1.8.1"
+       etat="test"
+       compatibilite="[2.0.0;3.0.99]"
+       logo="seo.png"
+       schema="1.1.1"
+       documentation="http://www.spip-contrib.net/?rubrique1248"
+>      
+
+       <nom>SEO</nom>
+       <!-- Search Engine Optimisation -->
+
+       <auteur mail="p.rousset@gmail.com">Pierre ROUSSET</auteur>
+
+       <copyright>2009-2012</copyright>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-2.0.html">GPL 2</licence>
+
+       <pipeline nom="declarer_tables_principales" inclure="base/seo_tables.php" />
+       <pipeline nom="declarer_tables_interfaces" inclure="base/seo_tables.php" />
+       <pipeline nom="insert_head" action="insert_head" inclure="pipelines/seo_insert_head.php" />
+       <pipeline nom="affichage_final" action="affichage_final" inclure="pipelines/seo_affichage_final.php" />
+       <pipeline nom="affiche_milieu" action="affiche_milieu" inclure="pipelines/seo_affiche_milieu.php" />
+       <pipeline nom="ajouter_onglets" action="ajouter_onglets" inclure="pipelines/seo_ajouter_onglets.php" />
+       <pipeline nom="autoriser" inclure="pipelines/seo_autoriser.php" />
+
+       <menu nom="seo" titre="seo:seo" parent="menu_configuration" icone="images/seo-16.png" action="configurer_seo" />
+</paquet>
diff --git a/www/plugins/seo-v1/pipelines/seo_affichage_final.php b/www/plugins/seo-v1/pipelines/seo_affichage_final.php
new file mode 100644 (file)
index 0000000..2626c2d
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+/**
+ * BouncingOrange SPIP SEO plugin
+ *
+ * @category   SEO
+ * @package    SPIP_SEO
+ * @author     Pierre ROUSSET (p.rousset@gmail.com)
+ * @copyright  Copyright (c) 2009 BouncingOrange (http://www.bouncingorange.com)
+ * @license    http://opensource.org/licenses/gpl-2.0.php  General Public License (GPL 2.0)
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Insertion dans le pipeline affichage_final (SPIP)
+ * Remplacement des métas et title dans le <head>
+ * Remplace les métas et title du squelette et celles insérées via insert_head également
+ *
+ * @param string $flux
+ *     Le contenu de la page
+ * @return string
+ *     Le contenu de la page modifié
+ */
+function seo_affichage_final($flux){
+       preg_match('/<head>(.*)<\/head>/mis', $flux, $head);
+       $head = isset($head[1]) ? $head[1] : false;
+
+       /**
+        * On n'agit que si on a un head
+        * sinon c'est tout et n'importe quoi
+        */
+       if ($head){
+               /**
+                * Pour lire_config
+                */
+               include_spip('inc/config');
+
+               $forcer_squelette = lire_config('seo/forcer_squelette', 'no');
+               if ($forcer_squelette!='yes')
+                       return $flux;
+
+               include_spip('seo_fonctions');
+
+               $meta_tags = calculer_meta_tags();
+
+               foreach ($meta_tags as $key => $value){
+                       $meta = generer_meta_tags(array($key => $value));
+                       $flux_meta = '';
+                       /**
+                        * Si le tag est <title>
+                        */
+                       if ($key=='title')
+                               $flux_meta = preg_replace("/(<\s*$key.*?>.*?<\/\s*$key.*?>)/mi", $meta, $flux, 1);
+                       /**
+                        * Le tag est une <meta>
+                        */
+                       else
+                               $flux_meta = preg_replace("/(<\s*meta\s*name=\"$key\"\s*content=\".*?\".*?>)/mi", $meta, $flux, 1);
+
+                       /**
+                        * Si $flux == $flux_meta
+                        * C'est que _SEO_FORCER_SQUELETTE est placé
+                        * On ajoute les metas juste avant </head>
+                        */
+                       if ($flux==$flux_meta)
+                               $flux_meta = str_replace('</head>', "\n" . $meta . "</head>", $flux);
+
+                       $flux = $flux_meta;
+               }
+       }
+       return $flux;
+}
+
diff --git a/www/plugins/seo-v1/pipelines/seo_affiche_milieu.php b/www/plugins/seo-v1/pipelines/seo_affiche_milieu.php
new file mode 100644 (file)
index 0000000..3a003ae
--- /dev/null
@@ -0,0 +1,58 @@
+<?php
+/**
+ * BouncingOrange SPIP SEO plugin
+ *
+ * @category   SEO
+ * @package    SPIP_SEO
+ * @author     Pierre ROUSSET (p.rousset@gmail.com)
+ * @copyright  Copyright (c) 2009 BouncingOrange (http://www.bouncingorange.com)
+ * @license    http://opensource.org/licenses/gpl-2.0.php  General Public License (GPL 2.0)
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Afficher le formulaire de config des meta dans l'admin
+ * @param array $vars
+ * @return array
+ */
+function seo_affiche_milieu($vars){
+       include_spip('inc/autoriser');
+       include_spip('inc/presentation');
+       $config = unserialize($GLOBALS['meta']['seo']);
+
+       // Rubrique
+       if (in_array($vars["args"]["exec"], array('naviguer', 'rubrique')) && $vars["args"]["id_rubrique"]!=''){
+               $objet = 'rubrique';
+               $id_objet = $vars["args"]["id_rubrique"];
+               // Article
+       } elseif (in_array($vars["args"]["exec"], array('articles', 'article')) && $vars["args"]["id_article"]!='') {
+               $objet = 'article';
+               $id_objet = $vars["args"]["id_article"];
+               // Other case we quit
+       } else {
+               return $vars;
+       }
+
+       // If meta tags are activates
+       if ($config['meta_tags']['activate']!='yes' || $config['meta_tags']['activate_editing']!='yes'){
+               return $vars;
+       }
+
+       $ret = '';
+
+       $bouton = bouton_block_depliable(_T('seo:meta_tags'), false, "SEO");
+       $ret .= debut_block_depliable(false, "SEO");
+
+       // List         
+       $ret .= recuperer_fond('prive/squelettes/inclure/seo_metas', array('objet' => $objet, 'id_objet' => $id_objet));
+
+       $ret .= fin_block();
+
+       // Create the border with the content
+       $ret = '<div class="nettoyeur"></div>' . debut_cadre_enfonce(_DIR_PLUGIN_SEO . 'img_pack/meta_tags-24.png', true, "", $bouton) . $ret . fin_cadre_enfonce(true);
+
+       $vars["data"] .= $ret;
+
+       return $vars;
+}
diff --git a/www/plugins/seo-v1/pipelines/seo_ajouter_onglets.php b/www/plugins/seo-v1/pipelines/seo_ajouter_onglets.php
new file mode 100644 (file)
index 0000000..38009db
--- /dev/null
@@ -0,0 +1,28 @@
+<?php
+/**
+ * BouncingOrange SPIP SEO plugin
+ *
+ * @category   SEO
+ * @package    SPIP_SEO
+ * @author     Pierre ROUSSET (p.rousset@gmail.com)
+ * @copyright  Copyright (c) 2009 BouncingOrange (http://www.bouncingorange.com)
+ * @license    http://opensource.org/licenses/gpl-2.0.php  General Public License (GPL 2.0)
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function seo_ajouter_onglets($flux){
+
+       global $connect_statut, $connect_toutes_rubriques;
+
+       // seul les administrateurs globaux ont acces au bouton de configuration
+       if ($connect_statut && $connect_toutes_rubriques){
+               if ($flux['args']=='configuration'){
+                       $flux['data']['seo'] = new Bouton(_DIR_PLUGIN_SEO . "img_pack/seo-24.png", _T("seo:seo"), generer_url_ecrire('seo_config'));
+               }
+       }
+
+       return ($flux);
+}
+
+?>
diff --git a/www/plugins/seo-v1/pipelines/seo_autoriser.php b/www/plugins/seo-v1/pipelines/seo_autoriser.php
new file mode 100644 (file)
index 0000000..ece880b
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function seo_autoriser(){
+}
+
+function autoriser_seo_bouton_dist($faire, $type, $id, $qui, $opt){
+       global $connect_statut, $connect_toutes_rubriques;
+
+       // seul les administrateurs globaux ont acces au bouton de configuration
+       return $connect_statut && $connect_toutes_rubriques;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/pipelines/seo_insert_head.php b/www/plugins/seo-v1/pipelines/seo_insert_head.php
new file mode 100644 (file)
index 0000000..04f67cd
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+/**
+ * BouncingOrange SPIP SEO plugin
+ *
+ * @category   SEO
+ * @package    SPIP_SEO
+ * @author     Pierre ROUSSET (p.rousset@gmail.com)
+ * @copyright  Copyright (c) 2009 BouncingOrange (http://www.bouncingorange.com)
+ * @license    http://opensource.org/licenses/gpl-2.0.php  General Public License (GPL 2.0)
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Inserer les meta dans le head
+ *
+ * @param string $flux
+ * @return string
+ */
+function seo_insert_head($flux){
+       /* CONFIG */
+       $config = unserialize($GLOBALS['meta']['seo']);
+       if (isset($config['insert_head']) && $config['insert_head']['activate']=='yes'){
+               $contexte = $GLOBALS['contexte'];
+               unset($contexte['lang']);
+               unset($contexte['date']);
+               unset($contexte['date_default']);
+               unset($contexte['date_redac']);
+               unset($contexte['date_redac_default']);
+               unset($contexte['lang']);
+               if (count($contexte)==0){
+                       $objet = 'sommaire';
+               } elseif (isset($contexte['id_article'])) {
+                       $id_objet = $contexte['id_article'];
+                       $objet = 'article';
+               } elseif (isset($contexte['id_rubrique'])) {
+                       $id_objet = $contexte['id_rubrique'];
+                       $objet = 'rubrique';
+               }
+               /* META TAGS */
+               if (isset($config['meta_tags']) && $config['meta_tags']['activate']=='yes'){
+                       if (!defined('_SEO_FORCER_SQUELETTE')){
+                               $meta_tags = calculer_meta_tags();
+                               $flux .= generer_meta_tags($meta_tags);
+                       }
+               }
+               /* META GOOGLE WEBMASTER TOOLS */
+               if (isset($config['webmaster_tools']) && $config['webmaster_tools']['activate']=='yes' && $objet=='sommaire'){
+                       $flux .= generer_webmaster_tools();
+               }
+
+               if (isset($config['bing']) && $config['bing']['activate']=='yes' && $objet=='sommaire'){
+                       $flux .= generer_bing();
+               }
+
+               /* CANONICAL URL */
+               if (isset($config['canonical_url']) && $config['canonical_url']['activate']=='yes'){
+                       $flux .= generer_urls_canoniques();
+               }
+
+               /* GOOGLE ANALYTICS */
+               if (isset($config['analytics']) && $config['analytics']['activate']=='yes'){
+                       $flux .= generer_google_analytics();
+               }
+
+               /* ALEXA */
+               if (isset($config['alexa']) && $config['alexa']['activate']=='yes' && $objet=='sommaire'){
+                       $flux .= generer_alexa();
+               }
+       }
+
+       return $flux;
+}
+
diff --git a/www/plugins/seo-v1/plugin.xml b/www/plugins/seo-v1/plugin.xml
new file mode 100644 (file)
index 0000000..17cf494
--- /dev/null
@@ -0,0 +1,61 @@
+<plugin>\r
+       <nom><multi>[fr]SEO[en]SEO</multi></nom>\r
+       <slogan>Search Engine Optimisation</slogan>\r
+       <auteur>[Pierre ROUSSET->p.rousset@gmail.com] for [Bouncing Orange->http://www.bouncingorange.com/]</auteur>\r
+       <prefix>seo</prefix>\r
+       <icon>seo.png</icon>\r
+       <description>\r
+               <multi>\r
+                       [fr]SEO est un plugin qui ajoute la possibilit&#233; d'ins&#233;rer dans la partie head de votre site web : meta tags, URL canonique, Google webmaster tools Meta Code et Google Analytics javascript. Il est configurable dans la page de configuration de SPIP ainsi que dans chaque rubrique et article pour les meta tags.\r
+                       [en]SEO is a plugin who add the possibility to insert in the head of your website: meta tags, canoical URL, Google webmaster tools Meta Code and Google Analytics javascript code. It is fully configurable in the SPIP configuration page and in each article or rubrique page for meta tags.\r
+               </multi>\r
+       </description>\r
+       <lien>http://www.spip-contrib.net/?rubrique1248</lien>\r
+       <licence>(c) 2009-2012 GPL v2</licence>\r
+       <etat>test</etat>\r
+       \r
+       <version>1.8.1</version>\r
+       <version_base>1.1.1</version_base>\r
+\r
+       <install>seo_administrations.php</install>\r
+       <pipeline>\r
+               <nom>declarer_tables_principales</nom>\r
+               <inclure>base/seo_tables.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>declarer_tables_interfaces</nom>\r
+               <inclure>base/seo_tables.php</inclure>\r
+       </pipeline>\r
+\r
+       <fonctions>seo_fonctions.php</fonctions>\r
+\r
+       <pipeline>\r
+        <nom>insert_head</nom>\r
+               <action>insert_head</action>\r
+        <inclure>pipelines/seo_insert_head.php</inclure>\r
+    </pipeline>\r
+       <pipeline>\r
+        <nom>affiche_milieu</nom>\r
+               <action>affiche_milieu</action>\r
+        <inclure>pipelines/seo_affiche_milieu.php</inclure>\r
+    </pipeline>\r
+       <pipeline>\r
+               <nom>ajouter_onglets</nom>\r
+               <action>ajouter_onglets</action>\r
+        <inclure>pipelines/seo_ajouter_onglets.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>autoriser</nom>\r
+               <inclure>pipelines/seo_autoriser.php</inclure>\r
+       </pipeline>\r
+\r
+       <bouton id="seo" parent="bando_configuration">\r
+               <icone>img_pack/seo-24.png</icone>\r
+               <titre>seo:seo</titre>  \r
+               <url>seo_config</url>   \r
+       </bouton>\r
+       \r
+       <chemin dir='' />\r
+       <necessite id="SPIP" version="[2.0.0;3.0.99]" />\r
+       <categorie>statistique</categorie>\r
+</plugin>\r
diff --git a/www/plugins/seo-v1/prive/configurer_seo.html b/www/plugins/seo-v1/prive/configurer_seo.html
new file mode 100644 (file)
index 0000000..f80ceb3
--- /dev/null
@@ -0,0 +1,52 @@
+[(#REM)
+
+       Inclusion dans la page de configuration
+       
+       Affiche les 6 formulaires de configuration :
+       -* FORMULAIRE_CONFIGURER_SEO_INSERT_HEAD
+       -* FORMULAIRE_CONFIGURER_SEO_METAS
+       -* FORMULAIRE_CONFIGURER_SEO_URLS_CANONIQUES
+       -* FORMULAIRE_CONFIGURER_SEO_WEBMASTER_TOOLS
+       -* FORMULAIRE_CONFIGURER_SEO_BING
+       -* FORMULAIRE_CONFIGURER_SEO_GANALYTICS
+       -* FORMULAIRE_CONFIGURER_SEO_ALEXA
+
+]
+
+[<div class="ajax">
+(#FORMULAIRE_CONFIGURER_SEO_INSERT_HEAD)
+</div>]
+
+<br />
+
+[<div class="ajax">
+(#FORMULAIRE_CONFIGURER_SEO_METAS)
+</div>]
+
+<br />
+
+[<div class="ajax">
+(#FORMULAIRE_CONFIGURER_SEO_URLS_CANONIQUES)
+</div>]
+
+<br />
+
+[<div class="ajax">
+(#FORMULAIRE_CONFIGURER_SEO_WEBMASTER_TOOLS)
+</div>]
+
+[<div class="ajax">
+(#FORMULAIRE_CONFIGURER_SEO_BING)
+</div>]
+
+<br />
+
+[<div class="ajax">
+(#FORMULAIRE_CONFIGURER_SEO_GANALYTICS)
+</div>]
+
+<br />
+
+[<div class="ajax">
+(#FORMULAIRE_CONFIGURER_SEO_ALEXA)
+</div>]
\ No newline at end of file
diff --git a/www/plugins/seo-v1/prive/squelettes/contenu/configurer_seo.html b/www/plugins/seo-v1/prive/squelettes/contenu/configurer_seo.html
new file mode 100644 (file)
index 0000000..1e401d9
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=prive/configurer_seo} />
diff --git a/www/plugins/seo-v1/prive/squelettes/inclure/seo_metas.html b/www/plugins/seo-v1/prive/squelettes/inclure/seo_metas.html
new file mode 100644 (file)
index 0000000..08278e3
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="ajax">
+       #FORMULAIRE_EDITER_SEO{#ENV{objet},#ENV{id_objet}}
+</div>
\ No newline at end of file
diff --git a/www/plugins/seo-v1/prive/style_prive_plugin_seo.html b/www/plugins/seo-v1/prive/style_prive_plugin_seo.html
new file mode 100644 (file)
index 0000000..9bbcc87
--- /dev/null
@@ -0,0 +1,26 @@
+[(#REM)
+
+       Ce squelette definit les styles de l'espace prive
+
+       Note: l'entete "Vary:" sert a repousser l'entete par
+       defaut "Vary: Cookie,Accept-Encoding", qui est (un peu)
+       genant en cas de "rotation du cookie de session" apres
+       un changement d'IP (effet de clignotement).
+
+       ATTENTION: il faut absolument le charset sinon Firefox croit que
+       c'est du text/html !
+]
+#CACHE{3600*100,cache-client}
+#HTTP_HEADER{Content-Type: text/css; charset=iso-8859-15}
+#HTTP_HEADER{Vary: Accept-Encoding}
+
+#SET{claire,##ENV{couleur_claire,edf3fe}}
+#SET{foncee,##ENV{couleur_foncee,3874b0}}
+
+[(#REM)
+       Dans SPIP 3.0 dans le privé, il y a une définition de l'id copyright avec un text-align à droite
+       On le rétabli à gauche pour les formulaires (ici on a un input)
+]
+.editer #copyright{
+       text-align:[(#ENV{left})];
+}
diff --git a/www/plugins/seo-v1/prive/themes/spip/images/seo-16.png b/www/plugins/seo-v1/prive/themes/spip/images/seo-16.png
new file mode 100644 (file)
index 0000000..c4a9d22
Binary files /dev/null and b/www/plugins/seo-v1/prive/themes/spip/images/seo-16.png differ
diff --git a/www/plugins/seo-v1/prive/themes/spip/images/seo-24.png b/www/plugins/seo-v1/prive/themes/spip/images/seo-24.png
new file mode 100644 (file)
index 0000000..c9f08ad
Binary files /dev/null and b/www/plugins/seo-v1/prive/themes/spip/images/seo-24.png differ
diff --git a/www/plugins/seo-v1/seo.png b/www/plugins/seo-v1/seo.png
new file mode 100644 (file)
index 0000000..c78641e
Binary files /dev/null and b/www/plugins/seo-v1/seo.png differ
diff --git a/www/plugins/seo-v1/seo_administrations.php b/www/plugins/seo-v1/seo_administrations.php
new file mode 100644 (file)
index 0000000..65999c3
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+include_spip('base/abstract_sql');
+
+// Installation et mise à jour
+function seo_upgrade($nom_meta_version_base, $version_cible){
+
+       $version_actuelle = '0.0';
+       if (
+               (!isset($GLOBALS['meta'][$nom_meta_version_base]))
+               || (($version_actuelle = $GLOBALS['meta'][$nom_meta_version_base])!=$version_cible)
+       ){
+               /* Installation normale */
+               if (version_compare($version_actuelle, '0.0', '=')){
+                       // Création des tables
+                       include_spip('base/create');
+                       creer_base();
+
+                       /**
+                        * La config de base active insert_head
+                        * (les utilisateurs n'ont pas à modifier leurs squelettes et à penser à l'activer)
+                        */
+                       $config_base = array();
+                       $config_base['insert_head']['activate'] = 'yes';
+                       ecrire_meta('seo', serialize($config_base), 'non');
+
+                       ecrire_meta($nom_meta_version_base, $version_actuelle = $version_cible, 'non');
+               }
+               /* Gestion des anciennes tables, la numérotation base était de 1.0 */
+               if (version_compare($version_actuelle, '1.0', '<=')){
+                       include_spip('base/create');
+
+                       // On change le nom de la table initialement mal choisi
+                       $prefixe = $GLOBALS['table_prefix'];
+                       sql_query("RENAME TABLE seo_meta_tags TO $prefixe" . "_seo");
+                       ecrire_meta($nom_meta_version_base, $version_actuelle = $version_cible, 'non');
+               }
+               if (version_compare($version_actuelle, '1.1.0', '<')){
+                       sql_alter('TABLE spip_seo DROP PRIMARY KEY');
+                       sql_alter('TABLE spip_seo CHANGE type_object objet varchar(10) NOT NULL');
+                       sql_alter('TABLE spip_seo CHANGE id_object id_objet int(11) NOT NULL');
+                       sql_alter('TABLE spip_seo ADD PRIMARY KEY ( `id_objet` , `objet` , `meta_name` )');
+                       ecrire_meta($nom_meta_version_base, $version_actuelle = $version_cible, 'non');
+               }
+               if (version_compare($version_actuelle, '1.1.1', '<')){
+                       if (defined('_SEO_FORCER_SQUELETTE'))
+                               ecrire_config('seo/forcer_squelette', 'yes');
+                       ecrire_meta($nom_meta_version_base, $version_actuelle = $version_cible, 'non');
+               }
+       }
+}
+
+// Désinstallation
+function seo_vider_tables($nom_meta_version_base){
+
+       // On efface la table du plugin
+       sql_drop_table('spip_seo');
+
+       // On efface la méta de configuration
+       effacer_meta('seo');
+
+       // On efface la version entregistrée
+       effacer_meta($nom_meta_version_base);
+}
diff --git a/www/plugins/seo-v1/seo_fonctions.php b/www/plugins/seo-v1/seo_fonctions.php
new file mode 100644 (file)
index 0000000..fc1a002
--- /dev/null
@@ -0,0 +1,275 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/texte');
+
+/**
+ * Renvoyer la balise <link> pour URL CANONIQUES
+ * @return string $flux
+ */
+function generer_urls_canoniques(){
+       include_spip('balise/url_');
+
+       if (count($GLOBALS['contexte'])==0){
+               $objet = 'sommaire';
+       } elseif (isset($GLOBALS['contexte']['id_article'])) {
+               $id_objet = $GLOBALS['contexte']['id_article'];
+               $objet = 'article';
+       } elseif (isset($GLOBALS['contexte']['id_rubrique'])) {
+               $id_objet = $GLOBALS['contexte']['id_rubrique'];
+               $objet = 'rubrique';
+       }
+
+       switch ($objet) {
+               case 'sommaire':
+                       $flux .= '<link rel="canonical" href="' . url_de_base() . '" />';
+                       break;
+               default:
+                       $flux .= '<link rel="canonical" href="' . url_de_base() . generer_url_entite($id_objet, $objet) . '" />';
+                       break;
+       }
+
+       return $flux;
+}
+
+/**
+ * Renvoyer la balise SCRIPT de Google Analytics
+ * @return string $flux
+ */
+function generer_google_analytics(){
+       /* CONFIG */
+       $config = unserialize($GLOBALS['meta']['seo']);
+
+       /* GOOGLE ANALYTICS */
+       if ($config['analytics']['id']){
+               // Nouvelle balise : http://www.google.com/support/analytics/bin/answer.py?hl=fr_FR&answer=174090&utm_id=ad
+               $flux .= "<script type=\"text/javascript\">
+       var _gaq = _gaq || [];
+       _gaq.push(['_setAccount', '" . $config['analytics']['id'] . "']);
+       _gaq.push(['_trackPageview']);
+       (function() {
+               var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+               ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+               var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+       })();
+</script>
+";
+       }
+
+       return $flux;
+}
+
+/**
+ * Renvoyer les META Classiques
+ * - Meta Titre / Description / etc.
+ * @return string $flux
+ */
+function calculer_meta_tags(){
+
+    include_spip('inc/texte');
+
+       /* CONFIG */
+       $config = unserialize($GLOBALS['meta']['seo']);
+
+       if (isset($GLOBALS['contexte']['id_article'])){
+               $id_objet = $GLOBALS['contexte']['id_article'];
+               $objet = 'article';
+       } elseif (isset($GLOBALS['contexte']['id_rubrique'])) {
+               $id_objet = $GLOBALS['contexte']['id_rubrique'];
+               $objet = 'rubrique';
+       } else {
+               $objet = 'sommaire';
+       }
+
+       /* META TAGS */
+
+       // If the meta tags configuration is activate
+       $meta_tags = array();
+
+       switch ($objet) {
+               case 'sommaire':
+                       $meta_tags = $config['meta_tags']['tag'];
+                       break;
+               default:
+                       $table = table_objet_sql($objet);
+                       $id_table_objet = id_table_objet($objet);
+                       $title = couper(sql_getfetsel("titre", $table, "$id_table_objet = " . intval($id_objet)), 64);
+                       $requete = sql_allfetsel("descriptif,texte", $table, "$id_table_objet = " . intval($id_objet));
+                       if ($requete) $description = couper(implode(" ", $requete[0]), 150, '');
+                       // Get the value set by default
+                       foreach ($config['meta_tags']['default'] as $name => $option){
+                               if ($option=='sommaire'){
+                                       $meta_tags[$name] = $config['meta_tags']['tag'][$name];
+                               } elseif ($option=='page') {
+                                       if ($name=='title') $meta_tags['title'] = $title;
+                                       if ($name=='description') $meta_tags['description'] = $description;
+                               } elseif ($option=='page_sommaire') {
+                                       if ($name=='title') $meta_tags['title'] = $title . (($title!='') ? ' - ' : '') . $config['meta_tags']['tag'][$name];
+                                       if ($name=='description') $meta_tags['description'] = $description . (($description!='') ? ' - ' : '') . $config['meta_tags']['tag'][$name];
+                               }
+                       }
+
+                       // If the meta tags rubrique and articles editing is activate (should overwrite other setting)
+                       if ($config['meta_tags']['activate_editing']=='yes' && ($objet=='article' || $objet=='rubrique')){
+                               $result = sql_select("*", "spip_seo", "id_objet = " . intval($id_objet) . " AND objet = " . sql_quote($objet));
+                               while ($r = sql_fetch($result)){
+                                       if ($r['meta_content']!='')
+                                               $meta_tags[$r['meta_name']] = $r['meta_content'];
+                               }
+                       }
+                       break;
+       }
+
+       return $meta_tags;
+}
+
+function generer_meta_tags($meta_tags = null){
+       $flux = '';
+       //Set meta list if not provided
+       if (!is_array($meta_tags))
+               $meta_tags = calculer_meta_tags();
+
+       // Print the result on the page
+       foreach ($meta_tags as $name => $content){
+               if ($content!='')
+                       if ($name=='title')
+                               $flux .= '<title>' . trim(htmlspecialchars(supprimer_numero(textebrut(propre($content))))) . '</title>' . "\n";
+                       else
+                               $flux .= '<meta name="' . $name . '" content="' . trim(htmlspecialchars(textebrut(propre($content)))) . '" />' . "\n";
+
+       }
+       return $flux;
+}
+
+/**
+ * Renvoyer une META toute seule (hors balise)
+ * @param string $nom
+ * @return string|bool
+ */
+function generer_meta_brute($nom){
+       $config = unserialize($GLOBALS['meta']['seo']);
+       $nom = strtolower($nom);
+
+       if ($config['meta_tags']['tag'][$nom]){
+               return $config['meta_tags']['tag'][$nom];
+       }
+
+       return false;
+}
+
+/**
+ * Renvoyer la META GOOGLE WEBMASTER TOOLS
+ * @return string $flux
+ */
+function generer_webmaster_tools(){
+       /* CONFIG */
+       $config = unserialize($GLOBALS['meta']['seo']);
+
+       if ($config['webmaster_tools']['id'])
+               return '<meta name="google-site-verification" content="' . $config['webmaster_tools']['id'] . '" />
+               ';
+}
+
+
+/**
+ * Renvoyer la META BING TOOLS
+ * @return string $flux
+ */
+function generer_bing(){
+       /* CONFIG */
+       $config = unserialize($GLOBALS['meta']['seo']);
+
+       if ($config['bing']['id'])
+               return '<meta name="msvalidate.01" content="' . $config['bing']['id'] . '" />
+               ';
+}
+
+/**
+ * Renvoyer la META ALEXA
+ * @return string $flux
+ */
+function generer_alexa(){
+       /* CONFIG */
+       $config = unserialize($GLOBALS['meta']['seo']);
+
+       if ($config['alexa']['id'])
+               return '<meta name="alexaVerifyID" content="' . $config['alexa']['id'] . '"/>';
+}
+
+/**
+ * #SEO_URL
+ * Renvoyer la balise <link> pour URL CANONIQUES
+ */
+function balise_SEO_URL($p){
+       $p->code = "calculer_balise_SEO_URL()";
+       return $p;
+}
+
+function calculer_balise_SEO_URL(){
+       $flux = generer_urls_canoniques();
+       return $flux;
+}
+
+/**
+ * #SEO_GA
+ * Renvoyer la balise SCRIPT de Google Analytics
+ */
+function balise_SEO_GA($p){
+       $p->code = "calculer_balise_SEO_GA()";
+       return $p;
+}
+
+function calculer_balise_SEO_GA(){
+       $flux = generer_google_analytics();
+       return $flux;
+}
+
+/**
+ * #SEO_META_TAGS
+ * Renvoyer les META Classiques
+ * - Meta Titre / Description / etc.
+ */
+function balise_SEO_META_TAGS($p){
+       $p->code = "calculer_balise_SEO_META_TAGS()";
+       return $p;
+}
+
+function calculer_balise_SEO_META_TAGS(){
+       $flux = generer_meta_tags();
+       return $flux;
+}
+
+/**
+ * #SEO_META_BRUTE{nom_de_la_meta}
+ * Renvoyer la valeur de la meta appelée (sans balise)
+ */
+function balise_SEO_META_BRUTE($p){
+       $_nom = str_replace("'", "", interprete_argument_balise(1, $p));
+       $p->code = "calculer_balise_META_BRUTE($_nom)";
+       $p->interdire_scripts = false;
+       return $p;
+}
+
+function calculer_balise_META_BRUTE($_nom){
+       $metas = calculer_meta_tags();
+       $meta = $metas[$_nom];
+       if (!$meta)
+               return "";
+       return $meta;
+}
+
+/**
+ * #SEO_GWT
+ * Renvoyer la META GOOGLE WEBMASTER TOOLS
+ */
+function balise_SEO_GWT($p){
+       $p->code = "calculer_balise_SEO_GWT()";
+       return $p;
+}
+
+function calculer_balise_SEO_GWT(){
+       $flux = generer_webmaster_tools();
+       return $flux;
+}
+
diff --git a/www/plugins/seo-v1/svn.revision b/www/plugins/seo-v1/svn.revision
new file mode 100644 (file)
index 0000000..1df081a
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/seo/branches/v1
+Revision: 72291
+Dernier commit: 2013-04-24 12:00:10 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/seo/branches/v1</origine>
+<revision>72291</revision>
+<commit>2013-04-24 12:00:10 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/spip-bonux-3/demo/boucle_et_saut.html b/www/plugins/spip-bonux-3/demo/boucle_et_saut.html
new file mode 100644 (file)
index 0000000..c43b737
--- /dev/null
@@ -0,0 +1,15 @@
+[(#REM)
+
+  Squelette
+  (c) 2009 xxx
+  Distribue sous licence GPL
+
+]
+<BOUCLE_art(ARTICLES){par id_article}{0,10}{'-'}>
+#TOTAL_BOUCLE:#COMPTEUR_BOUCLE:#ID_ARTICLE
+</BOUCLE_art>
+<hr />
+<BOUCLE_art2(ARTICLES){par id_article}{0,10}{'-'}>
+#TOTAL_BOUCLE:#COMPTEUR_BOUCLE:#ID_ARTICLE
+[(#SAUTER{1})]
+</BOUCLE_art2>
diff --git a/www/plugins/spip-bonux-3/demo/boucles_iterations.html b/www/plugins/spip-bonux-3/demo/boucles_iterations.html
new file mode 100644 (file)
index 0000000..004663d
--- /dev/null
@@ -0,0 +1,37 @@
+<BOUCLE_test10(POUR){tableau 1:10}>
+#CLE/#VALEUR<br />
+</BOUCLE_test10>
+#TOTAL_BOUCLE
+</B_test10>
+
+<hr />
+<BOUCLE_test11(POUR){tableau 1:2:10}>
+#CLE/#VALEUR<br />
+</BOUCLE_test11>
+#TOTAL_BOUCLE
+</B_test11>
+
+<hr />
+
+<BOUCLE_test12(POUR){tableau 10:-2:1}>
+#CLE/#VALEUR<br />
+</BOUCLE_test12>
+#TOTAL_BOUCLE
+</B_test12>
+
+<B_test13>
+       <p class="pagination">#PAGINATION</p>
+<BOUCLE_test13(POUR){tableau 1:100}{pagination}>
+#CLE/#VALEUR<br />
+</BOUCLE_test13>
+[#TOTAL_BOUCLE/#GRAND_TOTAL]
+</B_test13>
+
+<hr />
+
+<BOUCLE_test14(POUR){tableau 1:7}>
+       <BOUCLE_test15(POUR){tableau 1:#VALEUR}>
+       #VALEUR
+       </BOUCLE_test15>
+       <br />
+</BOUCLE_test14>
diff --git a/www/plugins/spip-bonux-3/demo/noeud.html b/www/plugins/spip-bonux-3/demo/noeud.html
new file mode 100644 (file)
index 0000000..8444005
--- /dev/null
@@ -0,0 +1,16 @@
+[(#REM)
+
+  Squelette
+  (c) xxx
+  Distribue sous licence GPL
+
+]
+#CACHE{0}
+
+<BOUCLE_rubn(RUBRIQUES){noeud}>
+<li>#ID_RUBRIQUE</li>
+</BOUCLE_rubn>
+<hr />
+<BOUCLE_rubf(RUBRIQUES){!feuille}>
+<li>#ID_RUBRIQUE</li>
+</BOUCLE_rubf>
\ No newline at end of file
diff --git a/www/plugins/spip-bonux-3/img_pack/annuler-recherche.png b/www/plugins/spip-bonux-3/img_pack/annuler-recherche.png
new file mode 100644 (file)
index 0000000..8252930
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/annuler-recherche.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/article-12.png b/www/plugins/spip-bonux-3/img_pack/article-12.png
new file mode 100644 (file)
index 0000000..35d3d3d
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/article-12.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/deplier-droite.gif b/www/plugins/spip-bonux-3/img_pack/deplier-droite.gif
new file mode 100644 (file)
index 0000000..b6a570d
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/deplier-droite.gif differ
diff --git a/www/plugins/spip-bonux-3/img_pack/deplier-droite.png b/www/plugins/spip-bonux-3/img_pack/deplier-droite.png
new file mode 100644 (file)
index 0000000..2865fd0
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/deplier-droite.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/frame-close.png b/www/plugins/spip-bonux-3/img_pack/frame-close.png
new file mode 100644 (file)
index 0000000..5dab592
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/frame-close.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/item-add.gif b/www/plugins/spip-bonux-3/img_pack/item-add.gif
new file mode 100644 (file)
index 0000000..33faedb
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/item-add.gif differ
diff --git a/www/plugins/spip-bonux-3/img_pack/item-add.png b/www/plugins/spip-bonux-3/img_pack/item-add.png
new file mode 100644 (file)
index 0000000..c180e0f
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/item-add.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/item-remove.png b/www/plugins/spip-bonux-3/img_pack/item-remove.png
new file mode 100644 (file)
index 0000000..566f4f6
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/item-remove.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/logo-bonux.gif b/www/plugins/spip-bonux-3/img_pack/logo-bonux.gif
new file mode 100644 (file)
index 0000000..b3a220b
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/logo-bonux.gif differ
diff --git a/www/plugins/spip-bonux-3/img_pack/message_erreur-24.png b/www/plugins/spip-bonux-3/img_pack/message_erreur-24.png
new file mode 100644 (file)
index 0000000..f483cef
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/message_erreur-24.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/message_notice-24.png b/www/plugins/spip-bonux-3/img_pack/message_notice-24.png
new file mode 100644 (file)
index 0000000..27d3247
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/message_notice-24.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/message_ok-24.png b/www/plugins/spip-bonux-3/img_pack/message_ok-24.png
new file mode 100644 (file)
index 0000000..dfcdb41
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/message_ok-24.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/spip-bonux.png b/www/plugins/spip-bonux-3/img_pack/spip-bonux.png
new file mode 100644 (file)
index 0000000..fffbb43
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/spip-bonux.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/tri_asc-12.png b/www/plugins/spip-bonux-3/img_pack/tri_asc-12.png
new file mode 100644 (file)
index 0000000..5f21f7b
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/tri_asc-12.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/tri_asc-16.png b/www/plugins/spip-bonux-3/img_pack/tri_asc-16.png
new file mode 100644 (file)
index 0000000..89cfd50
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/tri_asc-16.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/tri_asc-24.png b/www/plugins/spip-bonux-3/img_pack/tri_asc-24.png
new file mode 100644 (file)
index 0000000..cf55fbf
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/tri_asc-24.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/tri_asc.png b/www/plugins/spip-bonux-3/img_pack/tri_asc.png
new file mode 100644 (file)
index 0000000..a8a2918
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/tri_asc.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/tri_desc-12.png b/www/plugins/spip-bonux-3/img_pack/tri_desc-12.png
new file mode 100644 (file)
index 0000000..c853769
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/tri_desc-12.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/tri_desc-16.png b/www/plugins/spip-bonux-3/img_pack/tri_desc-16.png
new file mode 100644 (file)
index 0000000..6d9d043
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/tri_desc-16.png differ
diff --git a/www/plugins/spip-bonux-3/img_pack/tri_desc-24.png b/www/plugins/spip-bonux-3/img_pack/tri_desc-24.png
new file mode 100644 (file)
index 0000000..f34ae54
Binary files /dev/null and b/www/plugins/spip-bonux-3/img_pack/tri_desc-24.png differ
diff --git a/www/plugins/spip-bonux-3/inc/date_gestion.php b/www/plugins/spip-bonux-3/inc/date_gestion.php
new file mode 100644 (file)
index 0000000..5fd2c99
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+/**
+ * Plugin Spip-Bonux
+ * Le plugin qui lave plus SPIP que SPIP
+ * (c) 2008 Mathieu Marcillaud, Cedric Morin, Romy Tetue
+ * Licence GPL
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Recuperer les champs date_xx et heure_xx, verifier leur coherence et les reformater
+ *
+ * @param string $suffixe
+ * @param bool $horaire
+ * @param array $erreurs
+ * @return int
+ */
+function verifier_corriger_date_saisie($suffixe,$horaire,&$erreurs){
+       include_spip('inc/filtres');
+       $date = _request("date_$suffixe").($horaire?' '.trim(_request("heure_$suffixe")).':00':'');
+       $date = recup_date($date);
+       if (!$date)
+               return '';
+       $ret = null;
+       if (!$ret=mktime(0,0,0,$date[1],$date[2],$date[0]))
+               $erreurs["date_$suffixe"] = _T('spip_bonux:erreur_date');
+       elseif (!$ret=mktime($date[3],$date[4],$date[5],$date[1],$date[2],$date[0]))
+               $erreurs["date_$suffixe"] = _T('spip_bonux:erreur_heure');
+       if ($ret){
+               if (trim(_request("date_$suffixe")!==($d=date('d/m/Y',$ret)))){
+                       $erreurs["date_$suffixe"] = _T('spip_bonux:erreur_date_corrigee');
+                       set_request("date_$suffixe",$d);
+               }
+               if ($horaire AND trim(_request("heure_$suffixe")!==($h=date('H:i',$ret)))){
+                       $erreurs["heure_$suffixe"] = _T('spip_bonux:erreur_heure_corrigee');
+                       set_request("heure_$suffixe",$h);
+               }
+       }
+       return $ret;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/spip-bonux-3/inc/exporter_csv.php b/www/plugins/spip-bonux-3/inc/exporter_csv.php
new file mode 100644 (file)
index 0000000..bad0aed
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Plugin Spip-Bonux
+ * Le plugin qui lave plus SPIP que SPIP
+ * (c) 2008 Mathieu Marcillaud, Cedric Morin, Romy Tetue
+ * Licence GPL
+ *
+ * Fonctions d'export d'une requete sql ou d'un tableau
+ * au format CSV
+ * Merge du plugin csv_import et spip-surcharges
+ *
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+include_spip('inc/charsets');
+include_spip('inc/filtres');
+include_spip('inc/texte');
+
+/**
+ * Exporter un champ pour un export CSV : pas de retour a la ligne,
+ * et echapper les guillements par des doubles guillemets
+ * @param string $champ
+ * @return string
+ */
+function exporter_csv_champ($champ) {
+       #$champ = str_replace("\r", "\n", $champ);
+       #$champ = preg_replace(",[\n]+,ms", "\n", $champ);
+       #$champ = str_replace("\n", ", ", $champ);
+       $champ = preg_replace(',[\s]+,ms', ' ', $champ);
+       $champ = str_replace('"', '""', $champ);
+       return '"'.$champ.'"';
+}
+
+/**
+ * Exporter une ligne complete au format CSV, avec delimiteur fourni
+ * @param array $ligne
+ * @param string $delim
+ * @return string
+ */
+function exporter_csv_ligne($ligne, $delim = ',', $importer_charset = null) {
+       $output = join($delim, array_map('exporter_csv_champ', $ligne))."\r\n";
+       if ($importer_charset){
+               $output = unicode2charset(html2unicode(charset2unicode($output)), $importer_charset);
+       }
+       return $output;
+}
+
+
+function inc_exporter_csv_dist($titre, $resource, $delim=',', $entetes = null,$envoyer = true){
+
+       $filename = preg_replace(',[^-_\w]+,', '_', translitteration(textebrut(typo($titre))));
+       
+       if ($delim == 'TAB') $delim = "\t";
+       if (!in_array($delim,array(',',';',"\t")))
+               $delim = ",";
+
+       $charset = $GLOBALS['meta']['charset'];
+       $importer_charset = null;
+       if ($delim == ',')
+               $extension = 'csv';
+       else {
+               $extension = 'xls';
+               # Excel n'accepte pas l'utf-8 ni les entites html... on transcode tout ce qu'on peut
+               $importer_charset = $charset = 'iso-8859-1';
+       }
+       $filename = "$filename.$extension";
+
+       if ($entetes AND is_array($entetes) AND count($entetes))
+               $output = exporter_csv_ligne($entetes,$delim,$importer_charset);
+
+       // on passe par un fichier temporaire qui permet de ne pas saturer la memoire
+       // avec les gros exports
+       $fichier = sous_repertoire(_DIR_CACHE,"export") . $filename;
+       $fp = fopen($fichier, 'w');
+       $length = fwrite($fp, $output);
+
+       while ($row=is_array($resource)?array_shift($resource):sql_fetch($resource)){
+               $output = exporter_csv_ligne($row,$delim,$importer_charset);
+               $length += fwrite($fp, $output);
+       }
+       fclose($fp);
+
+       if ($envoyer) {
+               Header("Content-Type: text/comma-separated-values; charset=$charset");
+               Header("Content-Disposition: attachment; filename=$filename");
+               //non supporte
+               //Header("Content-Type: text/plain; charset=$charset");
+               Header("Content-Length: $length");
+               ob_clean();
+    flush();
+    readfile($fichier);
+       }
+
+       return $fichier;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/spip-bonux-3/inc/importer_csv.php b/www/plugins/spip-bonux-3/inc/importer_csv.php
new file mode 100644 (file)
index 0000000..f09d392
--- /dev/null
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Plugin Spip-Bonux
+ * Le plugin qui lave plus SPIP que SPIP
+ * (c) 2008 Mathieu Marcillaud, Cedric Morin, Romy Tetue
+ * Licence GPL
+ * 
+ * Fonctions de lecture d'un fichier CSV pour transformation en array()
+ * 
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+include_spip('inc/charsets');
+
+/**
+ * Based on an example by ramdac at ramdac dot org
+ * Returns a multi-dimensional array from a CSV file optionally using the
+ * first row as a header to create the underlying data as associative arrays.
+ * @param string $file Filepath including filename
+ * @param bool $head Use first row as header.
+ * @param string $delim Specify a delimiter other than a comma.
+ * @param int $len Line length to be passed to fgetcsv
+ * @return array or false on failure to retrieve any rows.
+ */
+
+/**
+ * Importer le charset d'une ligne
+ *
+ * @param unknown_type $texte
+ * @return array
+ */
+function importer_csv_importcharset($texte){
+       // le plus frequent, en particulier avec les trucs de ms@@@
+       $charset_source = 'iso-8859-1';
+       // mais open-office sait faire mieux, donc mefiance !
+       if (is_utf8($texte))
+               $charset_source = 'utf-8';
+       return importer_charset($texte,$charset_source);
+}
+
+/**
+ * enlever les accents des cles presentes dans le head,
+ * sinon ca pose des problemes ...
+ *
+ * @param string $key
+ * @return string
+ */
+function importer_csv_nettoie_key($key){
+       return translitteration($key);
+       /*$accents=array('�','�','�','�','�',"�","�","'");
+       $accents_rep=array('e','e','e','a','u',"o","c","_");
+       return str_replace($accents,$accents_rep,$key);*/
+}
+
+/**
+ * Lit un fichier csv et retourne un tableau
+ * si $head est true, la premiere ligne est utilisee en header
+ * pour generer un tableau associatif
+ *
+ * @param string $file
+ * @param bool $head
+ * @param string $delim
+ * @param string $enclos
+ * @param int $len
+ * @return array
+ */
+function inc_importer_csv_dist($file, $head = false, $delim = ",", $enclos = '"', $len = 10000) {
+       $return = false;
+       if (@file_exists($file)
+               AND $handle = fopen($file, "r")){
+               if ($head) {
+                       $header = fgetcsv($handle, $len, $delim, $enclos);
+                       if ($header){
+                               $header = array_map('importer_csv_importcharset',$header);
+                               $header = array_map('importer_csv_nettoie_key',$header);
+                               $header_type = array();
+                               foreach ($header as $heading) {
+                                       if (!isset($header_type[$heading]))
+                                               $header_type[$heading] = "scalar";
+                                       else
+                                               $header_type[$heading] = "array";
+                               }
+                       }
+               }
+               while (($data = fgetcsv($handle, $len, $delim, $enclos)) !== FALSE) {
+                       $data = array_map('importer_csv_importcharset',$data);
+                       if ($head AND isset($header)) {
+                               $row = array();
+                               foreach ($header as $key=>$heading) {
+                                       if ($header_type[$heading]=="array"){
+                                               if (!isset($row[$heading]))
+                                                       $row[$heading] = array();
+                                               if (isset($data[$key]) AND strlen($data[$key]))
+                                                       $row[$heading][]= $data[$key];
+                                       }
+                                       else
+                                               $row[$heading]=(isset($data[$key])) ? $data[$key] : '';
+                               }
+                               $return[]=$row;
+                       } else {
+                               $return[]=$data;
+                       }
+               }
+       }
+       return $return;
+}
+
diff --git a/www/plugins/spip-bonux-3/javascript/jquery.qtip-1.0.0-rc3.js b/www/plugins/spip-bonux-3/javascript/jquery.qtip-1.0.0-rc3.js
new file mode 100644 (file)
index 0000000..b71c021
--- /dev/null
@@ -0,0 +1,2040 @@
+/*!
+* jquery.qtip. The jQuery tooltip plugin
+*
+* Copyright (c) 2009 Craig Thompson
+* http://craigsworks.com
+*
+* Licensed under MIT
+* http://www.opensource.org/licenses/mit-license.php
+*
+* Launch  : February 2009
+* Version : 1.0.0-rc3
+* Released: Tuesday 12th May, 2009 - 00:00
+* Debug: jquery.qtip.debug.js
+*/
+
+"use strict"; // Enable ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
+/*jslint browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, bitwise: true, regexp: true, strict: true, newcap: true, immed: true */
+
+/*global window: false, jQuery: false */
+(function ($) {
+       // Assign cache and event initialisation on document load
+       $(document).ready(function () {
+               // Adjust positions of the tooltips on window resize or scroll if enabled
+               var i;
+               $(window).bind('resize scroll', function (event) {
+                       for (i = 0; i < $.fn.qtip.interfaces.length; i++) {
+                               // Access current elements API
+                               var api = $.fn.qtip.interfaces[i];
+
+                               // Update position if resize or scroll adjustments are enabled
+                               if(api && api.status && api.status.rendered && api.options.position.type !== 'static' && api.elements.tooltip.is(':visible') &&
+                               (api.options.position.adjust.scroll && event.type === 'scroll' || api.options.position.adjust.resize && event.type === 'resize')) {
+                                       // Queue the animation so positions are updated correctly
+                                       api.updatePosition(event, true);
+                               }
+                       }
+               });
+
+               // Hide unfocus toolipts on document mousedown
+               $(document).bind('mouseenter.qtip', function (event) {
+                       if($(event.target).parents('div.qtip').length === 0) {
+                               var tooltip = $('.qtipSelector'),
+                                       api = tooltip.qtip('api');
+
+                               // Only hide if its visible and not the tooltips target
+                               if(tooltip.is(':visible') && api && api.status && !api.status.disabled && $(event.target).add(api.elements.target).length > 1) { api.hide(event); }
+                       }
+               });
+       });
+
+       // Corner object parser
+       function Corner(corner) {
+               if(!corner){ return false; }
+
+               this.x = String(corner).replace(/middle/i, 'center').match(/left|right|center/i)[0].toLowerCase();
+               this.y = String(corner).replace(/middle/i, 'center').match(/top|bottom|center/i)[0].toLowerCase();
+               this.offset = { left: 0, top: 0 };
+               this.precedance = (corner.charAt(0).search(/^(t|b)/) > -1) ? 'y' : 'x';
+               this.string = function(){ return (this.precedance === 'y') ? this.y+this.x : this.x+this.y; };
+       }
+
+       // Tip coordinates calculator
+       function calculateTip(corner, width, height) {
+               // Define tip coordinates in terms of height and width values
+               var tips = {
+                       bottomright: [[0, 0], [width, height], [width, 0]],
+                       bottomleft: [[0, 0], [width, 0], [0, height]],
+                       topright: [[0, height], [width, 0], [width, height]],
+                       topleft: [[0, 0], [0, height], [width, height]],
+                       topcenter: [[0, height], [width / 2, 0], [width, height]],
+                       bottomcenter: [[0, 0], [width, 0], [width / 2, height]],
+                       rightcenter: [[0, 0], [width, height / 2], [0, height]],
+                       leftcenter: [[width, 0], [width, height], [0, height / 2]]
+               };
+               tips.lefttop = tips.bottomright;
+               tips.righttop = tips.bottomleft;
+               tips.leftbottom = tips.topright;
+               tips.rightbottom = tips.topleft;
+
+               return tips[corner];
+       }
+
+       // Border coordinates calculator
+       function calculateBorders(radius) {
+               var borders;
+
+               // Use canvas element if supported
+               if($('<canvas />').get(0).getContext) {
+                       borders = {
+                               topLeft: [radius, radius],
+                               topRight: [0, radius],
+                               bottomLeft: [radius, 0],
+                               bottomRight: [0, 0]
+                       };
+               }
+
+               // Canvas not supported - Use VML (IE)
+               else if($.browser.msie) {
+                       borders = {
+                               topLeft: [-90, 90, 0],
+                               topRight: [-90, 90, -radius],
+                               bottomLeft: [90, 270, 0],
+                               bottomRight: [90, 270, -radius]
+                       };
+               }
+
+               return borders;
+       }
+
+
+       // Build a jQuery style object from supplied style object
+       function jQueryStyle(style, sub) {
+               var styleObj, i;
+
+               styleObj = $.extend(true, {}, style);
+               for (i in styleObj) {
+                       if(sub === true && (/(tip|classes)/i).test(i)) { delete styleObj[i]; }
+                       else if(!sub && (/(width|border|tip|title|classes|user)/i).test(i)) { delete styleObj[i]; }
+               }
+
+               return styleObj;
+       }
+
+       // Sanitize styles
+       function sanitizeStyle(style) {
+               if(typeof style.tip !== 'object') {
+                       style.tip = { corner: style.tip };
+               }
+               if(typeof style.tip.size !== 'object') {
+                       style.tip.size = {
+                               width: style.tip.size,
+                               height: style.tip.size
+                       };
+               }
+               if(typeof style.border !== 'object') {
+                       style.border = {
+                               width: style.border
+                       };
+               }
+               if(typeof style.width !== 'object') {
+                       style.width = {
+                               value: style.width
+                       };
+               }
+               if(typeof style.width.max === 'string') { style.width.max = parseInt(style.width.max.replace(/([0-9]+)/i, "$1"), 10); }
+               if(typeof style.width.min === 'string') { style.width.min = parseInt(style.width.min.replace(/([0-9]+)/i, "$1"), 10); }
+
+               // Convert deprecated x and y tip values to width/height
+               if(typeof style.tip.size.x === 'number') {
+                       style.tip.size.width = style.tip.size.x;
+                       delete style.tip.size.x;
+               }
+               if(typeof style.tip.size.y === 'number') {
+                       style.tip.size.height = style.tip.size.y;
+                       delete style.tip.size.y;
+               }
+
+               return style;
+       }
+
+       // Build styles recursively with inheritance
+       function buildStyle() {
+               var self, i, styleArray, styleExtend, finalStyle, ieAdjust;
+               self = this;
+
+               // Build style options from supplied arguments
+               styleArray = [true, {}];
+               for(i = 0; i < arguments.length; i++){ styleArray.push(arguments[i]); }
+               styleExtend = [$.extend.apply($, styleArray)];
+
+               // Loop through each named style inheritance
+               while(typeof styleExtend[0].name === 'string') {
+                       // Sanitize style data and append to extend array
+                       styleExtend.unshift(sanitizeStyle($.fn.qtip.styles[styleExtend[0].name]));
+               }
+
+               // Make sure resulting tooltip className represents final style
+               styleExtend.unshift(true, {
+                       classes: {
+                               tooltip: 'qtip-' + (arguments[0].name || 'defaults')
+                       }
+               }, $.fn.qtip.styles.defaults);
+
+               // Extend into a single style object
+               finalStyle = $.extend.apply($, styleExtend);
+
+               // Adjust tip size if needed (IE 1px adjustment bug fix)
+               ieAdjust = ($.browser.msie) ? 1 : 0;
+               finalStyle.tip.size.width += ieAdjust;
+               finalStyle.tip.size.height += ieAdjust;
+
+               // Force even numbers for pixel precision
+               if(finalStyle.tip.size.width % 2 > 0) { finalStyle.tip.size.width += 1; }
+               if(finalStyle.tip.size.height % 2 > 0) { finalStyle.tip.size.height += 1; }
+
+               // Sanitize final styles tip corner value
+               if(finalStyle.tip.corner === true) {
+                       if(self.options.position.corner.tooltip === 'center' && self.options.position.corner.target === 'center') {
+                               finalStyle.tip.corner = false;
+                       }
+                       else {
+                               finalStyle.tip.corner = self.options.position.corner.tooltip;
+                       }
+               }
+
+               return finalStyle;
+       }
+
+       // Border canvas draw method
+       function drawBorder(canvas, coordinates, radius, color) {
+               // Create corner
+               var context = canvas.get(0).getContext('2d');
+               context.fillStyle = color;
+               context.beginPath();
+               context.arc(coordinates[0], coordinates[1], radius, 0, Math.PI * 2, false);
+               context.fill();
+       }
+
+       // Create borders using canvas and VML
+       function createBorder() {
+               var self, i, width, radius, color, coordinates, containers, size, betweenWidth, betweenCorners, borderTop, borderBottom, borderCoord, sideWidth, vertWidth;
+               self = this;
+
+               // Destroy previous border elements, if present
+               self.elements.wrapper.find('.qtip-borderBottom, .qtip-borderTop').remove();
+
+               // Setup local variables
+               width = self.options.style.border.width;
+               radius = self.options.style.border.radius;
+               color = self.options.style.border.color || self.options.style.tip.color;
+
+               // Calculate border coordinates
+               coordinates = calculateBorders(radius);
+
+               // Create containers for the border shapes
+               containers = {};
+               for (i in coordinates) {
+                       // Create shape container
+                       containers[i] = '<div rel="' + i + '" style="' + ((/Left/).test(i) ? 'left' : 'right') + ':0; ' + 'position:absolute; height:' + radius + 'px; width:' + radius + 'px; overflow:hidden; line-height:0.1px; font-size:1px">';
+
+                       // Canvas is supported
+                       if($('<canvas />').get(0).getContext) { containers[i] += '<canvas height="' + radius + '" width="' + radius + '" style="vertical-align: top"></canvas>'; }
+
+                       // No canvas, but if it's IE use VML
+                       else if($.browser.msie) {
+                               size = radius * 2 + 3;
+                               containers[i] += '<v:arc stroked="false" fillcolor="' + color + '" startangle="' + coordinates[i][0] + '" endangle="' + coordinates[i][1] + '" ' + 'style="width:' + size + 'px; height:' + size + 'px; margin-top:' + ((/bottom/).test(i) ? -2 : -1) + 'px; ' + 'margin-left:' + ((/Right/).test(i) ? coordinates[i][2] - 3.5 : -1) + 'px; ' + 'vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>';
+
+                       }
+
+                       containers[i] += '</div>';
+               }
+
+               // Create between corners elements
+               betweenWidth = self.getDimensions().width - (Math.max(width, radius) * 2);
+               betweenCorners = '<div class="qtip-betweenCorners" style="height:' + radius + 'px; width:' + betweenWidth + 'px; ' + 'overflow:hidden; background-color:' + color + '; line-height:0.1px; font-size:1px;">';
+
+               // Create top border container
+               borderTop = '<div class="qtip-borderTop" dir="ltr" style="height:' + radius + 'px; ' + 'margin-left:' + radius + 'px; line-height:0.1px; font-size:1px; padding:0;">' + containers.topLeft + containers.topRight + betweenCorners;
+               self.elements.wrapper.prepend(borderTop);
+
+               // Create bottom border container
+               borderBottom = '<div class="qtip-borderBottom" dir="ltr" style="height:' + radius + 'px; ' + 'margin-left:' + radius + 'px; line-height:0.1px; font-size:1px; padding:0;">' + containers.bottomLeft + containers.bottomRight + betweenCorners;
+               self.elements.wrapper.append(borderBottom);
+
+               // Draw the borders if canvas were used (Delayed til after DOM creation)
+               if($('<canvas />').get(0).getContext) {
+                       self.elements.wrapper.find('canvas').each(function () {
+                               borderCoord = coordinates[$(this).parent('[rel]:first').attr('rel')];
+                               drawBorder.call(self, $(this), borderCoord, radius, color);
+                       });
+               }
+
+               // Create a phantom VML element (IE won't show the last created VML element otherwise)
+               else if($.browser.msie) { self.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>'); }
+
+               // Setup contentWrapper border
+               sideWidth = Math.max(radius, (radius + (width - radius)));
+               vertWidth = Math.max(width - radius, 0);
+               self.elements.contentWrapper.css({
+                       border: '0px solid ' + color,
+                       borderWidth: vertWidth + 'px ' + sideWidth + 'px'
+               });
+       }
+
+       // Canvas tip drawing method
+       function drawTip(canvas, coordinates, color) {
+               // Setup properties
+               var context = canvas.get(0).getContext('2d');
+               context.fillStyle = color;
+
+               // Create tip
+               context.beginPath();
+               context.moveTo(coordinates[0][0], coordinates[0][1]);
+               context.lineTo(coordinates[1][0], coordinates[1][1]);
+               context.lineTo(coordinates[2][0], coordinates[2][1]);
+               context.fill();
+       }
+
+       function positionTip(corner) {
+               var self, ieAdjust, positionAdjust, paddingCorner, paddingSize, newMargin;
+               self = this;
+
+               // Return if tips are disabled or tip is not yet rendered
+               if(self.options.style.tip.corner === false || !self.elements.tip) { return; }
+               if(!corner) { corner = new Corner(self.elements.tip.attr('rel')); }
+
+               // Setup adjustment variables
+               ieAdjust = positionAdjust = ($.browser.msie) ? 1 : 0;
+
+               // Set initial position
+               self.elements.tip.css(corner[corner.precedance], 0);
+
+               // Set position of tip to correct side
+               if(corner.precedance === 'y') {
+                       // Adjustments for IE6 - 0.5px border gap bug
+                       if($.browser.msie) {
+                               if(parseInt($.browser.version.charAt(0), 10) === 6) { positionAdjust = corner.y === 'top' ? -3 : 1; }
+                               else { positionAdjust = corner.y === 'top' ? 1 : 2; }
+                       }
+
+                       if(corner.x === 'center') {
+                               self.elements.tip.css({
+                                       left: '50%',
+                                       marginLeft: -(self.options.style.tip.size.width / 2)
+                               });
+                       }
+                       else if(corner.x === 'left') {
+                               self.elements.tip.css({
+                                       left: self.options.style.border.radius - ieAdjust
+                               });
+                       }
+                       else {
+                               self.elements.tip.css({
+                                       right: self.options.style.border.radius + ieAdjust
+                               });
+                       }
+
+                       if(corner.y === 'top') {
+                               self.elements.tip.css({
+                                       top: -positionAdjust
+                               });
+                       }
+                       else {
+                               self.elements.tip.css({
+                                       bottom: positionAdjust
+                               });
+                       }
+
+               }
+               else {
+                       // Adjustments for IE6 - 0.5px border gap bug
+                       if($.browser.msie) {
+                               positionAdjust = (parseInt($.browser.version.charAt(0), 10) === 6) ? 1 : (corner.x === 'left' ? 1 : 2);
+                       }
+
+                       if(corner.y === 'center') {
+                               self.elements.tip.css({
+                                       top: '50%',
+                                       marginTop: -(self.options.style.tip.size.height / 2)
+                               });
+                       }
+                       else if(corner.y === 'top') {
+                               self.elements.tip.css({
+                                       top: self.options.style.border.radius - ieAdjust
+                               });
+                       }
+                       else {
+                               self.elements.tip.css({
+                                       bottom: self.options.style.border.radius + ieAdjust
+                               });
+                       }
+
+                       if(corner.x === 'left') {
+                               self.elements.tip.css({
+                                       left: -positionAdjust
+                               });
+                       }
+                       else {
+                               self.elements.tip.css({
+                                       right: positionAdjust
+                               });
+                       }
+               }
+
+               // Adjust tooltip padding to compensate for tip
+               paddingCorner = 'padding-' + corner[corner.precedance];
+               paddingSize = self.options.style.tip.size[corner.precedance === 'x' ? 'width' : 'height'];
+               self.elements.tooltip.css('padding', 0).css(paddingCorner, paddingSize);
+
+               // Match content margin to prevent gap bug in IE6 ONLY
+               if($.browser.msie && parseInt($.browser.version.charAt(0), 6) === 6) {
+                       newMargin = parseInt(self.elements.tip.css('margin-top'), 10) || 0;
+                       newMargin += parseInt(self.elements.content.css('margin-top'), 10) || 0;
+
+                       self.elements.tip.css({ marginTop: newMargin });
+               }
+       }
+
+       // Create tip using canvas and VML
+       function createTip(corner) {
+               var self, color, coordinates, coordsize, path, tip;
+               self = this;
+
+               // Destroy previous tip, if there is one
+               if(self.elements.tip !== null) { self.elements.tip.remove(); }
+
+               // Setup color and corner values
+               color = self.options.style.tip.color || self.options.style.border.color;
+               if(self.options.style.tip.corner === false) { return; }
+               else if(!corner) { corner = new Corner(self.options.style.tip.corner); }
+
+               // Calculate tip coordinates
+               coordinates = calculateTip(corner.string(), self.options.style.tip.size.width, self.options.style.tip.size.height);
+
+               // Create tip element
+               self.elements.tip = '<div class="' + self.options.style.classes.tip + '" dir="ltr" rel="' + corner.string() + '" style="position:absolute; ' + 'height:' + self.options.style.tip.size.height + 'px; width:' + self.options.style.tip.size.width + 'px; ' + 'margin:0 auto; line-height:0.1px; font-size:1px;"></div>';
+
+               // Attach new tip to tooltip element
+               self.elements.tooltip.prepend(self.elements.tip);
+
+               // Use canvas element if supported
+               if($('<canvas />').get(0).getContext) { tip = '<canvas height="' + self.options.style.tip.size.height + '" width="' + self.options.style.tip.size.width + '"></canvas>'; }
+
+               // Canvas not supported - Use VML (IE)
+               else if($.browser.msie) {
+                       // Create coordize and tip path using tip coordinates
+                       coordsize = self.options.style.tip.size.width + ',' + self.options.style.tip.size.height;
+                       path = 'm' + coordinates[0][0] + ',' + coordinates[0][1];
+                       path += ' l' + coordinates[1][0] + ',' + coordinates[1][1];
+                       path += ' ' + coordinates[2][0] + ',' + coordinates[2][1];
+                       path += ' xe';
+
+                       // Create VML element
+                       tip = '<v:shape fillcolor="' + color + '" stroked="false" filled="true" path="' + path + '" coordsize="' + coordsize + '" ' + 'style="width:' + self.options.style.tip.size.width + 'px; height:' + self.options.style.tip.size.height + 'px; ' + 'line-height:0.1px; display:inline-block; behavior:url(#default#VML); ' + 'vertical-align:' + (corner.y === 'top' ? 'bottom' : 'top') + '"></v:shape>';
+
+                       // Create a phantom VML element (IE won't show the last created VML element otherwise)
+                       tip += '<v:image style="behavior:url(#default#VML);"></v:image>';
+
+                       // Prevent tooltip appearing above the content (IE z-index bug)
+                       self.elements.contentWrapper.css('position', 'relative');
+               }
+
+               // Create element reference and append vml/canvas
+               self.elements.tip = self.elements.tooltip.find('.' + self.options.style.classes.tip).eq(0);
+               self.elements.tip.html(tip);
+
+               // Draw the canvas tip (Delayed til after DOM creation)
+               if($('<canvas  />').get(0).getContext) { drawTip.call(self, self.elements.tip.find('canvas:first'), coordinates, color); }
+
+               // Fix IE small tip bug
+               if(corner.y === 'top' && $.browser.msie && parseInt($.browser.version.charAt(0), 10) === 6) {
+                       self.elements.tip.css({
+                               marginTop: -4
+                       });
+               }
+
+               // Set the tip position
+               positionTip.call(self, corner);
+       }
+
+       // Create title bar for content
+       function createTitle() {
+               var self = this;
+
+               // Destroy previous title element, if present
+               if(self.elements.title !== null) { self.elements.title.remove(); }
+
+               // Append new ARIA attribute to tooltip
+               self.elements.tooltip.attr('aria-labelledby', 'qtip-' + self.id + '-title');
+
+               // Create title element
+               self.elements.title = $('<div id="qtip-' + self.id + '-title" class="' + self.options.style.classes.title + '"></div>').css(jQueryStyle(self.options.style.title, true)).css({
+                       zoom: ($.browser.msie) ? 1 : 0
+               }).prependTo(self.elements.contentWrapper);
+
+               // Update title with contents if enabled
+               if(self.options.content.title.text) { self.updateTitle.call(self, self.options.content.title.text); }
+
+               // Create title close buttons if enabled
+               if(self.options.content.title.button !== false && typeof self.options.content.title.button === 'string') {
+                       self.elements.button = $('<a class="' + self.options.style.classes.button + '" role="button" style="float:right; position: relative"></a>').css(jQueryStyle(self.options.style.button, true)).html(self.options.content.title.button).prependTo(self.elements.title).click(function (event) {
+                               if(!self.status.disabled) { self.hide(event); }
+                       });
+               }
+       }
+
+       // Assign hide and show events
+       function assignEvents() {
+               var self, showTarget, hideTarget, inactiveEvents;
+               self = this;
+
+               // Setup event target variables
+               showTarget = self.options.show.when.target;
+               hideTarget = self.options.hide.when.target;
+
+               // Add tooltip as a hideTarget is its fixed
+               if(self.options.hide.fixed) { hideTarget = hideTarget.add(self.elements.tooltip); }
+
+               // Define events which reset the 'inactive' event handler
+               inactiveEvents = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove',
+                                                       'mouseout', 'mouseenter', 'mouseleave', 'mouseover'];
+
+               // Define 'inactive' event timer method
+               function inactiveMethod(event) {
+                       if(self.status.disabled === true) { return; }
+
+                       //Clear and reset the timer
+                       clearTimeout(self.timers.inactive);
+                       self.timers.inactive = setTimeout(function () {
+                               // Unassign 'inactive' events
+                               $(inactiveEvents).each(function () {
+                                       hideTarget.unbind(this + '.qtip-inactive');
+                                       self.elements.content.unbind(this + '.qtip-inactive');
+                               });
+
+                               // Hide the tooltip
+                               self.hide(event);
+                       }, self.options.hide.delay);
+               }
+
+               // Check if the tooltip is 'fixed'
+               if(self.options.hide.fixed === true) {
+                       self.elements.tooltip.bind('mouseover.qtip', function () {
+                               if(self.status.disabled === true) { return; }
+
+                               // Reset the hide timer
+                               clearTimeout(self.timers.hide);
+                       });
+               }
+
+               // Define show event method
+               function showMethod(event) {
+                       if(self.status.disabled === true) { return; }
+
+                       // If set, hide tooltip when inactive for delay period
+                       if(self.options.hide.when.event === 'inactive') {
+                               // Assign each reset event
+                               $(inactiveEvents).each(function () {
+                                       hideTarget.bind(this + '.qtip-inactive', inactiveMethod);
+                                       self.elements.content.bind(this + '.qtip-inactive', inactiveMethod);
+                               });
+
+                               // Start the inactive timer
+                               inactiveMethod();
+                       }
+
+                       // Clear hide timers
+                       clearTimeout(self.timers.show);
+                       clearTimeout(self.timers.hide);
+
+                       // Start show timer
+                       if(self.options.show.delay > 0) {
+                               self.timers.show = setTimeout(function () {
+                                       self.show(event);
+                               }, self.options.show.delay);
+                       }
+                       else {
+                               self.show(event);
+                       }
+               }
+
+               // Define hide event method
+               function hideMethod(event) {
+                       if(self.status.disabled === true) { return; }
+
+                       // Prevent hiding if tooltip is fixed and event target is the tooltip
+                       if(self.options.hide.fixed === true && (/mouse(out|leave)/i).test(self.options.hide.when.event) && $(event.relatedTarget).parents('div.qtip[id^="qtip"]').length > 0) {
+                               // Prevent default and popagation
+                               event.stopPropagation();
+                               event.preventDefault();
+
+                               // Reset the hide timer
+                               clearTimeout(self.timers.hide);
+                               return false;
+                       }
+
+                       // Clear timers and stop animation queue
+                       clearTimeout(self.timers.show);
+                       clearTimeout(self.timers.hide);
+                       self.elements.tooltip.stop(true, true);
+
+                       // If tooltip has displayed, start hide timer
+                       self.timers.hide = setTimeout(function () {
+                               self.hide(event);
+                       }, self.options.hide.delay);
+               }
+
+               // If mouse is the target, update tooltip position on mousemove
+               if(self.options.position.target === 'mouse' && self.options.position.type !== 'static') {
+                       showTarget.bind('mousemove.qtip', function (event) {
+                               // Set the new mouse positions if adjustment is enabled
+                               self.cache.mouse = {
+                                       left: event.pageX,
+                                       top: event.pageY
+                               };
+
+                               // Update the tooltip position only if the tooltip is visible and adjustment is enabled
+                               if(self.status.disabled === false && self.options.position.adjust.mouse === true && self.options.position.type !== 'static' && self.elements.tooltip.css('display') !== 'none') {
+                                       self.updatePosition(event);
+                               }
+                       });
+               }
+
+               // Both events and targets are identical, apply events using a toggle
+               if((self.options.show.when.target.add(self.options.hide.when.target).length === 1 &&
+               self.options.show.when.event === self.options.hide.when.event && self.options.hide.when.event !== 'inactive') ||
+               self.options.hide.when.event === 'unfocus') {
+                       self.cache.toggle = 0;
+                       // Use a toggle to prevent hide/show conflicts
+                       showTarget.bind(self.options.show.when.event + '.qtip', function (event) {
+                               if(self.cache.toggle === 0) { showMethod(event); }
+                               else { hideMethod(event); }
+                       });
+               }
+
+               // Events are not identical, bind normally
+               else {
+                       showTarget.bind(self.options.show.when.event + '.qtip', showMethod);
+
+                       // If the hide event is not 'inactive', bind the hide method
+                       if(self.options.hide.when.event !== 'inactive') { hideTarget.bind(self.options.hide.when.event + '.qtip', hideMethod); }
+               }
+
+               // Focus the tooltip on mouseover
+               if((/(fixed|absolute)/).test(self.options.position.type)) { self.elements.tooltip.bind('mouseover.qtip', self.focus); }
+       }
+
+       // BGIFRAME JQUERY PLUGIN ADAPTION
+       //   Special thanks to Brandon Aaron for this plugin
+       //   http://plugins.jquery.com/project/bgiframe
+       function bgiframe() {
+               var self, html, dimensions;
+               self = this;
+               dimensions = self.getDimensions();
+
+               // Setup iframe HTML string
+               html = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" ' + 'style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; ' + 'height:' + dimensions.height + 'px; width:' + dimensions.width + 'px" />';
+
+               // Append the new HTML and setup element reference
+               self.elements.bgiframe = self.elements.wrapper.prepend(html).children('.qtip-bgiframe:first');
+       }
+
+       // Define primary construct function
+       function construct() {
+               var self, content, url, data, method;
+               self = this;
+
+               // Call API method
+               self.beforeRender.call(self);
+
+               // Set rendered status to true
+               self.status.rendered = 2;
+
+               // Create initial tooltip elements
+               self.elements.tooltip = '<div qtip="' + self.id + '" id="qtip-' + self.id + '" role="tooltip" ' + 'aria-describedby="qtip-' + self.id + '-content" class="qtip ' + (self.options.style.classes.tooltip || self.options.style) + '" ' + 'style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0; position:' + self.options.position.type + ';"> ' + '  <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;"> ' + '    <div class="qtip-contentWrapper" style="overflow:hidden;"> ' + '       <div id="qtip-' + self.id + '-content" class="qtip-content ' + self.options.style.classes.content + '"></div> ' + '</div></div></div>';
+
+               // Append to container element
+               self.elements.tooltip = $(self.elements.tooltip);
+               self.elements.tooltip.appendTo(self.options.position.container);
+
+               // Setup tooltip qTip data
+               self.elements.tooltip.data('qtip', {
+                       current: 0,
+                       interfaces: [self]
+               });
+
+               // Setup element references
+               self.elements.wrapper = self.elements.tooltip.children('div:first');
+               self.elements.contentWrapper = self.elements.wrapper.children('div:first');
+               self.elements.content = self.elements.contentWrapper.children('div:first').css(jQueryStyle(self.options.style));
+
+               // Apply IE hasLayout fix to wrapper and content elements
+               if($.browser.msie) { self.elements.wrapper.add(self.elements.content).css({ zoom: 1 }); }
+
+               // Setup tooltip attributes
+               if(self.options.hide.when.event === 'unfocus') { self.elements.tooltip.attr('unfocus', true); }
+
+               // If an explicit width is set, updateWidth prior to setting content to prevent dirty rendering
+               if(typeof self.options.style.width.value === 'number') { self.updateWidth(); }
+
+               // Create borders and tips if supported by the browser
+               if($('<canvas />').get(0).getContext || $.browser.msie) {
+                       // Create border
+                       if(self.options.style.border.radius > 0) { createBorder.call(self); }
+                       else {
+                               self.elements.contentWrapper.css({
+                                       border: self.options.style.border.width + 'px solid ' + self.options.style.border.color
+                               });
+                       }
+
+                       // Create tip if enabled
+                       if(self.options.style.tip.corner !== false) { createTip.call(self); }
+               }
+
+               // Neither canvas or VML is supported, tips and borders cannot be drawn!
+               else {
+                       // Set defined border width
+                       self.elements.contentWrapper.css({
+                               border: self.options.style.border.width + 'px solid ' + self.options.style.border.color
+                       });
+
+                       // Reset border radius and tip
+                       self.options.style.border.radius = 0;
+                       self.options.style.tip.corner = false;
+               }
+
+               // Use the provided content string or DOM array
+               if((typeof self.options.content.text === 'string' && self.options.content.text.length > 0) || (self.options.content.text.jquery && self.options.content.text.length > 0)) { 
+                       content = self.options.content.text; 
+               }
+
+               // Check for valid title and alt attributes
+               else { content = ' '; }
+
+               // Set the tooltips content and create title if enabled
+               if(self.options.content.title.text !== false) { createTitle.call(self); }
+               self.updateContent(content, false);
+
+               // Assign events and toggle tooltip with focus
+               assignEvents.call(self);
+               if(self.options.show.ready === true) { self.show(); }
+
+               // Retrieve ajax content if provided
+               if(self.options.content.url !== false) {
+                       url = self.options.content.url;
+                       data = self.options.content.data;
+                       method = self.options.content.method || 'get';
+                       self.loadContent(url, data, method);
+               }
+
+               // Call API method and log event
+               self.status.rendered = true;
+               self.onRender.call(self);
+       }
+
+       // Instantiator
+       function QTip(target, options, id) {
+               // Declare this reference
+               var self = this;
+
+               // Setup class attributes
+               self.id = id;
+               self.options = options;
+               self.status = {
+                       animated: false,
+                       rendered: false,
+                       disabled: false,
+                       focused: false
+               };
+               self.elements = {
+                       target: target.addClass(self.options.style.classes.target),
+                       tooltip: null,
+                       wrapper: null,
+                       content: null,
+                       contentWrapper: null,
+                       title: null,
+                       button: null,
+                       tip: null,
+                       bgiframe: null
+               };
+               self.cache = {
+                       attr: false,
+                       mouse: {},
+                       toggle: 0,
+                       overflow: { left: false, top: false }
+               };
+               self.timers = {};
+
+               // Define exposed API methods
+               $.extend(self, self.options.api, {
+                       show: function (event) {
+                               var returned, solo;
+
+                               // Make sure tooltip is rendered and if not, return
+                               if(!self.status.rendered) { return false; }
+
+                               // Only continue if element is visible
+                               if(self.elements.tooltip.css('display') !== 'none') { return self; }
+
+                               // Clear animation queue
+                               self.elements.tooltip.stop(true, false);
+
+                               // Call API method and if return value is false, halt
+                               returned = self.beforeShow.call(self, event);
+                               if(returned === false) { return self; }
+
+                               // Define afterShow callback method
+                               function afterShow() {
+                                       // Set ARIA hidden status attribute
+                                       self.elements.tooltip.attr('aria-hidden', true);
+
+                                       // Call API method and focus if it isn't static
+                                       if(self.options.position.type !== 'static') { self.focus(); }
+                                       self.onShow.call(self, event);
+
+                                       // Prevent antialias from disappearing in IE7 by removing filter and opacity attribute
+                                       if($.browser.msie) { 
+                                               var ieStyle = self.elements.tooltip.get(0).style;
+                                               ieStyle.removeAttribute('filter');
+                                               ieStyle.removeAttribute('opacity');
+                                       }
+                                       else {
+                                               self.elements.tooltip.css({ opacity: '' });
+                                       }
+                               }
+
+                               // Maintain toggle functionality if enabled
+                               self.cache.toggle = 1;
+
+                               // Update tooltip position if it isn't static
+                               if(self.options.position.type !== 'static') {
+                                       self.updatePosition(event, (self.options.show.effect.length > 0 && self.rendered !== 2));
+                               }
+
+                               // Hide other tooltips if tooltip is solo
+                               if(typeof self.options.show.solo === 'object') {
+                                       solo = $(self.options.show.solo);
+                               }
+                               else if(self.options.show.solo === true) {
+                                       solo = $('div.qtip').not(self.elements.tooltip);
+                               }
+                               if(solo) {
+                                       solo.each(function () {
+                                               if($(this).qtip('api').status.rendered === true) { $(this).qtip('api').hide(); }
+                                       });
+                               }
+
+                               // Show tooltip
+                               if(typeof self.options.show.effect.type === 'function') {
+                                       self.options.show.effect.type.call(self.elements.tooltip, self.options.show.effect.length);
+                                       self.elements.tooltip.queue(function () {
+                                               afterShow();
+                                               $(this).dequeue();
+                                       });
+                               }
+                               else {
+                                       switch (self.options.show.effect.type.toLowerCase()) {
+                                               case 'fade':
+                                                       self.elements.tooltip.fadeIn(self.options.show.effect.length, afterShow);
+                                               break;
+
+                                               case 'slide':
+                                                       self.elements.tooltip.slideDown(self.options.show.effect.length, function () {
+                                                               afterShow();
+                                                               if(self.options.position.type !== 'static') { self.updatePosition(event, true); }
+                                                       });
+                                               break;
+
+                                               case 'grow':
+                                                       self.elements.tooltip.show(self.options.show.effect.length, afterShow);
+                                               break;
+
+                                               default:
+                                                       self.elements.tooltip.show(null, afterShow);
+                                               break;
+                                       }
+
+                                       // Add active class to tooltip
+                                       self.elements.tooltip.addClass(self.options.style.classes.active);
+                               }
+
+                               // Log event and return
+                               return self;
+                       },
+
+                       hide: function (event) {
+                               var returned;
+
+                               // Make sure tooltip is rendered and if not, return
+                               if(!self.status.rendered) { return false; }
+
+                               // Only continue if element is visible
+                               else if(self.elements.tooltip.css('display') === 'none') { return self; }
+
+                               // Stop show timer and animation queue
+                               clearTimeout(self.timers.show);
+                               self.elements.tooltip.stop(true, false);
+
+                               // Call API method and if return value is false, halt
+                               returned = self.beforeHide.call(self, event);
+                               if(returned === false) { return self; }
+
+                               // Define afterHide callback method
+                               function afterHide() {
+                                       // Set ARIA hidden status attribute
+                                       self.elements.tooltip.attr('aria-hidden', true);
+
+                                       // Remove opacity attribute
+                                       if($.browser.msie) { 
+                                               self.elements.tooltip.get(0).style.removeAttribute('opacity');
+                                       }
+                                       else {
+                                               self.elements.tooltip.css({ opacity: '' });
+                                       }
+
+                                       // Call API callback
+                                       self.onHide.call(self, event);
+                               }
+
+                               // Maintain toggle functionality if enabled
+                               self.cache.toggle = 0;
+
+                               // Hide tooltip
+                               if(typeof self.options.hide.effect.type === 'function') {
+                                       self.options.hide.effect.type.call(self.elements.tooltip, self.options.hide.effect.length);
+                                       self.elements.tooltip.queue(function () {
+                                               afterHide();
+                                               $(this).dequeue();
+                                       });
+                               }
+                               else {
+                                       switch (self.options.hide.effect.type.toLowerCase()) {
+                                               case 'fade':
+                                                       self.elements.tooltip.fadeOut(self.options.hide.effect.length, afterHide);
+                                               break;
+
+                                               case 'slide':
+                                                       self.elements.tooltip.slideUp(self.options.hide.effect.length, afterHide);
+                                               break;
+
+                                               case 'grow':
+                                                       self.elements.tooltip.hide(self.options.hide.effect.length, afterHide);
+                                               break;
+
+                                               default:
+                                                       self.elements.tooltip.hide(null, afterHide);
+                                               break;
+                                       }
+
+                                       // Remove active class to tooltip
+                                       self.elements.tooltip.removeClass(self.options.style.classes.active);
+                               }
+
+                               // Log event and return
+                               return self;
+                       },
+
+                       toggle: function (event, state) {
+                               var condition = /boolean|number/.test(typeof state) ? state : !self.elements.tooltip.is(':visible');
+
+                               self[condition ? 'show' : 'hide'](event);
+
+                               return self;
+                       },
+
+                       updatePosition: function (event, animate) {
+                               if(!self.status.rendered) {
+                                       return false;
+                               }
+
+                               var posOptions = options.position,
+                                       target = $(posOptions.target),
+                                       elemWidth = self.elements.tooltip.outerWidth(),
+                                       elemHeight = self.elements.tooltip.outerHeight(),
+                                       targetWidth, targetHeight, position,
+                                       my = posOptions.corner.tooltip,
+                                       at = posOptions.corner.target,
+                                       returned,
+                                       coords, i, mapName, imagePos,
+                                       adapt = {
+                                               left: function () {
+                                                       var leftEdge = $(window).scrollLeft(),
+                                                               rightEdge = $(window).width() + $(window).scrollLeft(),
+                                                               myOffset = my.x === 'center' ? elemWidth/2 : elemWidth,
+                                                               atOffset = my.x === 'center' ? targetWidth/2 : targetWidth,
+                                                               borderAdjust = (my.x === 'center' ? 1 : 2) * self.options.style.border.radius,
+                                                               offset = -2 * posOptions.adjust.x,
+                                                               pRight = position.left + elemWidth,
+                                                               adj;
+
+                                                       // Cut off by right side of window
+                                                       if(pRight > rightEdge) {
+                                                               adj = offset - myOffset - atOffset + borderAdjust;
+
+                                                               // Shifting to the left will make whole qTip visible, or will minimize how much is cut off
+                                                               if(position.left + adj > leftEdge || leftEdge - (position.left + adj) < pRight - rightEdge) {
+                                                                       return { adjust: adj, tip: 'right' };
+                                                               }
+                                                       }
+                                                       // Cut off by left side of window
+                                                       if(position.left < leftEdge) {
+                                                               adj = offset + myOffset + atOffset - borderAdjust;
+
+                                                               // Shifting to the right will make whole qTip visible, or will minimize how much is cut off
+                                                               if(pRight + adj < rightEdge || pRight + adj - rightEdge < leftEdge - position.left) {
+                                                                       return { adjust: adj, tip: 'left' };
+                                                               }
+                                                       }
+
+                                                       return { adjust: 0, tip: my.x };
+                                               },
+                                               top: function () {
+                                                       var topEdge = $(window).scrollTop(),
+                                                               bottomEdge = $(window).height() + $(window).scrollTop(),
+                                                               myOffset = my.y === 'center' ? elemHeight/2 : elemHeight,
+                                                               atOffset = my.y === 'center' ? targetHeight/2 : targetHeight,
+                                                               borderAdjust = (my.y === 'center' ? 1 : 2) * self.options.style.border.radius,
+                                                               offset = -2 * posOptions.adjust.y,
+                                                               pBottom = position.top + elemHeight,
+                                                               adj;
+
+                                                       // Cut off by bottom of window
+                                                       if(pBottom > bottomEdge) {
+                                                               adj = offset - myOffset - atOffset + borderAdjust;
+
+                                                               // Shifting to the top will make whole qTip visible, or will minimize how much is cut off
+                                                               if(position.top + adj > topEdge || topEdge - (position.top + adj) < pBottom - bottomEdge) {
+                                                                       return { adjust: adj, tip: 'bottom' };
+                                                               }
+                                                       }
+                                                       // Cut off by top of window
+                                                       if(position.top < topEdge) {
+                                                               adj = offset + myOffset + atOffset - borderAdjust;
+
+                                                               // Shifting to the top will make whole qTip visible, or will minimize how much is cut off
+                                                               if(pBottom + adj < bottomEdge || pBottom + adj - bottomEdge < topEdge - position.top) {
+                                                                       return { adjust: adj, tip: 'top' };
+                                                               }
+                                                       }
+
+                                                       return { adjust: 0, tip: my.y };
+                                               }
+                                       };
+
+                               if(event && options.position.target === 'mouse') {
+                                       // Force left top to allow flipping
+                                       at = { x: 'left', y: 'top' };
+                                       targetWidth = targetHeight = 0;
+                                       
+                                       // Use cached mouse coordiantes if not available
+                                       if(!event.pageX) {
+                                               position = self.cache.mouse;
+                                       }
+                                       else {
+                                               position = {
+                                                       top: event.pageY,
+                                                       left: event.pageX
+                                               };
+                                       }
+                               }
+                               else {
+                                       if(target[0] === document) {
+                                               targetWidth = target.width();
+                                               targetHeight = target.height();
+                                               position = { top: 0, left: 0 };
+                                       }
+                                       else if(target[0] === window) {
+                                               targetWidth = target.width();
+                                               targetHeight = target.height();
+                                               position = {
+                                                       top: target.scrollTop(),
+                                                       left: target.scrollLeft()
+                                               };
+                                       }
+                                       else if(target.is('area')) {
+                                               // Retrieve coordinates from coords attribute and parse into integers
+                                               coords = self.options.position.target.attr('coords').split(',');
+                                               for(i = 0; i < coords.length; i++) { coords[i] = parseInt(coords[i], 10); }
+
+                                               // Setup target position object
+                                               mapName = self.options.position.target.parent('map').attr('name');
+                                               imagePos = $('img[usemap="#' + mapName + '"]:first').offset();
+                                               position = {
+                                                       left: Math.floor(imagePos.left + coords[0]),
+                                                       top: Math.floor(imagePos.top + coords[1])
+                                               };
+
+                                               // Determine width and height of the area
+                                               switch (self.options.position.target.attr('shape').toLowerCase()) {
+                                                       case 'rect':
+                                                               targetWidth = Math.ceil(Math.abs(coords[2] - coords[0]));
+                                                               targetHeight = Math.ceil(Math.abs(coords[3] - coords[1]));
+                                                       break;
+
+                                                       case 'circle':
+                                                               targetWidth = coords[2] + 1;
+                                                               targetHeight = coords[2] + 1;
+                                                       break;
+
+                                                       case 'poly':
+                                                               targetWidth = coords[0];
+                                                               targetHeight = coords[1];
+
+                                                               for (i = 0; i < coords.length; i++) {
+                                                                       if(i % 2 === 0) {
+                                                                               if(coords[i] > targetWidth) { targetWidth = coords[i]; }
+                                                                               if(coords[i] < coords[0]) { position.left = Math.floor(imagePos.left + coords[i]); }
+                                                                       }
+                                                                       else {
+                                                                               if(coords[i] > targetHeight) { targetHeight = coords[i]; }
+                                                                               if(coords[i] < coords[1]) { position.top = Math.floor(imagePos.top + coords[i]); }
+                                                                       }
+                                                               }
+
+                                                               targetWidth = targetWidth - (position.left - imagePos.left);
+                                                               targetHeight = targetHeight - (position.top - imagePos.top);
+                                                       break;
+                                               }
+
+                                               // Adjust position by 2 pixels (Positioning bug?)
+                                               targetWidth -= 2;
+                                               targetHeight -= 2;
+                                       }
+                                       else {
+                                               targetWidth = target.outerWidth();
+                                               targetHeight = target.outerHeight();
+
+                                               if(!self.elements.tooltip.is(':visible')) {
+                                                       self.elements.tooltip.css({ left: '-10000000em' }).show();
+                                               }
+
+                                               // Account for tooltips offset parent if necessary
+                                               if(self.elements.tooltip.offsetParent()[0] === document.body) {
+                                                       position = target.offset();     
+                                               }
+                                               else {
+                                                       // Account for offset parent and it's scroll positions
+                                                       position = target.position();
+                                                       position.top += target.offsetParent().scrollTop();
+                                                       position.left += target.offsetParent().scrollLeft();
+                                               }
+                                       }
+
+                                       // Adjust position relative to target
+                                       position.left += at.x === 'right' ? targetWidth : at.x === 'center' ? targetWidth / 2 : 0;
+                                       position.top += at.y === 'bottom' ? targetHeight : at.y === 'center' ? targetHeight / 2 : 0;
+                               }
+
+                               // Adjust position relative to tooltip
+                               position.left += posOptions.adjust.x + (my.x === 'right' ? -elemWidth : my.x === 'center' ? -elemWidth / 2 : 0);
+                               position.top += posOptions.adjust.y + (my.y === 'bottom' ? -elemHeight : my.y === 'center' ? -elemHeight / 2 : 0);
+
+                               // Adjust for border radius
+                               if(self.options.style.border.radius > 0) {
+                                       if(my.x === 'left') { position.left -= self.options.style.border.radius; }
+                                       else if(my.x === 'right') { position.left += self.options.style.border.radius; }
+
+                                       if(my.y === 'top') { position.top -= self.options.style.border.radius; }
+                                       else if(my.y === 'bottom') { position.top += self.options.style.border.radius; }
+                               }
+
+                               // Adjust tooltip position if screen adjustment is enabled
+                               if(posOptions.adjust.screen) {
+                                       (function() {
+                                               var adjusted = { x: 0, y: 0 },
+                                                       adapted = { x: adapt.left(), y: adapt.top() },
+                                                       tip = new Corner(options.style.tip.corner);
+
+                                               if(self.elements.tip && tip) {
+                                                       // Adjust position according to adjustment that took place
+                                                       if(adapted.y.adjust !== 0) {
+                                                               position.top += adapted.y.adjust;
+                                                               tip.y = adjusted.y = adapted.y.tip;
+                                                       }
+                                                       if(adapted.x.adjust !== 0) {
+                                                               position.left += adapted.x.adjust;
+                                                               tip.x = adjusted.x = adapted.x.tip;
+                                                       }
+
+                                                       // Update overflow cache
+                                                       self.cache.overflow = {
+                                                               left: adjusted.x === false,
+                                                               top: adjusted.y === false
+                                                       };
+
+                                                       // Update and redraw the tip
+                                                       if(self.elements.tip.attr('rel') !== tip.string()) { createTip.call(self, tip); }
+                                               }
+                                       }());
+                               }
+
+                               // Initiate bgiframe plugin in IE6 if tooltip overlaps a select box or object element
+                               if(!self.elements.bgiframe && $.browser.msie && parseInt($.browser.version.charAt(0), 10) === 6) {
+                                       bgiframe.call(self);
+                               }
+
+                               // Call API method and if return value is false, halt
+                               returned = self.beforePositionUpdate.call(self, event);
+                               if(returned === false) { return self; }
+
+                               // Check if animation is enabled
+                               if(options.position.target !== 'mouse' && animate === true) {
+                                       // Set animated status
+                                       self.status.animated = true;
+
+                                       // Animate and reset animated status on animation end
+                                       self.elements.tooltip.stop().animate(position, 200, 'swing', function () {
+                                               self.status.animated = false;
+                                       });
+                               }
+
+                               // Set new position via CSS
+                               else { self.elements.tooltip.css(position); }
+
+                               // Call API method and log event if its not a mouse move
+                               self.onPositionUpdate.call(self, event);
+
+                               return self;
+                       },
+
+                       updateWidth: function (newWidth) {
+                               // Make sure tooltip is rendered and width is a number
+                               if(!self.status.rendered || (newWidth && typeof newWidth !== 'number')) { return false; }
+
+                               // Setup elements which must be hidden during width update
+                               var hidden = self.elements.contentWrapper.siblings().add(self.elements.tip).add(self.elements.button),
+                                       zoom = self.elements.wrapper.add(self.elements.contentWrapper.children()),
+                                       tooltip = self.elements.tooltip,
+                                       max = self.options.style.width.max,
+                                       min = self.options.style.width.min;
+
+                               // Calculate the new width if one is not supplied
+                               if(!newWidth) {
+                                       // Explicit width is set
+                                       if(typeof self.options.style.width.value === 'number') {
+                                               newWidth = self.options.style.width.value;
+                                       }
+
+                                       // No width is set, proceed with auto detection
+                                       else {
+                                               // Set width to auto initally to determine new width and hide other elements
+                                               self.elements.tooltip.css({ width: 'auto' });
+                                               hidden.hide();
+
+                                               // Set the new calculated width and if width has not numerical, grab new pixel width
+                                               tooltip.width(newWidth);
+
+                                               // Set position and zoom to defaults to prevent IE hasLayout bug
+                                               if($.browser.msie) {
+                                                       zoom.css({ zoom: '' });
+                                               }
+
+                                               // Set the new width
+                                               newWidth = self.getDimensions().width;
+
+                                               // Make sure its within the maximum and minimum width boundries
+                                               if(!self.options.style.width.value) {
+                                                       newWidth = Math.min(Math.max(newWidth, min), max);
+                                               }
+                                       }
+                               }
+
+                               // Adjust newWidth by 1px if width is odd (IE6 rounding bug fix)
+                               if(newWidth % 2) { newWidth += 1; }
+
+                               // Set the new calculated width and unhide other elements
+                               self.elements.tooltip.width(newWidth);
+                               hidden.show();
+
+                               // Set the border width, if enabled
+                               if(self.options.style.border.radius) {
+                                       self.elements.tooltip.find('.qtip-betweenCorners').each(function (i) {
+                                               $(this).width(newWidth - (self.options.style.border.radius * 2));
+                                       });
+                               }
+
+                               // IE only adjustments
+                               if($.browser.msie) {
+                                       // Reset position and zoom to give the wrapper layout (IE hasLayout bug)
+                                       zoom.css({ zoom: 1 });
+
+                                       // Set the new width
+                                       self.elements.wrapper.width(newWidth);
+
+                                       // Adjust BGIframe height and width if enabled
+                                       if(self.elements.bgiframe) { self.elements.bgiframe.width(newWidth).height(self.getDimensions.height); }
+                               }
+
+                               // Log event and return
+                               return self;
+                       },
+
+                       updateStyle: function (name) {
+                               var tip, borders, context, corner, coordinates;
+
+                               // Make sure tooltip is rendered and style is defined
+                               if(!self.status.rendered || typeof name !== 'string' || !$.fn.qtip.styles[name]) { return false; }
+
+                               // Set the new style object
+                               self.options.style = buildStyle.call(self, $.fn.qtip.styles[name], self.options.user.style);
+
+                               // Update initial styles of content and title elements
+                               self.elements.content.css(jQueryStyle(self.options.style));
+                               if(self.options.content.title.text !== false) { self.elements.title.css(jQueryStyle(self.options.style.title, true)); }
+
+                               // Update CSS border colour
+                               self.elements.contentWrapper.css({
+                                       borderColor: self.options.style.border.color
+                               });
+
+                               // Update tip color if enabled
+                               if(self.options.style.tip.corner !== false) {
+                                       if($('<canvas />').get(0).getContext) {
+                                               // Retrieve canvas context and clear
+                                               tip = self.elements.tooltip.find('.qtip-tip canvas:first');
+                                               context = tip.get(0).getContext('2d');
+                                               context.clearRect(0, 0, 300, 300);
+
+                                               // Draw new tip
+                                               corner = tip.parent('div[rel]:first').attr('rel');
+                                               coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
+                                               drawTip.call(self, tip, coordinates, self.options.style.tip.color || self.options.style.border.color);
+                                       }
+                                       else if($.browser.msie) {
+                                               // Set new fillcolor attribute
+                                               tip = self.elements.tooltip.find('.qtip-tip [nodeName="shape"]');
+                                               tip.attr('fillcolor', self.options.style.tip.color || self.options.style.border.color);
+                                       }
+                               }
+
+                               // Update border colors if enabled
+                               if(self.options.style.border.radius > 0) {
+                                       self.elements.tooltip.find('.qtip-betweenCorners').css({
+                                               backgroundColor: self.options.style.border.color
+                                       });
+
+                                       if($('<canvas />').get(0).getContext) {
+                                               borders = calculateBorders(self.options.style.border.radius);
+                                               self.elements.tooltip.find('.qtip-wrapper canvas').each(function () {
+                                                       // Retrieve canvas context and clear
+                                                       context = $(this).get(0).getContext('2d');
+                                                       context.clearRect(0, 0, 300, 300);
+
+                                                       // Draw new border
+                                                       corner = $(this).parent('div[rel]:first').attr('rel');
+                                                       drawBorder.call(self, $(this), borders[corner], self.options.style.border.radius, self.options.style.border.color);
+                                               });
+                                       }
+                                       else if($.browser.msie) {
+                                               // Set new fillcolor attribute on each border corner
+                                               self.elements.tooltip.find('.qtip-wrapper [nodeName="arc"]').each(function () {
+                                                       $(this).attr('fillcolor', self.options.style.border.color);
+                                               });
+                                       }
+                               }
+
+                               // Log event and return
+                               return self;
+                       },
+
+                       updateContent: function (content, reposition) {
+                               var parsedContent, images, loadedImages;
+
+                               function afterLoad() {
+                                       // Update the tooltip width
+                                       self.updateWidth();
+
+                                       // If repositioning is enabled, update positions
+                                       if(reposition !== false) {
+                                               // Update position if tooltip isn't static
+                                               if(self.options.position.type !== 'static') { self.updatePosition(self.elements.tooltip.is(':visible'), true); }
+
+                                               // Reposition the tip if enabled
+                                               if(self.options.style.tip.corner !== false) { positionTip.call(self); }
+                                       }
+                               }
+
+                               // Make sure content is defined if not, return
+                               if(!content) { return false; }
+
+                               // Call API method and set new content if a string is returned
+                               parsedContent = self.beforeContentUpdate.call(self, content);
+                               if(typeof parsedContent === 'string') { content = parsedContent; }
+                               else if(parsedContent === false) { return; }
+
+                               // Continue normally if rendered, but if not set options.content.text instead
+                               if(self.status.rendered) {
+                                       // Set position and zoom to defaults to prevent IE hasLayout bug
+                                       if($.browser.msie) {
+                                               self.elements.contentWrapper.children().css({
+                                                       zoom: 'normal'
+                                               });
+                                       }
+
+                                       // Append new content if its a DOM array and show it if hidden
+                                       if(content.jquery && content.length > 0) { content.clone(true).appendTo(self.elements.content).show(); }
+
+                                       // Content is a regular string, insert the new content
+                                       else { self.elements.content.html(content); }
+
+                                       // Check if images need to be loaded before position is updated to prevent mis-positioning
+                                       images = self.elements.content.find('img[complete=false]');
+                                       if(images.length > 0) {
+                                               loadedImages = 0;
+                                               images.each(function (i) {
+                                                       $('<img src="' + $(this).attr('src') + '" />').load(function () {
+                                                               if(++loadedImages === images.length) { afterLoad(); }
+                                                       });
+                                               });
+                                       }
+                                       else { afterLoad(); }
+                               }
+                               else {
+                                       self.options.content.text = content;
+                               }
+
+                               // Call API method and log event
+                               self.onContentUpdate.call(self);
+                               return self;
+                       },
+
+                       loadContent: function (url, data, method) {
+                               var returned;
+
+                               function setupContent(content) {
+                                       // Call API method and log event
+                                       self.onContentLoad.call(self);
+
+                                       // Update the content
+                                       self.updateContent(content);
+                               }
+
+                               // Make sure tooltip is rendered and if not, return
+                               if(!self.status.rendered) { return false; }
+
+                               // Call API method and if return value is false, halt
+                               returned = self.beforeContentLoad.call(self);
+                               if(returned === false) { return self; }
+
+                               // Load content using specified request type
+                               if(method === 'post') { $.post(url, data, setupContent); }
+                               else { $.get(url, data, setupContent); }
+
+                               return self;
+                       },
+
+                       updateTitle: function (content) {
+                               var returned;
+
+                               // Make sure tooltip is rendered and content is defined
+                               if(!self.status.rendered || !content) { return false; }
+
+                               // Call API method and if return value is false, halt
+                               returned = self.beforeTitleUpdate.call(self);
+                               if(returned === false) { return self; }
+
+                               // Set the new content and reappend the button if enabled
+                               if(self.elements.button) { self.elements.button = self.elements.button.clone(true); }
+                               self.elements.title.html(content);
+                               if(self.elements.button) { self.elements.title.prepend(self.elements.button); }
+
+                               // Call API method and log event
+                               self.onTitleUpdate.call(self);
+                               return self;
+                       },
+
+                       focus: function (event) {
+                               var curIndex, newIndex, elemIndex, returned;
+
+                               // Make sure tooltip is rendered and if not, return
+                               if(!self.status.rendered || self.options.position.type === 'static') { return false; }
+
+                               // Set z-index variables
+                               curIndex = parseInt(self.elements.tooltip.css('z-index'), 10);
+                               newIndex = 15000 + $('div.qtip[id^="qtip"]').length - 1;
+
+                               // Only update the z-index if it has changed and tooltip is not already focused
+                               if(!self.status.focused && curIndex !== newIndex) {
+                                       // Call API method and if return value is false, halt
+                                       returned = self.beforeFocus.call(self, event);
+                                       if(returned === false) { return self; }
+
+                                       // Loop through all other tooltips
+                                       $('div.qtip[id^="qtip"]').not(self.elements.tooltip).each(function () {
+                                               if($(this).qtip('api').status.rendered === true) {
+                                                       elemIndex = parseInt($(this).css('z-index'), 10);
+
+                                                       // Reduce all other tooltip z-index by 1
+                                                       if(typeof elemIndex === 'number' && elemIndex > -1) {
+                                                               $(this).css({ zIndex: parseInt($(this).css('z-index'), 10) - 1 });
+                                                       }
+
+                                                       // Set focused status to false
+                                                       $(this).qtip('api').status.focused = false;
+                                               }
+                                       });
+
+                                       // Set the new z-index and set focus status to true
+                                       self.elements.tooltip.css({ zIndex: newIndex });
+                                       self.status.focused = true;
+
+                                       // Call API method and log event
+                                       self.onFocus.call(self, event);
+                               }
+
+                               return self;
+                       },
+
+                       disable: function (state) {
+                               self.status.disabled = state ? true : false;
+                               return self;
+                       },
+
+                       destroy: function () {
+                               var i, returned, interfaces,
+                                       oldattr = self.elements.target.data('old'+self.cache.attr[0]);
+
+                               // Call API method and if return value is false, halt
+                               returned = self.beforeDestroy.call(self);
+                               if(returned === false) { return self; }
+
+                               // Check if tooltip is rendered
+                               if(self.status.rendered) {
+                                       // Remove event handlers and remove element
+                                       self.options.show.when.target.unbind('mousemove.qtip', self.updatePosition);
+                                       self.options.show.when.target.unbind('mouseout.qtip', self.hide);
+                                       self.options.show.when.target.unbind(self.options.show.when.event + '.qtip');
+                                       self.options.hide.when.target.unbind(self.options.hide.when.event + '.qtip');
+                                       self.elements.tooltip.unbind(self.options.hide.when.event + '.qtip');
+                                       self.elements.tooltip.unbind('mouseover.qtip', self.focus);
+                                       self.elements.tooltip.remove();
+                               }
+
+                               // Tooltip isn't yet rendered, remove render event
+                               else { self.options.show.when.target.unbind(self.options.show.when.event + '.qtip-' + self.id + '-create'); }
+
+                               // Check to make sure qTip data is present on target element
+                               if(typeof self.elements.target.data('qtip') === 'object') {
+                                       // Remove API references from interfaces object
+                                       interfaces = self.elements.target.data('qtip').interfaces;
+                                       if(typeof interfaces === 'object' && interfaces.length > 0) {
+                                               // Remove API from interfaces array
+                                               for(i = 0; i < interfaces.length - 1; i++) {
+                                                       if(interfaces[i].id === self.id) { interfaces.splice(i, 1); }
+                                               }
+                                       }
+                               }
+                               $.fn.qtip.interfaces.splice(self.id, 1);
+
+                               // Set qTip current id to previous tooltips API if available
+                               if(typeof interfaces === 'object' && interfaces.length > 0) { self.elements.target.data('qtip').current = interfaces.length - 1; }
+                               else { self.elements.target.removeData('qtip'); }
+
+                               // Reset old title attribute if removed
+                               if(oldattr) {
+                                       self.elements.target.attr(self.cache.attr[0], oldattr);
+                               }
+
+                               // Call API method and log destroy
+                               self.onDestroy.call(self);
+
+                               return self.elements.target;
+                       },
+
+                       getPosition: function () {
+                               var show, offset;
+
+                               // Make sure tooltip is rendered and if not, return
+                               if(!self.status.rendered) { return false; }
+
+                               show = (self.elements.tooltip.css('display') !== 'none') ? false : true;
+
+                               // Show and hide tooltip to make sure coordinates are returned
+                               if(show) { self.elements.tooltip.css({ visiblity: 'hidden' }).show(); }
+                               offset = self.elements.tooltip.offset();
+                               if(show) { self.elements.tooltip.css({ visiblity: 'visible' }).hide(); }
+
+                               return offset;
+                       },
+
+                       getDimensions: function () {
+                               var show, dimensions;
+
+                               // Make sure tooltip is rendered and if not, return
+                               if(!self.status.rendered) { return false; }
+
+                               show = (!self.elements.tooltip.is(':visible')) ? true : false;
+
+                               // Show and hide tooltip to make sure dimensions are returned
+                               if(show) { self.elements.tooltip.css({ visiblity: 'hidden' }).show(); }
+                               dimensions = {
+                                       height: self.elements.tooltip.outerHeight(),
+                                       width: self.elements.tooltip.outerWidth()
+                               };
+                               if(show) { self.elements.tooltip.css({ visiblity: 'visible' }).hide(); }
+
+                               return dimensions;
+                       }
+               });
+       }
+
+       // Implementation
+       $.fn.qtip = function (options, blanket) {
+               var i, id, interfaces, opts, obj, command, config, api;
+
+               // Return API / Interfaces if requested
+               if(typeof options === 'string') {
+                       if($(this).data('qtip')) {
+                               // Return requested object
+                               if(options === 'api') {
+                                       return $(this).data('qtip').interfaces[$(this).data('qtip').current];
+                               }
+                               else if(options === 'interfaces') {
+                                       return $(this).data('qtip').interfaces;
+                               }
+                       }
+                       else {
+                               return $(this);
+                       }
+               }
+
+               // Validate provided options
+               else {
+                       // Set null options object if no options are provided
+                       if(!options) { options = {}; }
+
+                       // Sanitize option data
+                       if(typeof options.content !== 'object' || (options.content.jquery && options.content.length > 0)) {
+                               options.content = { text: options.content };
+                       }
+                       if(typeof options.content.title !== 'object') {
+                               options.content.title = { text: options.content.title };
+                       }
+                       if(typeof options.position !== 'object') {
+                               options.position = { corner: options.position };
+                       }
+                       if(typeof options.position.corner !== 'object') {
+                               options.position.corner = {
+                                       target: options.position.corner,
+                                       tooltip: options.position.corner
+                               };
+                       }
+                       if(typeof options.show !== 'object') {
+                               options.show = { when: options.show };
+                       }
+                       if(typeof options.show.when !== 'object') {
+                               options.show.when = { event: options.show.when };
+                       }
+                       if(typeof options.show.effect !== 'object') {
+                               options.show.effect = { type: options.show.effect };
+                       }
+                       if(typeof options.hide !== 'object') {
+                               options.hide = { when: options.hide };
+                       }
+                       if(typeof options.hide.when !== 'object') {
+                               options.hide.when = { event: options.hide.when };
+                       }
+                       if(typeof options.hide.effect !== 'object') {
+                               options.hide.effect = { type: options.hide.effect };
+                       }
+                       if(typeof options.style !== 'object') {
+                               options.style = { name: options.style };
+                       }
+
+                       // Sanitize option styles
+                       options.style = sanitizeStyle(options.style);
+
+                       // Build main options object
+                       opts = $.extend(true, {}, $.fn.qtip.defaults, options);
+
+                       // Inherit all style properties into one syle object and include original options
+                       opts.style = buildStyle.call({
+                               options: opts
+                       }, opts.style);
+                       opts.user = $.extend(true, {}, options);
+               }
+
+               // Iterate each matched element
+               return $(this).each(function () // Return original elements as per jQuery guidelines
+               {
+                       var self = $(this), content = false;
+
+                       // Check for API commands
+                       if(typeof options === 'string') {
+                               command = options.toLowerCase();
+                               interfaces = $(this).qtip('interfaces');
+
+                               // Make sure API data exists
+                               if(typeof interfaces === 'object') {
+                                       // Check if API call is a BLANKET DESTROY command
+                                       if(blanket === true && command === 'destroy') {
+                                               for(i = interfaces.length - 1; i > -1; i--) {
+                                                       if('object' === typeof interfaces[i]) {
+                                                               interfaces[i].destroy();
+                                                       }
+                                               }
+                                       }
+
+                                       // API call is not a BLANKET DESTROY command
+                                       else {
+                                               // Check if supplied command effects this tooltip only (NOT BLANKET)
+                                               if(blanket !== true) { interfaces = [$(this).qtip('api')]; }
+
+                                               // Execute command on chosen qTips
+                                               for (i = 0; i < interfaces.length; i++) {
+                                                       // Destroy command doesn't require tooltip to be rendered
+                                                       if(command === 'destroy') { interfaces[i].destroy(); }
+
+                                                       // Only call API if tooltip is rendered and it wasn't a destroy call
+                                                       else if(interfaces[i].status.rendered === true) {
+                                                               if(command === 'show') { interfaces[i].show(); }
+                                                               else if(command === 'hide') { interfaces[i].hide(); }
+                                                               else if(command === 'focus') { interfaces[i].focus(); }
+                                                               else if(command === 'disable') { interfaces[i].disable(true); }
+                                                               else if(command === 'enable') { interfaces[i].disable(false); }
+                                                               else if(command === 'update') { interfaces[i].updatePosition(); }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       // No API commands, continue with qTip creation
+                       else {
+                               // Create unique configuration object
+                               config = $.extend(true, {}, opts);
+                               config.hide.effect.length = opts.hide.effect.length;
+                               config.show.effect.length = opts.show.effect.length;
+
+                               // Sanitize target options
+                               if(config.position.container === false) { config.position.container = $(document.body); }
+                               if(config.position.target === false) { config.position.target = $(this); }
+                               if(config.show.when.target === false) { config.show.when.target = $(this); }
+                               if(config.hide.when.target === false) { config.hide.when.target = $(this); }
+
+                               // Parse corner options
+                               config.position.corner.tooltip = new Corner(config.position.corner.tooltip);
+                               config.position.corner.target = new Corner(config.position.corner.target);
+
+                               // If no content is provided, check title and alt attributes for fallback
+                               if(!config.content.text.length) {
+                                       $(['title', 'alt']).each(function(i, attr) {
+                                               var val = self.attr(attr);
+                                               if(val && val.length) {
+                                                       content = [attr, val];
+                                                       self.data('old'+attr, val).removeAttr(attr);
+                                                       config.content.text = val.replace(/\n/gi, '<br />');
+                                                       return false;
+                                               }
+                                       });
+                               }
+
+                               // Determine tooltip ID (Reuse array slots if possible)
+                               id = $.fn.qtip.interfaces.length;
+                               for (i = 0; i < id; i++) {
+                                       if(typeof $.fn.qtip.interfaces[i] === 'undefined') {
+                                               id = i;
+                                               break;
+                                       }
+                               }
+
+                               // Instantiate the tooltip
+                               obj = new QTip($(this), config, id);
+
+                               // Add API references and cache content if present
+                               $.fn.qtip.interfaces[id] = obj;
+                               obj.cache.attr = content;
+
+                               // Check if element already has qTip data assigned
+                               if(typeof $(this).data('qtip') === 'object' && $(this).data('qtip')) {
+                                       // Set new current interface id
+                                       if(typeof $(this).attr('qtip') === 'undefined') { $(this).data('qtip').current = $(this).data('qtip').interfaces.length; }
+
+                                       // Push new API interface onto interfaces array
+                                       $(this).data('qtip').interfaces.push(obj);
+                               }
+
+                               // No qTip data is present, create now
+                               else {
+                                       $(this).data('qtip', {
+                                               current: 0,
+                                               interfaces: [obj]
+                                       });
+                               }
+
+                               // If prerendering is disabled, create tooltip on showEvent
+                               if(config.content.prerender === false && config.show.when.event !== false && config.show.ready !== true) {
+                                       config.show.when.target.bind(config.show.when.event + '.qtip-' + id + '-create', { qtip: id }, function (event) {
+                                               // Retrieve API interface via passed qTip Id
+                                               api = $.fn.qtip.interfaces[event.data.qtip];
+
+                                               // Unbind show event and cache mouse coords
+                                               api.options.show.when.target.unbind(api.options.show.when.event + '.qtip-' + event.data.qtip + '-create');
+                                               api.cache.mouse = {
+                                                       left: event.pageX,
+                                                       top: event.pageY
+                                               };
+
+                                               // Render tooltip and start the event sequence
+                                               construct.call(api);
+                                               api.options.show.when.target.trigger(api.options.show.when.event);
+                                       });
+                               }
+
+                               // Prerendering is enabled, create tooltip now
+                               else {
+                                       // Set mouse position cache to top left of the element
+                                       obj.cache.mouse = {
+                                               left: config.show.when.target.offset().left,
+                                               top: config.show.when.target.offset().top
+                                       };
+
+                                       // Construct the tooltip
+                                       construct.call(obj);
+                               }
+                       }
+               });
+       };
+
+       // Define qTip API interfaces array
+       $.fn.qtip.interfaces = [];
+
+       /* Add intermediary method to the 'attr' class to allow other plugins to successfully 
+       retrieve the title of an element with a qTip applied */
+       $.fn.qtip.fn = { attr: $.fn.attr };
+       $.fn.attr = function(attr) {
+               var api = $(this).qtip('api');
+
+               return (arguments.length === 1 && (/title|alt/i).test(attr) && api.status && api.status.rendered === true)
+                       ? $(this).data('old' + api.cache.attr[0])
+                       : $.fn.qtip.fn.attr.apply(this, arguments);
+       };
+
+       // Define configuration defaults
+       $.fn.qtip.defaults = {
+               // Content
+               content: {
+                       prerender: false,
+                       text: false,
+                       url: false,
+                       data: null,
+                       title: {
+                               text: false,
+                               button: false
+                       }
+               },
+               // Position
+               position: {
+                       target: false,
+                       corner: {
+                               target: 'bottomRight',
+                               tooltip: 'topLeft'
+                       },
+                       adjust: {
+                               x: 0,
+                               y: 0,
+                               mouse: true,
+                               screen: false,
+                               scroll: true,
+                               resize: true
+                       },
+                       type: 'absolute',
+                       container: false
+               },
+               // Effects
+               show: {
+                       when: {
+                               target: false,
+                               event: 'mouseover'
+                       },
+                       effect: {
+                               type: 'fade',
+                               length: 100
+                       },
+                       delay: 140,
+                       solo: false,
+                       ready: false
+               },
+               hide: {
+                       when: {
+                               target: false,
+                               event: 'mouseout'
+                       },
+                       effect: {
+                               type: 'fade',
+                               length: 100
+                       },
+                       delay: 0,
+                       fixed: false
+               },
+               // Callbacks
+               api: {
+                       beforeRender: function () {},
+                       onRender: function () {},
+                       beforePositionUpdate: function () {},
+                       onPositionUpdate: function () {},
+                       beforeShow: function () {},
+                       onShow: function () {},
+                       beforeHide: function () {},
+                       onHide: function () {},
+                       beforeContentUpdate: function () {},
+                       onContentUpdate: function () {},
+                       beforeContentLoad: function () {},
+                       onContentLoad: function () {},
+                       beforeTitleUpdate: function () {},
+                       onTitleUpdate: function () {},
+                       beforeDestroy: function () {},
+                       onDestroy: function () {},
+                       beforeFocus: function () {},
+                       onFocus: function () {}
+               }
+       };
+
+       $.fn.qtip.styles = {
+               defaults: {
+                       background: 'white',
+                       color: '#111',
+                       overflow: 'hidden',
+                       textAlign: 'left',
+                       width: {
+                               min: 0,
+                               max: 250
+                       },
+                       padding: '5px 9px',
+                       border: {
+                               width: 1,
+                               radius: 0,
+                               color: '#d3d3d3'
+                       },
+                       tip: {
+                               corner: false,
+                               color: false,
+                               size: {
+                                       width: 13,
+                                       height: 13
+                               },
+                               opacity: 1
+                       },
+                       title: {
+                               background: '#e1e1e1',
+                               fontWeight: 'bold',
+                               padding: '7px 12px'
+                       },
+                       button: {
+                               cursor: 'pointer'
+                       },
+                       classes: {
+                               target: '',
+                               tip: 'qtip-tip',
+                               title: 'qtip-title',
+                               button: 'qtip-button',
+                               content: 'qtip-content',
+                               active: 'qtip-active'
+                       }
+               },
+               cream: {
+                       border: {
+                               width: 3,
+                               radius: 0,
+                               color: '#F9E98E'
+                       },
+                       title: {
+                               background: '#F0DE7D',
+                               color: '#A27D35'
+                       },
+                       background: '#FBF7AA',
+                       color: '#A27D35',
+
+                       classes: {
+                               tooltip: 'qtip-cream'
+                       }
+               },
+               light: {
+                       border: {
+                               width: 3,
+                               radius: 0,
+                               color: '#E2E2E2'
+                       },
+                       title: {
+                               background: '#f1f1f1',
+                               color: '#454545'
+                       },
+                       background: 'white',
+                       color: '#454545',
+
+                       classes: {
+                               tooltip: 'qtip-light'
+                       }
+               },
+               dark: {
+                       border: {
+                               width: 3,
+                               radius: 0,
+                               color: '#303030'
+                       },
+                       title: {
+                               background: '#404040',
+                               color: '#f3f3f3'
+                       },
+                       background: '#505050',
+                       color: '#f3f3f3',
+
+                       classes: {
+                               tooltip: 'qtip-dark'
+                       }
+               },
+               red: {
+                       border: {
+                               width: 3,
+                               radius: 0,
+                               color: '#CE6F6F'
+                       },
+                       title: {
+                               background: '#f28279',
+                               color: '#9C2F2F'
+                       },
+                       background: '#F79992',
+                       color: '#9C2F2F',
+
+                       classes: {
+                               tooltip: 'qtip-red'
+                       }
+               },
+               green: {
+                       border: {
+                               width: 3,
+                               radius: 0,
+                               color: '#A9DB66'
+                       },
+                       title: {
+                               background: '#b9db8c',
+                               color: '#58792E'
+                       },
+                       background: '#CDE6AC',
+                       color: '#58792E',
+
+                       classes: {
+                               tooltip: 'qtip-green'
+                       }
+               },
+               blue: {
+                       border: {
+                               width: 3,
+                               radius: 0,
+                               color: '#ADD9ED'
+                       },
+                       title: {
+                               background: '#D0E9F5',
+                               color: '#5E99BD'
+                       },
+                       background: '#E5F6FE',
+                       color: '#4D9FBF',
+
+                       classes: {
+                               tooltip: 'qtip-blue'
+                       }
+               }
+       };
+}(jQuery));
\ No newline at end of file
diff --git a/www/plugins/spip-bonux-3/javascript/jquery.qtip.activate.js b/www/plugins/spip-bonux-3/javascript/jquery.qtip.activate.js
new file mode 100644 (file)
index 0000000..3ab1c4e
--- /dev/null
@@ -0,0 +1,68 @@
+/* 
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+
+/*!
+ * jquery.qtip. The jQuery tooltip plugin
+ *
+ * Copyright (c) 2009 Craig Thompson
+ * http://craigsworks.com
+ *
+ * Licensed under MIT
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Launch  : February 2009
+ * Version : 1.0.0-rc3
+ * Released: Tuesday 12th May, 2009 - 00:00
+ * Debug: jquery.qtip.debug.js
+ */
+(function($)
+{
+       jQuery.fn.qtip_activate = function() {
+         return this.each(function() {
+                       var c=jQuery(this).attr('class');
+                       var ptarget = 'rightTop';
+                       var ptooltip = 'leftTop';
+                       var reg=new RegExp('target_[^\\s]+',"");
+                       var f=c.match(reg);
+                       if (f) { ptarget = f[0].substr(7);}
+                       reg=new RegExp('tooltip_[^\\s]+',"");
+                       f=c.match(reg);
+                       if (f) { ptooltip = f[0].substr(8);}
+
+                       var content = jQuery(this).siblings('.qTipContent');
+                       if (content.length)
+                               jQuery(this).qtip({
+                                       content: {
+                                               text: content
+                                       },
+                                       hide: {
+                                               fixed: true
+                                       },
+                                       style: {
+                                               tip: true,
+                                               name: 'light' // Inherit from preset style
+                                               /*width: { max:220}*/
+                                       },
+                                       position: {
+                                        corner: {target: ptarget, tooltip: ptooltip}
+                                       }
+                               });
+                       jQuery(this).addClass('qTipDone');
+               });
+       }
+
+       jQuery(function() {
+               jQuery('.qTip').qtip_activate();
+       });
+
+       // ... et a chaque fois que le DOM change
+       onAjaxLoad(function() {
+               if (jQuery){
+                       jQuery('.qTip',this).qtip_activate();
+               }
+       });
+
+})(jQuery);
diff --git a/www/plugins/spip-bonux-3/lang/paquet-spip_bonux.xml b/www/plugins/spip-bonux-3/lang/paquet-spip_bonux.xml
new file mode 100644 (file)
index 0000000..f263448
--- /dev/null
@@ -0,0 +1,18 @@
+<traduction module="paquet-spip_bonux" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/spip-bonux-3/lang/" reference="fr">
+       <langue code="ar" url="http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=ar">
+               <traducteur nom="George" lien="http://trad.spip.net/auteur/جورج-قندلفت" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=en">
+               <traducteur nom="Gilles" lien="http://trad.spip.net/auteur/gilles" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_ar.php b/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_ar.php
new file mode 100644 (file)
index 0000000..020ad4a
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=ar
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'spip_bonux_description' => 'الملحق الذي يجعل SPIP أكثر بياضاً من SPIP، ويقدم هدايا ممتعة!
+جداول، عدادات، الخ.',
+       'spip_bonux_slogan' => 'الملحق الذي يجعل SPIP أكثر بياضاً من.'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_en.php b/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_en.php
new file mode 100644 (file)
index 0000000..051e1e6
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'spip_bonux_description' => 'The plugin that make SPIP better than SPIP, with nice gifts inside !
+       arrays, counter, etc.',
+       'spip_bonux_slogan' => 'The plugin that make SPIP better than SPIP.'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_es.php b/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_es.php
new file mode 100644 (file)
index 0000000..924e45b
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'spip_bonux_description' => 'El plugin que lava más SPIP que SPIP, ¡con bonitos regalos dentro!
+       Tableros, contador, etcétera.',
+       'spip_bonux_slogan' => 'El plugin que lava más SPIP que SPIP.'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_fr.php b/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_fr.php
new file mode 100644 (file)
index 0000000..9068077
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/spip-bonux-3/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'spip_bonux_description' => 'Le plugin qui lave plus SPIP que SPIP, avec des chouettes cadeaux dedans !
+       Tableaux, compteur, etc.',
+       'spip_bonux_slogan' => 'Le plugin qui lave plus SPIP que SPIP.'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_ru.php b/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_ru.php
new file mode 100644 (file)
index 0000000..0e7e554
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'spip_bonux_description' => 'SPIP Bonux необходим для работы многих других плагинов. Он существенно расширяет возможности SPIP, делая его лучше чем SPIP :)))',
+       'spip_bonux_slogan' => 'SPIP Bonux существенно расширяет возможности SPIP, делая его лучше чем SPIP :)))'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_sk.php b/www/plugins/spip-bonux-3/lang/paquet-spip_bonux_sk.php
new file mode 100644 (file)
index 0000000..c779759
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-spip_bonux?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // S
+       'spip_bonux_description' => 'Zásuvný modul, ktorý prečistí SPIP ako SPIP s peknými darčekmi vnútri!
+       Tabuľky, počítadlo, a i.',
+       'spip_bonux_slogan' => 'Zásuvný modul, ktorý prečistí SPIP ako SPIP.'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/spip_bonux.xml b/www/plugins/spip-bonux-3/lang/spip_bonux.xml
new file mode 100644 (file)
index 0000000..a7b88c8
--- /dev/null
@@ -0,0 +1,14 @@
+<traduction module="spip_bonux" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/spip-bonux-3/lang/" reference="fr">
+       <langue code="ar" />
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/spip-bonux-3/lang/spip_bonux_ar.php b/www/plugins/spip-bonux-3/lang/spip_bonux_ar.php
new file mode 100644 (file)
index 0000000..7e98053
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=ar
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'afficher_calendrier' => 'عرض الروزنامة',
+       'annee_precedente' => 'السنة السابقة',
+       'annee_suivante' => 'السنة التالية',
+       'annuler_recherche' => 'إلغاء البحث',
+
+       // B
+       'bouton_fermer' => 'إغلاق',
+
+       // E
+       'erreur_date' => 'هذا التاريخ غير صحيح',
+       'erreur_date_corrigee' => 'تم تصحيح التاريخ',
+       'erreur_heure' => 'هذه الساعة غير صحيحة',
+       'erreur_heure_corrigee' => 'تم تصحيح الساعة',
+
+       // I
+       'id_rapide' => 'إضافة سريعة',
+
+       // M
+       'mois_precedent' => 'الشهر السابق',
+       'mois_suivant' => 'الشهر التالي',
+
+       // P
+       'pages' => 'الصفحات'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/spip_bonux_en.php b/www/plugins/spip-bonux-3/lang/spip_bonux_en.php
new file mode 100644 (file)
index 0000000..80fe663
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'afficher_calendrier' => 'Show the calendar',
+       'annee_precedente' => 'Previous year',
+       'annee_suivante' => 'Next year',
+       'annuler_recherche' => 'Cancel the search',
+
+       // B
+       'bouton_fermer' => 'Close',
+
+       // E
+       'erreur_date' => 'This date is incorrect',
+       'erreur_date_corrigee' => 'The date has been corrected',
+       'erreur_heure' => 'This hour is incorrect',
+       'erreur_heure_corrigee' => 'The hour has been corrected',
+
+       // I
+       'id_rapide' => 'Ajout rapide',
+
+       // M
+       'mois_precedent' => 'Previous month',
+       'mois_suivant' => 'Next month',
+
+       // P
+       'pages' => 'Pages'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/spip_bonux_es.php b/www/plugins/spip-bonux-3/lang/spip_bonux_es.php
new file mode 100644 (file)
index 0000000..8899e18
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'afficher_calendrier' => 'Mostrar el calendario',
+       'annee_precedente' => 'Año anterior',
+       'annee_suivante' => 'Año siguiente',
+       'annuler_recherche' => 'Cancelar la búsqueda',
+
+       // B
+       'bouton_fermer' => 'Cerrar',
+
+       // E
+       'erreur_date' => 'Esta fecha es incorrecta',
+       'erreur_date_corrigee' => 'La fecha ha sido corregida',
+       'erreur_heure' => 'Esta hora es incorrecta',
+       'erreur_heure_corrigee' => 'La hora ha sido corregida',
+
+       // I
+       'id_rapide' => 'Añadido rápido',
+
+       // M
+       'mois_precedent' => 'Mes anterior',
+       'mois_suivant' => 'Mes siguiente',
+
+       // P
+       'pages' => 'Páginas'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/spip_bonux_fr.php b/www/plugins/spip-bonux-3/lang/spip_bonux_fr.php
new file mode 100644 (file)
index 0000000..002ec6f
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/spip-bonux-3/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'afficher_calendrier' => 'Afficher le calendrier',
+       'annee_precedente' => 'Anée précédente',
+       'annee_suivante' => 'Année suivante',
+       'annuler_recherche' => 'Annuler la recherche',
+
+       // B
+       'bouton_fermer' => 'Fermer',
+
+       // E
+       'erreur_date' => 'Cette date est incorrecte',
+       'erreur_date_corrigee' => 'La date a été corrigée',
+       'erreur_heure' => 'Cette heure est incorrecte',
+       'erreur_heure_corrigee' => 'L\'heure a été corrigée',
+
+       // I
+       'id_rapide' => 'Ajout rapide',
+
+       // M
+       'mois_precedent' => 'Mois précédent',
+       'mois_suivant' => 'Mois suivant',
+
+       // P
+       'pages' => 'Pages'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/spip_bonux_ru.php b/www/plugins/spip-bonux-3/lang/spip_bonux_ru.php
new file mode 100644 (file)
index 0000000..7760ad2
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'afficher_calendrier' => 'Показать календарь',
+       'annee_precedente' => 'Предыдущий год',
+       'annee_suivante' => 'Следующий год',
+       'annuler_recherche' => 'Отменить поиск',
+
+       // B
+       'bouton_fermer' => 'Закрыть',
+
+       // E
+       'erreur_date' => 'Неправильная дата',
+       'erreur_date_corrigee' => 'Дата была исправлена',
+       'erreur_heure' => 'Неправильный час',
+       'erreur_heure_corrigee' => 'Час был исправлен',
+
+       // I
+       'id_rapide' => 'Быстрое добавление',
+
+       // M
+       'mois_precedent' => 'Предыдущий месяц',
+       'mois_suivant' => 'Следующий месяц',
+
+       // P
+       'pages' => 'Страницы'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/lang/spip_bonux_sk.php b/www/plugins/spip-bonux-3/lang/spip_bonux_sk.php
new file mode 100644 (file)
index 0000000..96522f8
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/spip_bonux?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'afficher_calendrier' => 'Zobraziť kalendár',
+       'annee_precedente' => 'Minulý rok',
+       'annee_suivante' => 'Budúci rok',
+       'annuler_recherche' => 'Zrušiť vyhľadávanie',
+
+       // B
+       'bouton_fermer' => 'Zatvoriť',
+
+       // E
+       'erreur_date' => 'Tento dátum je nesprávny',
+       'erreur_date_corrigee' => 'Dátum bol opravený',
+       'erreur_heure' => 'Tento čas je nesprávny',
+       'erreur_heure_corrigee' => 'Čas bol opravený',
+
+       // I
+       'id_rapide' => 'Rýchle pridanie',
+
+       // M
+       'mois_precedent' => 'Minulý mesiac',
+       'mois_suivant' => 'Budúci mesiac',
+
+       // P
+       'pages' => 'Stránky'
+);
+
+?>
diff --git a/www/plugins/spip-bonux-3/modeles/pagination_noancre.html b/www/plugins/spip-bonux-3/modeles/pagination_noancre.html
new file mode 100644 (file)
index 0000000..97984a5
--- /dev/null
@@ -0,0 +1,16 @@
+#SET{bornes,#ENV{page_courante}|bornes_pagination{#ENV{nombre_pages},10}}
+#SET{premiere, #GET{bornes}|reset}
+#SET{derniere, #GET{bornes}|end}
+#SET{pages,#GET{premiere}|range{#GET{derniere}}}
+#SET{separateur,#ENV{separateur,'|'}}
+[(#SET{label,[(#ENV{label}|sinon{<span class='pagination_label'><:spip_bonux:pages:></span>})]})]
+<B_pages>
+[(#GET{label})]
+[<a href='[(#ENV{url}|parametre_url{#ENV{debut},''})]' class='lien_pagination' rel='nofollow'>(#GET{premiere}|>{1}|?{'...',''})</a> [<span class='sep separateur'>(#GET*{separateur})</span>]]
+<BOUCLE_pages(POUR){tableau #GET{pages}}>
+[(#SET{item, #VALEUR|moins{1}|mult{#ENV{pas}} })]
+[(#ENV{url}|parametre_url{#ENV{debut},#GET{item}}|aoustrong{#VALEUR,#VALEUR|=={#ENV{page_courante}},lien_pagination,'',nofollow})]
+[<span class='sep separateur'>(#VALEUR|<{#GET{derniere}}|?{#GET{separateur}})</span>]
+</BOUCLE_pages>
+[[<span class='sep separateur'>(#GET*{separateur})</span>] <a href='[(#ENV{url}|parametre_url{#ENV{debut},#ENV{nombre_pages}|moins{1}|mult{#ENV{pas}}})]' class='lien_pagination' rel='nofollow'>(#GET{derniere}|<{#ENV{nombre_pages}}|?{'...',''})</a>]
+</B_pages>
\ No newline at end of file
diff --git a/www/plugins/spip-bonux-3/paquet.xml b/www/plugins/spip-bonux-3/paquet.xml
new file mode 100644 (file)
index 0000000..b4909a7
--- /dev/null
@@ -0,0 +1,22 @@
+<paquet
+       prefix="spip_bonux"
+       categorie="outil"
+       version="3.0.5"
+       etat="stable"
+       compatibilite="[3.0.0-dev;3.1.*]"
+       logo="img_pack/spip-bonux.png"
+       documentation="http://www.spip-contrib.net/SPIP-Bonux"
+>      
+
+       <nom>SPIP Bonux</nom>
+       <!-- Le plugin qui lave plus SPIP que SPIP, avec des chouettes cadeaux dedans -->
+
+       <auteur>Cedric Morin</auteur>
+       <auteur>Matthieu Marcillaud</auteur>
+       <auteur>romy.tetue.net</auteur>
+
+       <copyright>2008-2013</copyright>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL</licence>
+       <pipeline nom="affichage_final" />
+</paquet>
diff --git a/www/plugins/spip-bonux-3/public/spip_bonux_balises.php b/www/plugins/spip-bonux-3/public/spip_bonux_balises.php
new file mode 100644 (file)
index 0000000..59bce20
--- /dev/null
@@ -0,0 +1,136 @@
+<?php
+/**
+ * Plugin Spip-Bonux
+ * Le plugin qui lave plus SPIP que SPIP
+ * (c) 2008 Mathieu Marcillaud, Cedric Morin, Romy Tetue
+ * Licence GPL
+ *
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * Empile un element dans un tableau declare par #SET{tableau,#ARRAY}
+ * #SET_PUSH{tableau,valeur}
+ *
+ * @param Champ $p : objet balise
+ * @return Champ
+ *     La balise ne retourne rien ("")
+**/
+function balise_SET_PUSH_dist($p){
+       $_nom = interprete_argument_balise(1,$p);
+       $_valeur = interprete_argument_balise(2,$p);
+
+       if ($_nom AND $_valeur)
+               // si le tableau n'existe pas encore, on le cree
+               // on ajoute la valeur ensuite (sans passer par array_push)
+               $p->code = "vide((\$cle=$_nom)
+                       . vide((!isset(\$Pile['vars'][\$cle]) OR !is_array(\$Pile['vars'][\$cle]))?\$Pile['vars'][\$cle]=array():'')
+                       . vide(\$Pile['vars'][\$cle][]=$_valeur))";
+       else
+               $p->code = "''";
+
+       $p->interdire_scripts = false; // la balise ne renvoie rien
+       return $p;
+}
+
+/**
+ * Si 3 arguments : Cree un tableau nom_tableau de t1 + t2
+ * #SET_MERGE{nom_tableau,t1,t2}
+ * #SET_MERGE{nom_tableau,#GET{tableau},#ARRAY{cle,valeur}}
+ *
+ * Si 2 arguments : Merge t1 dans nom_tableau
+ * #SET_MERGE{nom_tableau,t1}
+ * #SET_MERGE{nom_tableau,#GET{tableau}}
+ *
+ * @param Champ $p : objet balise
+ * @return Champ
+ *     La balise ne retourne rien ("")
+**/
+function balise_SET_MERGE_dist($p){
+       $_nom = interprete_argument_balise(1,$p);
+       $_t1 = interprete_argument_balise(2,$p);
+       $_t2 = interprete_argument_balise(3,$p);
+
+       if ($_nom AND $_t1 AND !$_t2)
+               // 2 arguments : merge de $_nom et $_t1 dans $_nom
+               // si le tableau n'existe pas encore, on le cree
+               $p->code = "vide((\$cle=$_nom)
+                       . vide((!isset(\$Pile['vars'][\$cle]) OR !is_array(\$Pile['vars'][\$cle]))?\$Pile['vars'][\$cle]=array():'')
+                       . vide(is_array(\$new=$_t1)?'':\$new=array(\$new))
+                       . vide(\$Pile['vars'][\$cle] = array_merge(\$Pile['vars'][\$cle],\$new)))";
+       elseif ($_nom AND $_t1 AND $_t2)
+               // 3 arguments : merge de $_t1 et $_t2 dans $_nom
+               // si le tableau n'existe pas encore, on le cree
+               $p->code = "vide((\$cle=$_nom)
+                       . vide((!isset(\$Pile['vars'][\$cle]) OR !is_array(\$Pile['vars'][\$cle]))?\$Pile['vars'][\$cle]=array():'')
+                       . vide(is_array(\$new1=$_t1)?'':\$new1=array(\$new1))
+                       . vide(is_array(\$new2=$_t2)?'':\$new2=array(\$new2))
+                       . vide(\$Pile['vars'][\$cle] = array_merge(\$new1,\$new2)))";
+       else
+               $p->code = "''";
+
+       $p->interdire_scripts = false; // la balise ne renvoie rien
+       return $p;
+}
+
+/**
+ * Balise #COMPTEUR associee au critere compteur
+ *
+ * @param Champ $p
+ * @return Champ
+ */
+function balise_COMPTEUR_dist($p) {
+       calculer_balise_criteres('compteur', $p);
+       if ($p->code=="''")
+               calculer_balise_criteres('compteur', $p, "compteur_left");
+       return $p;
+}
+
+/** Balise #SOMME associee au critere somme */
+function balise_SOMME_dist($p) {
+       return calculer_balise_criteres('somme', $p);
+}
+
+/** Balise #COMPTE associee au critere compte */
+function balise_COMPTE_dist($p) {
+       return calculer_balise_criteres('compte', $p);
+}
+
+/** Balise #MOYENNE associee au critere moyenne */
+function balise_MOYENNE_dist($p) {
+       return calculer_balise_criteres('moyenne', $p);
+}
+
+/** Balise #MINIMUM associee au critere moyenne */
+function balise_MINIMUM_dist($p) {
+       return calculer_balise_criteres('minimum', $p);
+}
+
+/** Balise #MAXIMUM associee au critere moyenne */
+function balise_MAXIMUM_dist($p) {
+       return calculer_balise_criteres('maximum', $p);
+}
+
+/** Balise #STATS associee au critere stats
+ * #STATS{id_article,moyenne}
+ */
+function balise_STATS_dist($p) {
+       if (isset($p->param[0][2][0])
+       AND $nom = ($p->param[0][2][0]->texte)) {
+               return calculer_balise_criteres($nom, $p, 'stats');
+       }
+       return $p;
+}
+
+function calculer_balise_criteres($nom, $p, $motif="") {
+       $p->code = "''";
+       $motif = $motif ? $motif : $nom;
+       if (isset($p->param[0][1][0])
+       AND $champ = ($p->param[0][1][0]->texte)) {
+               return rindex_pile($p, $nom."_$champ", $motif);
+       }
+  return $p;
+}
+
+?>
diff --git a/www/plugins/spip-bonux-3/public/spip_bonux_criteres.php b/www/plugins/spip-bonux-3/public/spip_bonux_criteres.php
new file mode 100644 (file)
index 0000000..2fd43e0
--- /dev/null
@@ -0,0 +1,147 @@
+<?php
+/**
+ * Plugin Spip-Bonux
+ * Le plugin qui lave plus SPIP que SPIP
+ * (c) 2008 Mathieu Marcillaud, Cedric Morin, Romy Tetue
+ * Licence GPL
+ * 
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+/**
+ * http://www.spip-contrib.net/Classer-les-articles-par-nombre-de#forum409210
+ * Permet de faire un comptage par table liee
+ * exemple
+ * <BOUCLE1(AUTEURS){compteur articles}{par compteur_articles}>
+ * #ID_AUTEUR : #COMPTEUR{articles}
+ * </BOUCLE1>
+ * pour avoir les auteurs classes par articles et le nombre d'article de chacun
+ *
+ * @param unknown_type $idb
+ * @param unknown_type $boucles
+ * @param unknown_type $crit
+ */
+function critere_compteur($idb, &$boucles, $crit, $left=false){
+       $boucle = &$boucles[$idb];
+
+       $_fusion = calculer_liste($crit->param[1], array(), $boucles, $boucle->id_parent);
+       $params = $crit->param;
+       $table = reset($params);
+       $table = $table[0]->texte;
+       $op = false;
+       if(preg_match(',^(\w+)([<>=])([0-9]+)$,',$table,$r)){
+               $table=$r[1];
+               if (count($r)>=3) $op=$r[2];
+               if (count($r)>=4) $op_val=$r[3];
+       }
+       $type = objet_type($table);
+       $type_id = id_table_objet($type);
+       
+       /**
+        * Si la clé primaire est une clé multiple, on prend la première partie
+        * Utile pour compter les versions de spip_versions par exemple
+        */
+       if(count($types = explode(',',$type_id)) > 1)
+               $type_id = $types[0];
+       $table_sql = table_objet_sql($type);
+
+       $trouver_table = charger_fonction('trouver_table','base');
+       $arrivee = array($table, $trouver_table($table, $boucle->sql_serveur));
+       $depart = array($boucle->id_table,$trouver_table($boucle->id_table, $boucle->sql_serveur));
+
+       // noter les jointures deja installees
+       $joins = array_keys($boucle->from);
+       if ($compt = calculer_jointure($boucle,$depart,$arrivee)){
+               if ($_fusion!="''"){
+                       // en cas de jointure, on ne veut pas du group_by sur la cle primaire !
+                       // cela casse le compteur !
+                       foreach($boucle->group as $k=>$group)
+                               if ($group == $boucle->id_table.'.'.$boucle->primary)
+                                       unset($boucle->group[$k]);
+                       $boucle->group[] = '".($gb='.$_fusion.')."';
+               }
+
+               $boucle->select[]= "COUNT($compt.$type_id) AS compteur_$table"; 
+               if ($op)
+                       $boucle->having[]= array("'".$op."'", "'compteur_".$table."'",$op_val);
+               if ($left){
+                       foreach($boucle->from as $k=>$val){
+                               if (!in_array($k, $joins)){
+                                       $boucle->from_type[$k] = 'left';
+                               }
+                       }
+               }
+       }
+}
+
+/**
+ * {compteur_left xxx} permet de faire la meme chose que {compteur xxx}
+ * mais avec un LEFT JOIN pour ne pas ignorer ceux qui ont un compteur nul
+ * @param <type> $idb
+ * @param <type> $boucles
+ * @param <type> $crit
+ */
+function critere_compteur_left($idb, &$boucles, $crit){
+       critere_compteur($idb, $boucles, $crit, true);
+}
+
+/**  Critere {somme champ} #SOMME{champ} */
+function critere_somme($idb, &$boucles, $crit){
+       calcul_critere_fonctions(array('SUM'=>'somme'), $idb, $boucles, $crit);
+}
+
+/**  Critere {compte champ} #COMPTE{champ} */
+function critere_compte($idb, &$boucles, $crit){
+       calcul_critere_fonctions(array('COUNT'=>'compte'), $idb, $boucles, $crit);
+}
+
+/**  Critere {moyenne champ} #MOYENNE{champ} */
+function critere_moyenne($idb, &$boucles, $crit){
+       calcul_critere_fonctions(array('AVG'=>'moyenne'), $idb, $boucles, $crit);
+}
+
+/**  Critere {minimum champ} #MINIMUM{champ} */
+function critere_minimum($idb, &$boucles, $crit){
+       calcul_critere_fonctions(array('MIN'=>'minimum'), $idb, $boucles, $crit);
+}
+
+/**  Critere {maximum champ} #MAXIMUM{champ} */
+function critere_maximum($idb, &$boucles, $crit){
+       calcul_critere_fonctions(array('MAX'=>'maximum'), $idb, $boucles, $crit);
+}
+
+/**  Critere {stats champ} calcul la totale : somme, compte, minimum, moyenne, maximum */
+function critere_stats($idb, &$boucles, $crit){
+       calcul_critere_fonctions(array(
+               'SUM'=>'somme',
+               'COUNT'=>'compte',
+               'AVG'=>'moyenne',
+               'MIN'=>'minimum',
+               'MAX'=>'maximum',
+       ), $idb, $boucles, $crit);
+}
+
+/* $func : array(FUNC => balise) */
+function calcul_critere_fonctions($func, $idb, &$boucles, $crit) {
+       $boucle = &$boucles[$idb];
+
+       $params = $crit->param;
+       $champ = reset($params);
+       $champ = $champ[0]->texte;
+
+       // option DISTINCT {compte DISTINCT(id_article) }
+       $filter="";
+       if (preg_match('/^([a-zA-Z]+)\(\s*([a-zA-Z_]+)\s*\)$/', trim($champ), $r)) {
+               $filter = $r[1]; // DISTINCT
+               $champ = $r[2]; // id_article
+       }
+       
+       $sel = $filter ? "$filter($champ)" : $champ;
+       foreach ($func as $f => $as) {
+               $boucle->select[]= "$f($sel) AS $as" . "_$champ";
+       }
+}
+
+
+?>
diff --git a/www/plugins/spip-bonux-3/spip_bonux_fonctions.php b/www/plugins/spip-bonux-3/spip_bonux_fonctions.php
new file mode 100644 (file)
index 0000000..c3b7411
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Plugin Spip-Bonux
+ * Le plugin qui lave plus SPIP que SPIP
+ * (c) 2008 Mathieu Marcillaud, Cedric Morin, Romy Tetue
+ * Licence GPL
+ * 
+ */
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+include_spip('public/spip_bonux_criteres');
+include_spip('public/spip_bonux_balises');
+
+/**
+ * une fonction pour generer une balise img a partir d'un nom de fichier
+ *
+ * @param string $img
+ * @param string $alt
+ * @param string $class
+ * @return string
+ */
+function tag_img($img,$alt="",$class=""){
+       $balise_img = chercher_filtre('balise_img');
+       return $balise_img($img,$alt,$class);
+}
+
+function previsu_verifier_cle_temporaire($cle){
+       $validite = 12; // validite de 12h maxi
+       $old = 0;
+       do {
+               $date = date('Y-m-d H',strtotime("-$old hour"));
+               if ($cle==previsu_cle_temporaire($date))
+                       return true;
+       } while ($old++<$validite);
+       return false;
+}
+function previsu_cle_temporaire($date=null){
+       include_spip('inc/securiser_action');
+       if (!$date) $date = date('Y-m-d H');
+       $url = self();
+       $cle = md5($url.$date.secret_du_site());
+       return $cle;
+}
+
+?>
diff --git a/www/plugins/spip-bonux-3/spip_bonux_options.php b/www/plugins/spip-bonux-3/spip_bonux_options.php
new file mode 100644 (file)
index 0000000..fd09065
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+/**
+ * Plugin Spip-Bonux
+ * Le plugin qui lave plus SPIP que SPIP
+ * (c) 2008 Mathieu Marcillaud, Cedric Morin, Romy Tetue
+ * Licence GPL
+ * 
+ */
+
+if (_request('var_mode')=='preview'
+  AND $cle = _request('var_relecture')){
+       include_spip("spip_bonux_fonctions");
+       if (previsu_verifier_cle_temporaire($cle)){
+               include_spip("inc/autoriser");
+               autoriser_exception('previsualiser','',0);
+               define('_VAR_PREVIEW_EXCEPTION',true);
+       }
+}
+
+function spip_bonux_affichage_final($flux){
+       if (defined('_VAR_PREVIEW') AND _VAR_PREVIEW){
+               $p = stripos($flux,"</body>");
+               $url_relecture = parametre_url(self(),'var_mode','preview','&');
+               $js = "";
+               if (!defined('_VAR_PREVIEW_EXCEPTION')){
+                       $url_relecture = parametre_url($url_relecture,'var_relecture',previsu_cle_temporaire(),'&');
+                       $label = "Relecture temporaire";
+               }
+               else {
+                       $label = _T('previsualisation');
+                       $js = "jQuery('.spip-previsu').html('Relecture temporaire');";
+               }
+               $js .= "jQuery('#spip-admin').append('<a class=\"spip-admin-boutons review_link\" href=\"$url_relecture\">$label</a>');";
+               $js = "jQuery(function(){ $js });";
+               $js = "<script>$js</script>";
+               $flux = substr_replace($flux,$js,$p,0);
+       }
+       return $flux;
+}
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+ /**
+ * une fonction qui regarde si $texte est une chaine de langue
+ * de la forme <:qqch:>
+ * si oui applique _T()
+ * si non applique typo() suivant le mode choisi
+ *
+ * @param unknown_type $valeur Une valeur à tester. Si c'est un tableau, la fonction s'appliquera récursivement dessus.
+ * @param string $mode_typo Le mode d'application de la fonction typo(), avec trois valeurs possibles "toujours", "jamais" ou "multi".
+ * @return unknown_type Retourne la valeur éventuellement modifiée.
+ */
+if (!function_exists('_T_ou_typo')) {
+function _T_ou_typo($valeur, $mode_typo='toujours') {
+       
+       // Si la valeur est bien une chaine (et pas non plus un entier déguisé)
+       if (is_string($valeur) and !intval($valeur)){
+               // Si la chaine est du type <:truc:> on passe à _T()
+               if (preg_match('/^\<:(.*?):\>$/', $valeur, $match)) 
+                       $valeur = _T($match[1]);
+               // Sinon on la passe a typo()
+               else {
+                       if (!in_array($mode_typo, array('toujours', 'multi', 'jamais')))
+                               $mode_typo = 'toujours';
+                       
+                       if ($mode_typo == 'toujours' or ($mode_typo == 'multi' and strpos($valeur, '<multi>') !== false)){
+                               include_spip('inc/texte');
+                               $valeur = typo($valeur);
+                       }
+               }
+       }
+       // Si c'est un tableau, on reapplique la fonction récursivement
+       elseif (is_array($valeur)){
+               foreach ($valeur as $cle => $valeur2){
+                       $valeur[$cle] = _T_ou_typo($valeur2, $mode_typo);
+               }
+       }
+
+       return $valeur;
+
+}
+}
+
+/*
+ * Insère toutes les valeurs du tableau $arr2 après (ou avant) $cle dans le tableau $arr1.
+ * Si $cle n'est pas trouvé, les valeurs de $arr2 seront ajoutés à la fin de $arr1.
+ *
+ * La fonction garde autant que possible les associations entre les clés. Elle fonctionnera donc aussi bien
+ * avec des tableaux à index numérique que des tableaux associatifs.
+ * Attention tout de même, elle utilise array_merge() donc les valeurs de clés étant en conflits seront écrasées.
+ *
+ * @param array $arr1 Tableau dans lequel se fera l'insertion
+ * @param unknown_type $cle Clé de $arr1 après (ou avant) laquelle se fera l'insertion
+ * @param array $arr2 Tableau contenant les valeurs à insérer
+ * @param bool $avant Indique si l'insertion se fait avant la clé (par défaut c'est après)
+ * @return array Retourne le tableau avec l'insertion
+ */
+if (!function_exists('array_insert')) {
+function array_insert($arr1, $cle, $arr2, $avant=false){
+       $index = array_search($cle, array_keys($arr1));
+       if($index === false){
+               $index = count($arr1); // insert @ end of array if $key not found
+       }
+       else {
+               if(!$avant){
+                       $index++;
+               }
+       }
+       $fin = array_splice($arr1, $index);
+       return array_merge($arr1, $arr2, $fin);
+}
+}
+
+/*
+ * Une fonction extrêmement pratique, mais qui n'est disponible qu'à partir de PHP 5.3 !
+ * cf. http://www.php.net/manual/fr/function.array-replace-recursive.php
+ */
+if (!function_exists('array_replace_recursive')){
+       function array_replace_recursive($array, $array1){
+               function recurse($array, $array1){
+                       foreach ($array1 as $key => $value){
+                               // create new key in $array, if it is empty or not an array
+                               if (!isset($array[$key]) || (isset($array[$key]) && !is_array($array[$key])))
+                                       $array[$key] = array();
+                               // overwrite the value in the base array
+                               if (is_array($value))
+                                       $value = recurse($array[$key], $value);
+                               $array[$key] = $value;
+                       }
+                       return $array;
+               }
+
+               // handle the arguments, merge one by one
+               $args = func_get_args();
+               $array = $args[0];
+               if (!is_array($array))
+                       return $array;
+               
+               for ($i = 1; $i < count($args); $i++)
+                       if (is_array($args[$i]))
+                               $array = recurse($array, $args[$i]);
+               
+               return $array;
+       }
+}
+
+
+?>
diff --git a/www/plugins/spip-bonux-3/svn.revision b/www/plugins/spip-bonux-3/svn.revision
new file mode 100644 (file)
index 0000000..50f6416
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/spip-bonux-3
+Revision: 71958
+Dernier commit: 2013-04-11 18:00:24 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/spip-bonux-3</origine>
+<revision>71958</revision>
+<commit>2013-04-11 18:00:24 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/spip-bonux-3/tests/balises/set_merge.html b/www/plugins/spip-bonux-3/tests/balises/set_merge.html
new file mode 100644 (file)
index 0000000..86b149f
--- /dev/null
@@ -0,0 +1,60 @@
+[(#REM)
+
+       la balise SET_MERGE sert a merger des valeurs dans un tableau #SET
+       #SET_MERGE{tab,t1} : merge tab et t1 dans tab
+       #SET_MERGE{tab,t1,t2} : merge t1 et t2 dans tab
+]
+
+[(#REM) ----- 2 arguments ------ ]
+[(#REM) 
+       SET SET+GET|merge = SET MERGE
+]
+       #SET{Aa,#ARRAY{a,aaa}} #SET{Aaa,#ARRAY{a,aaa}}
+       #SET{Ab,#ARRAY{b,bbb}}
+       [(#SET{Ac,[(#GET{Aa}|array_merge{#GET{Ab}})]})]
+       #SET_MERGE{Aaa,#GET{Ab}}
+       [(#GET{Ac}|!=={#GET{Aaa}}|oui)[(#SET{err,"Aaa et Ac sont differents"})]]
+
+
+[(#REM) 
+       SET_MERGE peut etre fait sans declarer un SET prealable
+]
+       #SET{Ba,#ARRAY{a,aaa}}
+       #SET_MERGE{Bb,#GET{Ba}}
+       [(#GET{Ba}|!=={#GET{Bb}}|oui)[(#SET{err,"Ba et Bb sont différents"})]]
+
+[(#REM) 
+       Si une chaine est donnee a MERGE, elle est transformee en tableau
+]
+       #SET_MERGE{C,coucou}
+       [(#GET{C}|!=={#ARRAY{0,coucou}})[(#SET{err,"(C) String non compris par #SET_MERGE"})]]
+
+
+[(#REM) ----- 3 arguments ------ ]
+[(#REM) 
+       SET SET+GET|merge = SET MERGE
+]
+       #SET{Fa,#ARRAY{a,aaa}}
+       #SET{Fb,#ARRAY{b,bbb}}
+       [(#SET{Fc,[(#GET{Fa}|array_merge{#GET{Fb}})]})]
+       #SET_MERGE{Fd,#GET{Fa},#GET{Fb}}
+       [(#GET{Fc}|!=={#GET{Fd}}|oui)[(#SET{err,"Fc et Fd sont differents"})]]
+       
+       
+[(#REM) 
+       MERGE peut etre fait sans declarer un SET prealable
+]
+       #SET{Ga,#ARRAY{a,aaa}}
+       #SET{Gb,#ARRAY{b,bbb}}
+       [(#SET{Gc,[(#GET{Ga}|array_merge{#GET{Gb}})]})]
+       #SET_MERGE{Gd,#GET{Ga},#GET{Gb}}
+       [(#GET{Gc}|!=={#GET{Gd}}|oui)[(#SET{err,"Gc et Gd sont différents"})]]
+
+
+[(#REM) 
+       Si une chaine est donnee a MERGE, elle est transformee en tableau
+]
+       #SET_MERGE{H,coucou,toutou}
+       [(#GET{H}|!=={#ARRAY{0,coucou,1,toutou}})[(#SET{err,"(H) String non compris par #SET_MERGE"})]]
+
+[(#GET{err}|?{ERREUR,OK}) #GET{err} ]
diff --git a/www/plugins/spip-bonux-3/tests/balises/set_push.html b/www/plugins/spip-bonux-3/tests/balises/set_push.html
new file mode 100644 (file)
index 0000000..74bc38e
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM)
+
+       la balise SET_PUSH sert a ajouter des valeurs dans un tableau #SET
+
+]
+
+[(#REM) 
+       SET GET|push = SET PUSH 
+]
+       #SET{A,#ARRAY}
+       #SET{B,#ARRAY}
+       [(#SET{A,[(#GET{A}|push{abc})]})]
+       #SET_PUSH{B,abc}
+       [(#GET{A}|!=={#GET{B}}|oui)[(#SET{err,"A et B sont différents"})]]
+
+
+[(#REM) 
+       SET_PUSH peut être fait sans declarer un SET prealable
+]
+       #SET_PUSH{C,abc}
+       [(#GET{A}|!=={#GET{C}}|oui)[(#SET{err,"A et C sont différents"})]]
+
+
+
+[(#GET{err}|?{ERREUR,OK}) #GET{err} ]
diff --git a/www/plugins/spip_piwik_2_0/action/piwik_creer_site.php b/www/plugins/spip_piwik_2_0/action/piwik_creer_site.php
new file mode 100644 (file)
index 0000000..4fae842
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Fonction de création de site dans le serveur piwik
+ * 
+ * Utilise l'api de piwik pour ajouter un site dans le serveur 
+ * Le nouveau site aura le nom du site SPIP (la traduction dans la langue 
+ * en cours si le site est dans un bloc multi)
+ * 
+ * @return 
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_piwik_creer_site_dist(){
+       include_spip('inc/filtres');
+       $piwik_site = _request('urlsite');
+       $piwik_token = _request('token');
+
+       $piwik_url = 'http://'.$piwik_site.'/';
+
+       $options['siteName'] = extraire_multi($GLOBALS['meta']['nom_site']);
+       $options['urls'] = $GLOBALS['meta']['adresse_site'];
+       
+       $piwik_recuperer_data = charger_fonction('piwik_recuperer_data','inc');
+       
+       $methode = 'SitesManager.addSite';
+       $datas = $piwik_recuperer_data($piwik_url,$piwik_token,'',$methode,'PHP',$options);
+       
+       $methode_bis = 'SitesManager.getSitesWithAdminAccess';
+       $datas_bis = $piwik_recuperer_data($piwik_url,$piwik_token,'',$methode_bis,'PHP');
+       ecrire_meta('piwik_sites_dispo', $datas_bis);
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/action/piwik_recuperer_liste.php b/www/plugins/spip_piwik_2_0/action/piwik_recuperer_liste.php
new file mode 100644 (file)
index 0000000..1ae8b67
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Récupère la liste des sites accessibles par l'utilisateur 
+ * sur le serveur Piwik configuré
+ * 
+ * Elle crée une meta spécifique 'piwik_sites_dispo' qui est un array serialisé
+ * Utilise la fonction de communication avec l'API
+ * 
+ * @return 
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_piwik_recuperer_liste(){
+       include_spip('inc/config');
+       $config = lire_config('piwik',array());
+       $piwik_site = isset($config['urlpiwik']) ? $config['urlpiwik'] : false;
+       $piwik_token = isset($config['token']) ? $config['token'] : false;
+       
+       if($piwik_site && $piwik_token){
+               $piwik_url = 'http://'.$piwik_site.'/';
+               
+               $format = _request('format')?_request('format'):'PHP';
+               
+               $piwik_api = charger_fonction('piwik_recuperer_data','inc');
+               
+               /**
+                * Récupération de la liste des sites où cet utilisateur 
+                * a les droits d'admin
+                */
+               $method = 'SitesManager.getSitesWithAdminAccess';
+               $datas = $piwik_api($piwik_url,$piwik_token,'',$method,$format);
+               ecrire_meta('piwik_sites_dispo', $datas);
+       }
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/balise/piwik.php b/www/plugins/spip_piwik_2_0/balise/piwik.php
new file mode 100644 (file)
index 0000000..e5ad8ce
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Balise #PIWIK
+ *
+ * Au final ne correspond qu'à un inclure mais est plus rapide à écrire
+ * et ne casse pas à la compilation si le plugin n'est pas activé
+ *
+ * @param object $p
+ * @return
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function balise_PIWIK_dist($p) {
+    return calculer_balise_dynamique($p, 'PIWIK', array());
+}
+function balise_PIWIK_stat($args, $filtres) {
+    return $args;
+}
+function balise_PIWIK_dyn() {
+       if(!function_exists('lire_config'))
+               include_spip('inc/config');
+       $config = lire_config('piwik',array());
+       if(!empty($config['urlpiwik']) && is_numeric($config['idpiwik']) && ($config['mode_insertion'] == 'balise')){
+               if(in_array($GLOBALS['visiteur_session']['statut'],lire_config('piwik/restreindre_statut_public',array()))||in_array($GLOBALS['visiteur_session']['id_auteur'],lire_config('piwik/restreindre_auteurs_public',array()))){
+                       return;
+               }
+               $piwik_ips = array_flip(preg_split('/(\s*[;,]\s*|\s+)/',trim($config['exclure_ips']),-1,PREG_SPLIT_NO_EMPTY));
+               if (isset($piwik_ips[$GLOBALS['ip']])) {
+                       return;
+               }
+               return array(
+               'prive/piwik',
+               0,
+               array()
+       );
+       }
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/fonds/cfg_piwik.html b/www/plugins/spip_piwik_2_0/fonds/cfg_piwik.html
new file mode 100644 (file)
index 0000000..331ee6c
--- /dev/null
@@ -0,0 +1,12 @@
+<!-- titre=<:piwik:piwik:> -->
+<!-- descriptif=
+<p><:piwik:cfg_description_piwik:></p>
+-->
+<!-- icone=images/piwik-22.png -->
+<!-- logo=images/piwik.png -->
+#CACHE{0}
+
+<div class="ajax">
+#FORMULAIRE_CONFIGURER_PIWIK
+</div>
+
diff --git a/www/plugins/spip_piwik_2_0/formulaires/configurer_piwik.html b/www/plugins/spip_piwik_2_0/formulaires/configurer_piwik.html
new file mode 100644 (file)
index 0000000..224400f
--- /dev/null
@@ -0,0 +1,101 @@
+<!-- autoriser=webmestre -->
+<!-- refus=<:cfg:refus_configuration_webmestre:> -->
+<!-- nom=piwik -->
+#CACHE{0}
+
+<div class="formulaire_spip formulaire_editer formulaire_config">
+
+       [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>]
+       [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
+
+       <form method="post" action="#ENV{action}"><div>
+       #ACTION_FORMULAIRE{SELF}
+               <ul>
+                       [(#SAISIE{input,urlpiwik,
+                               label=<:piwik:label_adresse_serveur:>,
+                               explication=<:piwik:explication_adresse_serveur:>,
+                               obligatoire=oui,
+                               size=50
+                       })]
+                       
+                       [(#SAISIE{input,user,
+                               label=<:piwik:label_piwik_user:>,
+                               obligatoire=oui,
+                               size=50
+                       })]
+                       
+                       [(#SAISIE{input,token,
+                               label=<:piwik:label_token:>,
+                               explication=<:piwik:explication_token:>,
+                               obligatoire=oui,
+                               size=50
+                       })]
+                       [(#CONFIG{piwik/token}|et{#CONFIG{piwik/user}}|oui)
+                               [(#SET{defaut,[(#URL_SITE_SPIP)]})]
+                               [(#SAISIE{sites_piwik,idpiwik,
+                                       label=<:piwik:label_identifiant_site:>,
+                                       explication=<:piwik:explication_identifiant_site:>,
+                                       option_intro='-',
+                                       defaut=#GET{defaut},
+                                       size=5
+                               })]
+                               [(#CONFIG{piwik_admin}|=={oui}|oui)
+                               <li class="editer editer_creer_site">
+                                       <label><:piwik:label_creer_site:></label>
+                                       <p class="explication"><:piwik:explication_creer_site:></p>
+                                       <a href="[(#URL_ACTION_AUTEUR{piwik_creer_site,test&urlsite=[(#CONFIG{piwik/urlpiwik})]&token=[(#CONFIG{piwik/token})],#SELF})]"><:piwik:action_creer_site:></a>
+                                       <a href="[(#URL_ACTION_AUTEUR{piwik_recuperer_liste,test,#SELF})]"><:piwik:action_recuperer_liste:></a>
+                               </li>]
+                               [(#CONFIG{piwik_admin}|=={non}|oui)
+                               <li>
+                                       <label><:piwik:label_recuperer_liste:></label>
+                                       <p class="explication"><:piwik:explication_recuperer_liste:></p>
+                                       <a href="[(#URL_ACTION_AUTEUR{piwik_recuperer_liste,test,#SELF})]"><:piwik:action_recuperer_liste:></a>
+                               </li>]
+                               [(#SAISIE{radio, mode_insertion,
+                                       label=<:piwik:label_mode_insertion:>,
+                                       explication=<:piwik:explication_mode_insertion:>,
+                                       datas=#ARRAY{
+                                               pipeline,<:piwik:mode_insertion_pipeline:>,
+                                               balise,<:piwik:mode_insertion_balise:>
+                               }})]
+
+                               [(#CONFIG{piwik/mode_insertion}|=={balise}|oui)
+
+                                       [(#SAISIE{statuts_auteurs, restreindre_statut_public,
+                                               label=<:piwik:label_restreindre_statut_public:>,
+                                               explication=<:piwik:explication_restreindre_statut_public:>,
+                                               multiple=oui})]
+
+                                       [(#SAISIE{auteurs, restreindre_auteurs_public,
+                                               label=<:piwik:label_restreindre_auteurs_public:>,
+                                               multiple=oui})]
+
+                                       [(#SAISIE{input,exclure_ips,
+                                               label=<:piwik:label_exclure_ips:>,
+                                               explication=<:piwik:explication_exclure_ips:>,
+                                               size=50
+                                       })]
+                               ]
+
+                               [(#SAISIE{case, piwik_prive,
+                                       label=<:piwik:label_comptabiliser_prive:>
+                               })]
+
+                               [(#CONFIG{piwik/piwik_prive}|=={on}|oui)
+                                       [(#SAISIE{statuts_auteurs, restreindre_statut_prive,
+                                               label=<:piwik:label_restreindre_statut_prive:>,
+                                               explication=<:piwik:explication_restreindre_statut_prive:>,
+                                               multiple=oui})]
+
+                                       [(#SAISIE{auteurs, restreindre_auteurs_prive,
+                                               label=<:piwik:label_restreindre_auteurs_prive:>,
+                                               multiple=oui})]
+                               ]
+                       ]
+               </ul>
+               <p class="boutons">
+                       <input type="submit" name="_cfg_ok" value="<:bouton_valider:>" class="submit" />
+               </p>
+       </div></form>
+</div>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/formulaires/configurer_piwik_fonctions.php b/www/plugins/spip_piwik_2_0/formulaires/configurer_piwik_fonctions.php
new file mode 100644 (file)
index 0000000..125de27
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * 
+ * Fonction de verification du formulaire de configuration CFG
+ * 
+ */
+function cfg_config_piwik_verifier(&$cfg){
+       $obligatoires = array('token','user','urlpiwik');
+       foreach($obligatoires as $obligatoire){
+               if(!$cfg->val[$obligatoire]){
+                       $erreur[$obligatoire] = _T('info_obligatoire');
+               }
+       }
+       
+       $piwik_token = $cfg->val['token'];
+       if (!$erreur['token'] && !preg_match('/^[a-f0-9]{32}$/i',$piwik_token)) {
+               $erreur['token'] = _T('piwik:cfg_erreur_token');
+               return $erreur;
+       }
+       $piwik_url = 'http://'.$cfg->val['urlpiwik'].'/';
+       
+       $piwik_recuperer_data = charger_fonction('piwik_recuperer_data','inc');
+       
+       /**
+        * Vérifier la correspondance nom d'utilisateur/ token
+        * Qui nous permettra par la suite de définir d'autres choses
+        */
+       $method_verif_user = 'UsersManager.getUser';
+       $options_user = array('userLogin'=>$cfg->val['user']);
+       $datas_user = $piwik_recuperer_data($piwik_url,$piwik_token,'',$method_verif_user,'PHP',$options_user);
+       if(is_array($datas_user = unserialize($datas_user))){
+               if(!$erreur['user'] && $datas_user['result'] == 'error'){
+                       $erreur['user'] = _T('piwik:cfg_erreur_user_token');
+               }
+               /**
+                * Vérifier que ce token est un token admin
+                * Si non : mettre une meta comme quoi il n'est pas admin pour créer des sites
+                */
+               $method_verif_user_bis = 'UsersManager.getUsers';
+               $datas_user_bis = $piwik_recuperer_data($piwik_url,$piwik_token,'',$method_verif_user_bis,'PHP');
+               $datas_user_bis = unserialize($datas_user_bis);
+               if(is_array($datas_user_bis) && ($datas_user_bis['result'] == 'error')){
+                       ecrire_meta('piwik_admin', 'non');
+               }else{
+                       ecrire_meta('piwik_admin', 'oui');
+                       unset($erreur['user']);
+               }
+       }
+
+       /**
+        * Récupération de la liste des sites où cet utilisateur 
+        * a les droits d'admin
+        */
+       $method = 'SitesManager.getSitesWithAdminAccess';
+       $datas = $piwik_recuperer_data($piwik_url,$piwik_token,'',$method,'PHP');
+       if(!$erreur['urlpiwik'] && !is_array(unserialize($datas))){
+               $erreur['urlpiwik'] = _T('piwik:cfg_erreur_recuperation_data');
+       }else{
+               ecrire_meta('piwik_sites_dispo', $datas);       
+       }
+       
+       return $erreur;
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/images/piwik-22.png b/www/plugins/spip_piwik_2_0/images/piwik-22.png
new file mode 100644 (file)
index 0000000..c878306
Binary files /dev/null and b/www/plugins/spip_piwik_2_0/images/piwik-22.png differ
diff --git a/www/plugins/spip_piwik_2_0/images/piwik.png b/www/plugins/spip_piwik_2_0/images/piwik.png
new file mode 100644 (file)
index 0000000..80d8fd5
Binary files /dev/null and b/www/plugins/spip_piwik_2_0/images/piwik.png differ
diff --git a/www/plugins/spip_piwik_2_0/inc/piwik_recuperer_data.php b/www/plugins/spip_piwik_2_0/inc/piwik_recuperer_data.php
new file mode 100644 (file)
index 0000000..47bb050
--- /dev/null
@@ -0,0 +1,33 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Fonction de communication avec l'API REST du serveur Piwik
+ * 
+ * @param string $piwik_url Url du serveur
+ * @param string $token_auth Le token d'autentification du serveur
+ * @param string $module [optional]
+ * @param string $method
+ * @param string $format [optional]
+ * @param array $options [optional]
+ * @return string Le contenu de la réponse
+ */
+function inc_piwik_recuperer_data_dist($piwik_url,$token_auth,$module='API',$method,$format='PHP',$options=array()){
+       
+       $url = parametre_url($piwik_url,'token_auth',$token_auth);
+       $url = parametre_url($url,'module','API','&');
+       $url = parametre_url($url,'format',$format,'&');
+       $url = parametre_url($url,'method',$method,'&');
+       if(is_array($options)){
+               foreach($options as $cle => $val){
+                       $url = parametre_url($url,$cle,$val,'&');
+               }
+       }
+       
+       include_spip('inc/distant');
+       $content = recuperer_page($url);
+       
+       return $content;
+}
+?>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/lang/paquet-piwik.xml b/www/plugins/spip_piwik_2_0/lang/paquet-piwik.xml
new file mode 100644 (file)
index 0000000..362ef88
--- /dev/null
@@ -0,0 +1,16 @@
+<traduction module="paquet-piwik" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/spip_piwik/spip_piwik_2_0/lang/" reference="fr">
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/spip_piwik_2_0/lang/paquet-piwik_en.php b/www/plugins/spip_piwik_2_0/lang/paquet-piwik_en.php
new file mode 100644 (file)
index 0000000..b7564ec
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // P
+       'piwik_description' => 'Adds the Piwik statistics script (web traffic analyzer) on the pages of the site.',
+       'piwik_slogan' => 'Link [SPIP->http://www.spip.net] and [Piwik->http://www.piwik.org]'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/paquet-piwik_es.php b/www/plugins/spip_piwik_2_0/lang/paquet-piwik_es.php
new file mode 100644 (file)
index 0000000..bd240e2
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // P
+       'piwik_description' => 'Añade el script de estadísticas Piwik (analizador de tráfico web) en las páginas del sitio web.',
+       'piwik_slogan' => 'Conectar Spip y Piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/paquet-piwik_fa.php b/www/plugins/spip_piwik_2_0/lang/paquet-piwik_fa.php
new file mode 100644 (file)
index 0000000..ee78176
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // P
+       'piwik_description' => 'افزودن نويسه‌ي آماري پيويك (تحليلگر ترافيك وب)(Piwik) روي صفحه‌هاي سايت ',
+       'piwik_slogan' => 'پيوند [اسپيپ->http://www.spip.net] و [پيويك->http://www.piwik.org]'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/paquet-piwik_fr.php b/www/plugins/spip_piwik_2_0/lang/paquet-piwik_fr.php
new file mode 100644 (file)
index 0000000..79d9c02
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/spip_piwik/spip_piwik_2_0/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // P
+       'piwik_description' => 'Ajoute le script de statistiques Piwik (analyseur de trafic web) sur les pages du site.',
+       'piwik_slogan' => 'Interfacer Spip et Piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/paquet-piwik_ru.php b/www/plugins/spip_piwik_2_0/lang/paquet-piwik_ru.php
new file mode 100644 (file)
index 0000000..ca346af
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // P
+       'piwik_description' => 'Добавляет код системы веб-аналитики Piwik на все страницы сайта.',
+       'piwik_slogan' => 'Объединяет [SPIP->http://www.spip.net] и [Piwik->http://www.piwik.org]'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/paquet-piwik_sk.php b/www/plugins/spip_piwik_2_0/lang/paquet-piwik_sk.php
new file mode 100644 (file)
index 0000000..60df298
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-piwik?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // P
+       'piwik_description' => 'Na stránky webu pridá skript so štatistikami Piwik (analyzátor návštevnosti webu).',
+       'piwik_slogan' => 'Rozhranie Spip a Piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik.xml b/www/plugins/spip_piwik_2_0/lang/piwik.xml
new file mode 100644 (file)
index 0000000..6357732
--- /dev/null
@@ -0,0 +1,16 @@
+<traduction module="piwik" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/spip_piwik/spip_piwik_2_0/lang/" reference="fr">
+       <langue code="ca" />
+       <langue code="de" />
+       <langue code="en" />
+       <langue code="es" url="http://trad.spip.net/tradlang_module/piwik?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" />
+       <langue code="fr" />
+       <langue code="fr_tu" url="http://trad.spip.net/tradlang_module/piwik?lang_cible=fr_tu">
+               <traducteur nom="beatnick" lien="http://trad.spip.net/auteur/beatnick" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/piwik?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_ca.php b/www/plugins/spip_piwik_2_0/lang/piwik_ca.php
new file mode 100644 (file)
index 0000000..c772ad9
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/piwik?lang_cible=ca
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'Crear el lloc',
+       'action_recuperer_liste' => 'Récupérer la liste des sites', # NEW
+
+       // C
+       'cfg_description_piwik' => 'Podeu introduir aquí el vostre nom d\'usuari piwik i l\'adreça del servidor que gestiona les vostres estadístiques.',
+       'cfg_erreur_recuperation_data' => 'Hi ha un error de comunicació amb el servidor, verifiqueu l\'adreça i el token',
+       'cfg_erreur_token' => 'El vostre token d\'identificació és invàlid',
+       'cfg_erreur_user_token' => 'La correspondance Nom d\'utilisateur / Token n\'est pas correcte.', # NEW
+
+       // E
+       'explication_adresse_serveur' => 'Entreu l\'adreça sense "http://" ni "https://" ni barra final',
+       'explication_creer_site' => 'El següent enllaç us permet crear un lloc al servidor Piwik que estarà disponible a continuació a la llista. Verifiqueu que heu configurat l\'adreça correctament i el nom del vostre lloc SPIP abans de clicar. Són aquestes informacions les que s\'utilitzaran.',
+       'explication_exclure_ips' => 'Per excloure diverses adreces, separeu-les amb punts i comes',
+       'explication_identifiant_site' => 'La llista dels llocs disponibles al servidor Piwik s\'ha recuperat automàticament gràcies a les informacions presentades. Seleccioneu de la següent llista la que més us convingui',
+       'explication_mode_insertion' => 'Hi ha dues maneres d\'inserir a les pàgines el codi necessari per un bon funcionament del connector. Mitjançant el pipeline "insert_head" (mètode automàtic però poc configurable), o mitjançant la inserció d\'una etiqueta (mètode manual inserint a la part inferior de les vostres pàgines l\'etiqueta #PIWIK) que, a més a més, és totalment configurable.',
+       'explication_recuperer_liste' => 'Le lien ci-dessous vous permet de récupérer la liste des sites que votre compte peut administrer sur le serveur Piwik.', # NEW
+       'explication_restreindre_statut_prive' => 'Escolliu aquí els estats d\'usuaris que no es comptabilitzaran a les estadístiques en l\'espai privat',
+       'explication_restreindre_statut_public' => 'Escolliu aquí els estats d\'usuaris que no es comptabilitzaran a les estadístiques a la part pública',
+       'explication_token' => 'El token d\'identificació està disponible o bé a les vostres preferències personals o a la part API de vostre servidor Piwik',
+
+       // I
+       'info_aucun_site_compte' => 'Aucun site n\'est associé à votre compte Piwik.', # NEW
+       'info_aucun_site_compte_demander_admin' => 'Vous devez demander à un administrateur de votre serveur Piwik d\'ajouter un site correspondant.', # NEW
+
+       // L
+       'label_adresse_serveur' => 'Adreça URL del servidor (https:// o http://)',
+       'label_comptabiliser_prive' => 'Comptabilitzar les visites de l\'espai privat',
+       'label_creer_site' => 'Crear un lloc al servidor Piwik',
+       'label_exclure_ips' => 'Excloure certes adreces IP',
+       'label_identifiant_site' => 'L\'identificador del vostre lloc al servidor Piwik',
+       'label_mode_insertion' => 'Mode d\'inserció a les pàgines públiques',
+       'label_piwik_user' => 'Compte utilisateur Piwik', # NEW
+       'label_recuperer_liste' => 'Récupérer la liste des sites sur le serveur Piwik', # NEW
+       'label_restreindre_auteurs_prive' => 'Restringir determinats usuaris connectats (privat)',
+       'label_restreindre_auteurs_public' => 'Restringir determinats usuaris connectats (públic)',
+       'label_restreindre_statut_prive' => 'Restringir determinats estats d\'usuaris a l\'espai privat',
+       'label_restreindre_statut_public' => 'Restringir determinats estats d\'usuaris a l\'espai públic',
+       'label_token' => 'Token d\'identificació al vostre servidor',
+
+       // M
+       'mode_insertion_balise' => 'Inserció per mitjà de l\'etiqueta #PIWIK (cal que modifiqueu els vostres esquelets)',
+       'mode_insertion_pipeline' => 'Inserció automàtica per mitja del pipeline "insert_head"',
+
+       // P
+       'piwik' => 'Piwik',
+
+       // T
+       'texte_votre_identifiant' => 'Nom d\'usuari',
+       'textes_url_piwik' => 'El vostre servidor piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_de.php b/www/plugins/spip_piwik_2_0/lang/piwik_de.php
new file mode 100644 (file)
index 0000000..7aed9f9
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/piwik?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'Site anlegen',
+       'action_recuperer_liste' => 'Récupérer la liste des sites', # NEW
+
+       // C
+       'cfg_description_piwik' => 'Hier können sie ihre PIWIK-Anmeldedaten sowie die Adresse des Servers für ihre Statistiken angeben.',
+       'cfg_erreur_recuperation_data' => 'Kommunikation mit dem Server gescheitert, bitte überprüfen sie die Adresse und das Token.',
+       'cfg_erreur_token' => 'Ihre Token-ID ist ungültig.',
+       'cfg_erreur_user_token' => 'La correspondance Nom d\'utilisateur / Token n\'est pas correcte.', # NEW
+
+       // E
+       'explication_adresse_serveur' => 'Geben sie die Adresse ohne "http://" oder "https://" und ohne Slash "/" am Ende an.',
+       'explication_creer_site' => 'Mit diesem Link können sie auf dem PIWIK-Server eine Site anlegen, welche dann in der Liste angezeigt wird. Bitte prüfen sie, ob sie den Namen und die Adresse ihrer SPIP-Website richtig eingetragen haben, denn diese Daten werden an PIWIK übertragen.',
+       'explication_exclure_ips' => 'Um mehrere Adressen auszuschließen, trennen sie sie bitte mit einem Semikolon.',
+       'explication_identifiant_site' => 'Die Liste der auf dem PIWIK-Server verfügbaren Websites wurde aufgrund der angegebenen Informationen übertragen. Bitte wählen sie in der untenstehenden Liste die gewünschte Site aus.',
+       'explication_mode_insertion' => 'Es gibt zwei Methoden, den für das Funktionieren des Plugins erforderlichen Code in die Seiten einzufügen: Mit der Pipeline "indert_head" (vollautomatisch aber ohne erweiterte Konfigurationsmöglichkeiten) oder durch Einfügen des Tags #PIWIK in den Fußbereich ihrer Skelette (dann können sie alle Konfigurationsoptionen nutzen).',
+       'explication_recuperer_liste' => 'Le lien ci-dessous vous permet de récupérer la liste des sites que votre compte peut administrer sur le serveur Piwik.', # NEW
+       'explication_restreindre_statut_prive' => 'Wählen sie hier den Status der Besucher, deren Zugriffe auf das Redaktionssystem nicht in der Statistik erfaßt werden',
+       'explication_restreindre_statut_public' => 'Wählen sie hier den Status der Besucher, deren Zugriffe auf den öffentlichen Teil der Website nicht in der Statistik erfaßt werden',
+       'explication_token' => 'Das Identifikations-Token finden sie in ihren persönlichen Einstellungen oder im API-Bereich ihres PIWIK-Servers.',
+
+       // I
+       'info_aucun_site_compte' => 'Aucun site n\'est associé à votre compte Piwik.', # NEW
+       'info_aucun_site_compte_demander_admin' => 'Vous devez demander à un administrateur de votre serveur Piwik d\'ajouter un site correspondant.', # NEW
+
+       // L
+       'label_adresse_serveur' => 'Adresse (URL) des Servers (https:// oder http://)',
+       'label_comptabiliser_prive' => 'Abrufe des Redaktionssystems erfassen',
+       'label_creer_site' => 'Eine Site auf dem Piwik-Server anlegen',
+       'label_exclure_ips' => 'Bestimmte IP-Adressen ausschließen',
+       'label_identifiant_site' => 'ID ihrer Website auf dem Piwik-Server',
+       'label_mode_insertion' => 'Typ des Einfügens in die öffentlichen Seiten',
+       'label_piwik_user' => 'Compte utilisateur Piwik', # NEW
+       'label_recuperer_liste' => 'Récupérer la liste des sites sur le serveur Piwik', # NEW
+       'label_restreindre_auteurs_prive' => 'Einschränkungen für manche angemeldeten Besucher (Redaktion)',
+       'label_restreindre_auteurs_public' => 'Einschränkungen für manche angemeldeten Besucher (öffentlicher Bereich)',
+       'label_restreindre_statut_prive' => 'Einschränkungen für manche Mitglieder im Redaktionssystem',
+       'label_restreindre_statut_public' => 'Einschränkungen für manche Mitglieder im öffentlichen Bereich',
+       'label_token' => 'ID-Token auf dem Server',
+
+       // M
+       'mode_insertion_balise' => 'Einfügen mit dem Tag #PIWIK (erfordert Änderung ihrer Skelette)',
+       'mode_insertion_pipeline' => 'Automatisches Einfügen mit der Pipeline "insert_head"',
+
+       // P
+       'piwik' => 'Piwik',
+
+       // T
+       'texte_votre_identifiant' => 'Ihre ID',
+       'textes_url_piwik' => 'Ihr Piwik-Server'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_en.php b/www/plugins/spip_piwik_2_0/lang/piwik_en.php
new file mode 100644 (file)
index 0000000..3ab8eb7
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/piwik?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'Create the site',
+       'action_recuperer_liste' => 'Retrieve the list of sites',
+
+       // C
+       'cfg_description_piwik' => 'You can specify your piwik identifier here, as well as the the address of your statistics server.',
+       'cfg_erreur_recuperation_data' => 'There was a server communication problem - please check the address and token',
+       'cfg_erreur_token' => 'Your identification token is invalid',
+       'cfg_erreur_user_token' => 'The username and token do not match each other.',
+
+       // E
+       'explication_adresse_serveur' => 'Enter the URL address without "http://" or "https://" and without the final slash',
+       'explication_creer_site' => 'The link below enables you to create a site on the Piwik server which will then be available from the list.Check that you have correctly entered the address and name of your SPIP site before clicking, as these are the details will be used later.',
+       'explication_exclure_ips' => 'To nominate several addresses to be excluded, separate them with semi-colons',
+       'explication_identifiant_site' => 'The list of sites available on the Piwik server has been automatically retrieved using the submitted details. Select the one you wish to use from the list below',
+       'explication_mode_insertion' => 'There are two methods for inserting the code pages required to make the plugin work correctly: either with the "insert_head" pipeline (an automatic method with only minor configurations possible), or by inserting a tag (a manual method of including the #PIWIK tag at the bottom of your pages), which is fully configurable.',
+       'explication_recuperer_liste' => 'The link below is used to retrieve the lists of sites that your account can manage on the Piwik server.',
+       'explication_restreindre_statut_prive' => 'Select the user statuses which will not be taken into account in the private zone statistics',
+       'explication_restreindre_statut_public' => 'Select the user statuses which will not be taken into account in the public zone statistics',
+       'explication_token' => 'The identification token is available in your personal preferences or in the API section on your Piwik server',
+
+       // I
+       'info_aucun_site_compte' => 'There are no sites associated with your Piwik account.',
+       'info_aucun_site_compte_demander_admin' => 'You need to ask an administrator of your Piwik server to add a matching site.',
+
+       // L
+       'label_adresse_serveur' => 'URL address of the server (https:// or http://)',
+       'label_comptabiliser_prive' => 'Include visits to the private space',
+       'label_creer_site' => 'Create a site on the Piwik server',
+       'label_exclure_ips' => 'Exclude certain IP addresses',
+       'label_identifiant_site' => 'The identifier of your site on the Piwik server',
+       'label_mode_insertion' => 'Insert mode for the public pages',
+       'label_piwik_user' => 'Piwik user account',
+       'label_recuperer_liste' => 'Retrieve the list of sites on the Piwik server',
+       'label_restreindre_auteurs_prive' => 'Restrict certain logged in users (private)',
+       'label_restreindre_auteurs_public' => 'Restrict certain logged in users (public)',
+       'label_restreindre_statut_prive' => 'Restrict certain user statuses in the private zone',
+       'label_restreindre_statut_public' => 'Restrict certain user statuses in the public zone',
+       'label_token' => 'Identification token on the server',
+
+       // M
+       'mode_insertion_balise' => 'Insert using the #PIWIK tag (you must modify your templates)',
+       'mode_insertion_pipeline' => 'Automatic insertion using the "insert_head" pipeline',
+
+       // P
+       'piwik' => 'Piwik',
+
+       // T
+       'texte_votre_identifiant' => 'Your identifier',
+       'textes_url_piwik' => 'Your piwik server'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_es.php b/www/plugins/spip_piwik_2_0/lang/piwik_es.php
new file mode 100644 (file)
index 0000000..76a4dd8
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/piwik?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'Crear la lista',
+       'action_recuperer_liste' => 'Recuperar la lista de sitios webs',
+
+       // C
+       'cfg_description_piwik' => 'Aquí puede indicar su identificador piwik, así como la dirección del servidor que administra sus estadísticas.',
+       'cfg_erreur_recuperation_data' => 'Hay un error de comunicación con el servidor, verifique por favor la dirección y el token',
+       'cfg_erreur_token' => 'Su token de identificación no es válido',
+       'cfg_erreur_user_token' => 'La correspondencia entre Nombre de usuario / Token no es correcta. ',
+
+       // E
+       'explication_adresse_serveur' => 'Introduzca la dirección sin "http://" ni "https://" ni barra final',
+       'explication_creer_site' => 'El siguiente enlace le permite crear un sitio web en el servidor Piwik que estará disponible después en la lista. Verifique que ha configurado bien la dirección y el nombre de su sitio web SPIP antes de hacer click, ésta será la información utilizada.',
+       'explication_exclure_ips' => 'Para excluir varias direcciones, sepárelas por punto y coma',
+       'explication_identifiant_site' => 'La lista de los sitios webs disponibles en el servidor Piwik se ha recuperado automáticamente grácias a las informaciones presentadas. Seleccione en la siguiente lista el que le convenga',
+       'explication_mode_insertion' => 'Hay dos modos de inserción en las páginas del código necesario para el buen funcionamiento del plugin. Mediante el pipeline "insert_head" (método automático pero poco configurable), o mediante la inserción de una etiqueta (método manual cuando se inserta al pie de sus páginas la etiqueta #PIWIK), la cual es plenamente configurable. ',
+       'explication_recuperer_liste' => 'El siguiente enlace le permite recuperar la lista de sitios webs que su cuenta puede administrar en el servidor Piwik.',
+       'explication_restreindre_statut_prive' => 'Elija aquí los estatus de usuarios que no serán contabilizados en las estadísticas en el espacio privado',
+       'explication_restreindre_statut_public' => 'Elija aquí los estatus de usuarios que no serán contabilizados en las estadísticas en la parte público',
+       'explication_token' => 'El token de identificación está disponible en sus preferencias personales o en la parte API de su servidor Piwik',
+
+       // I
+       'info_aucun_site_compte' => 'Ningún sitio web está asociado a su cuenta Piwik.',
+       'info_aucun_site_compte_demander_admin' => 'Ha de solicitar a un administrador de su servidor Piwik el añadir un sitio correspondiente',
+
+       // L
+       'label_adresse_serveur' => 'Dirección URL del servidor (https:// o http://)',
+       'label_comptabiliser_prive' => 'Contabilizar las visitas al espacio privado',
+       'label_creer_site' => 'Crear un sitio en el servidor Piwik',
+       'label_exclure_ips' => 'Excluir ciertas direcciones IP',
+       'label_identifiant_site' => 'El identificador de su sitio web en el servidor Piwik',
+       'label_mode_insertion' => 'Modo de inserción en las páginas públicas',
+       'label_piwik_user' => 'Cuenta de usuario Piwik',
+       'label_recuperer_liste' => 'Recuperar la lista de sitios en el servidor Piwik',
+       'label_restreindre_auteurs_prive' => 'Restringir a ciertos usuarios conectados (privados)',
+       'label_restreindre_auteurs_public' => 'Restringir a ciertos usuarios conectados (público)',
+       'label_restreindre_statut_prive' => 'Restringir a ciertos estatus de usuarios en el espacio privado',
+       'label_restreindre_statut_public' => 'Restringir a ciertos estatus de usuarios en la parte pública',
+       'label_token' => 'Token de identificación en el servidor',
+
+       // M
+       'mode_insertion_balise' => 'Inserción por la etiqueta #PIWIK (modificación necesaria de sus essqueletos)',
+       'mode_insertion_pipeline' => 'Inserción automática por el pipeline "insert_head"',
+
+       // P
+       'piwik' => 'Piwik',
+
+       // T
+       'texte_votre_identifiant' => 'Su identificador',
+       'textes_url_piwik' => 'Su servidor Piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_fa.php b/www/plugins/spip_piwik_2_0/lang/piwik_fa.php
new file mode 100644 (file)
index 0000000..4568b31
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/piwik?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'ايجاد سايت',
+       'action_recuperer_liste' => 'بازيافت فهرست سايت‌ها',
+
+       // C
+       'cfg_description_piwik' => 'اينجا مي‌توانيد شناسه‌ي پي‌ويك (piwik) خود، نيز، نشاني ميزبان آمارهاي خود را مشخص كنيد.',
+       'cfg_erreur_recuperation_data' => 'در ارتباط با ميزبان خطايي رخ داده،‌نشاني و علامت را چك كنيد',
+       'cfg_erreur_token' => 'علامت شناسه‌ي شما معتبر نيست',
+       'cfg_erreur_user_token' => 'كاربرنام و نشانه با هم نمي‌خوانند.',
+
+       // E
+       'explication_adresse_serveur' => 'نشاني خود را بدون"http://" و "https://" و بدون خط كج آخر وارد كنيد.',
+       'explication_creer_site' => 'پيوند زير شما را قادر مي‌سازد تا روي ميزبان پي‌ويك خود يك سايت ايجاد كنيد كه سپس از طريق فهرست در دسترس قرار خواهد داشت. پيش از كليك چك كنيد كه نشاني و نام سايت اسپيپ خود را درست وارد كرده‌ايد، زيرا اين جزئيات بعداً مورد استفاده قرار مي‌گيرند.  ',
+       'explication_exclure_ips' => 'براي كنار گذاشتن تعدادي از نشاني‌ها،‌ آن‌ها را با نقطه ويرگول جداسازي كنيد',
+       'explication_identifiant_site' => 'فهرست سايت‌هاي در دسترس در ميزبان پي‌ويك به صورت خودكار و با استفاده از جزئيات بازيافت شده است. يكي از آن‌ها را كه مي‌خواهيد استفاده كنيد از فهرست زير انتخاب كنيد.',
+       'explication_mode_insertion' => 'براي گنجاندن كد صفحه‌هاي مورد نياز براي كاركرد دست پلاگين دو روش موجود است: هم با خط لوله‌ي"insert_head" (يك روش خودكار با كم‌ترين پيكربندي ممكن)، يا با گنجاندن يك تگ (يك روش دستي شامل تگ #PIWIK در پائين صفحه‌هاي شما)، كه به طور كامل قابل پيكربندي است. ',
+       'explication_recuperer_liste' => 'پيوند زيز براي بازيافت فهرست سايت‌هايي مورد استفاده قرار مي‌گيرد كه حساب شما مي‌تواند روي ميزبان پي‌ويك مديريت كند. ',
+       'explication_restreindre_statut_prive' => 'در اينجا وضعيت‌هاي كارفر را انتخاب كنيد كه در آمارهاي بخش خصوصي به حساب نمي‌آيند.',
+       'explication_restreindre_statut_public' => 'در اينجا وضعيت‌‌هايي براي كاربر انتخاب كنيد كه در آمارهاي بخش همگاني به حساب مي‌آيند.   ',
+       'explication_token' => 'نشانه‌ي شناسايي در ترجيحات شخصي شما يا در بخش آي.پي.اي ميزبان پي‌ويك شما در دسترس است. ',
+
+       // I
+       'info_aucun_site_compte' => 'هيچ سايت مرتبط با حساب پي‌ويك شما موجود نيست ',
+       'info_aucun_site_compte_demander_admin' => 'براي افزودن يك سايت مربوطه بايد از ادمين ميزبان پي‌ويك خود بخواهيد. ',
+
+       // L
+       'label_adresse_serveur' => 'نشاني يو.آر.ال ميزبان (https://  يا http://)',
+       'label_comptabiliser_prive' => 'گنجاندن بازديد‌هاي بخش خصوصي',
+       'label_creer_site' => 'ايجاد يك سايت روي ميزبان پي‌ويك',
+       'label_exclure_ips' => 'كنارگذاشتن بعضي از آي.پي نشاني‌ها',
+       'label_identifiant_site' => 'شناسه‌ي سايت شما روي ميزبان پي‌ويك',
+       'label_mode_insertion' => 'گنجاندن مد در صفحه‌هاي همگاني',
+       'label_piwik_user' => 'حساب كاربر پي‌ويك ',
+       'label_recuperer_liste' => 'بازيافت فهرست سايت‌ها روي ميزبان پي‌ويك',
+       'label_restreindre_auteurs_prive' => 'محدودسازي بعضي از كاربران متصل (قسمت خصوصي)',
+       'label_restreindre_auteurs_public' => 'محدودسازي بعضي از كاربران متصل (قسمت همگاني)',
+       'label_restreindre_statut_prive' => 'محدودسازي بعضي از وضعيت‌هاي كاربران در قسمت خصوصي ',
+       'label_restreindre_statut_public' => 'محدودسازي بعضي از وضعيت‌هاي كاربران در قسمت همگاني ',
+       'label_token' => 'نشانه‌ي شناسايي روي ميزبان ',
+
+       // M
+       'mode_insertion_balise' => 'گنجاندن با استفاده از تگ PIWIK# (بايد اسكلت‌ها‌ي خود را اصلاح كنيد)',
+       'mode_insertion_pipeline' => 'گنجاندن خودكار با استفاده از خط لوله "insert_head"',
+
+       // P
+       'piwik' => 'پي‌ويك (Piwik)',
+
+       // T
+       'texte_votre_identifiant' => 'شناسه‌ي شما',
+       'textes_url_piwik' => 'ميزبان پي‌ويك شما'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_fr.php b/www/plugins/spip_piwik_2_0/lang/piwik_fr.php
new file mode 100644 (file)
index 0000000..060f77a
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/spip_piwik/spip_piwik_2_0/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'Créer le site',
+       'action_recuperer_liste' => 'Récupérer la liste des sites',
+
+       // C
+       'cfg_description_piwik' => 'Ici vous pouvez indiquer votre identifiant piwik, ainsi que l\'adresse du serveur gérant vos statistiques.',
+       'cfg_erreur_recuperation_data' => 'Il y a une erreur de communication avec le serveur, veuillez vérifier l\'adresse et le token',
+       'cfg_erreur_token' => 'Votre token d\'identification est invalide',
+       'cfg_erreur_user_token' => 'La correspondance Nom d\'utilisateur / Token n\'est pas correcte.',
+
+       // E
+       'explication_adresse_serveur' => 'Entrez l\'adresse sans "http://" ni "https://" ni slash final',
+       'explication_creer_site' => 'Le lien ci-dessous vous permet de créer un site sur le serveur Piwik qui sera disponible ensuite dans la liste. Vérifiez que vous avez bien configuré l\'adresse et le nom de votre site SPIP avant de cliquer, ce sont ces informations qui seront utilisées.',
+       'explication_exclure_ips' => 'Pour exclure plusieurs adresses, séparez les par des points virgules',
+       'explication_identifiant_site' => 'La liste des sites disponibles sur le serveur Piwik a été récupérée automatiquement gràce aux informations soumises. Sélectionnez dans la liste ci-dessous celui qui vous convient',
+       'explication_mode_insertion' => 'Il existe deux modes d\'insertion dans les pages du code nécessaire au bon fonctionnement du plugin. Par le pipeline "insert_head" (méthode automatique mais peu configurable), ou par l\'insertion d\'une balise (méthode manuelle en insérant dans le pied de vos pages la balise #PIWIK) qui, quant à elle est pleinement configurable.',
+       'explication_recuperer_liste' => 'Le lien ci-dessous vous permet de récupérer la liste des sites que votre compte peut administrer sur le serveur Piwik.',
+       'explication_restreindre_statut_prive' => 'Choisissez ici les statuts d\'utilisateurs qui ne seront pas comptabilisés dans les statistiques dans l\'espace privé',
+       'explication_restreindre_statut_public' => 'Choisissez ici les statuts d\'utilisateurs qui ne seront pas comptabilisés dans les statistiques dans la partie publique',
+       'explication_token' => 'Le token d\'identification est disponible dans vos préférences personnelles ou dans la partie API de votre serveur Piwik',
+
+       // I
+       'info_aucun_site_compte' => 'Aucun site n\'est associé à votre compte Piwik.',
+       'info_aucun_site_compte_demander_admin' => 'Vous devez demander à un administrateur de votre serveur Piwik d\'ajouter un site correspondant.',
+
+       // L
+       'label_adresse_serveur' => 'Adresse URL du serveur (https:// ou http://)',
+       'label_comptabiliser_prive' => 'Comptabiliser les visites de l\'espace privé',
+       'label_creer_site' => 'Créer un site sur le serveur Piwik',
+       'label_exclure_ips' => 'Exclure certaines adresses IP',
+       'label_identifiant_site' => 'L\'identifiant de votre site sur le serveur Piwik',
+       'label_mode_insertion' => 'Mode d\'insertion dans les pages publiques',
+       'label_piwik_user' => 'Compte utilisateur Piwik',
+       'label_recuperer_liste' => 'Récupérer la liste des sites sur le serveur Piwik',
+       'label_restreindre_auteurs_prive' => 'Restreindre certains utilisateurs connectés (privé)',
+       'label_restreindre_auteurs_public' => 'Restreindre certains utilisateurs connectés (public)',
+       'label_restreindre_statut_prive' => 'Restreindre certains statuts d\'utilisateurs dans l\'espace privé',
+       'label_restreindre_statut_public' => 'Restreindre certains statuts d\'utilisateurs dans la partie publique',
+       'label_token' => 'Token d\'identification sur le serveur',
+
+       // M
+       'mode_insertion_balise' => 'Insertion par la balise #PIWIK (modification nécessaire de vos squelettes)',
+       'mode_insertion_pipeline' => 'Insertion automatique par le pipeline "insert_head"',
+
+       // P
+       'piwik' => 'Piwik',
+
+       // T
+       'texte_votre_identifiant' => 'Votre identifiant',
+       'textes_url_piwik' => 'Votre serveur piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_fr_tu.php b/www/plugins/spip_piwik_2_0/lang/piwik_fr_tu.php
new file mode 100644 (file)
index 0000000..a612fa4
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/piwik?lang_cible=fr_tu
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'Créer le site',
+       'action_recuperer_liste' => 'Récupérer la liste des sites',
+
+       // C
+       'cfg_description_piwik' => 'Ici tu peux indiquer ton identifiant piwik, ainsi que l\'adresse du serveur gérant tes statistiques.',
+       'cfg_erreur_recuperation_data' => 'Il y a une erreur de communication avec le serveur, vérifie l\'adresse et le token',
+       'cfg_erreur_token' => 'Ton token d\'identification est invalide',
+       'cfg_erreur_user_token' => 'La correspondance Nom d\'utilisateur / Token n\'est pas correcte.',
+
+       // E
+       'explication_adresse_serveur' => 'Entre l\'adresse sans "http://" ni "https://" ni slash final',
+       'explication_creer_site' => 'Le lien ci-dessous te permet de créer un site sur le serveur Piwik qui sera disponible ensuite dans la liste. Vérifie que tu as bien configuré l\'adresse et le nom de votre site SPIP avant de cliquer, ce sont ces informations qui seront utilisées.',
+       'explication_exclure_ips' => 'Pour exclure plusieurs adresses, sépare les par des points virgules',
+       'explication_identifiant_site' => 'La liste des sites disponibles sur le serveur Piwik a été récupérée automatiquement gràce aux informations soumises. Sélectionne dans la liste ci-dessous celui qui te convient',
+       'explication_mode_insertion' => 'Il existe deux modes d\'insertion dans les pages du code nécessaire au bon fonctionnement du plugin. Par le pipeline "insert_head" (méthode automatique mais peu configurable), ou par l\'insertion d\'une balise (méthode manuelle en insérant dans le pied de tes pages la balise #PIWIK) qui, quant à elle est pleinement configurable.',
+       'explication_recuperer_liste' => 'Le lien ci-dessous te permet de récupérer la liste des sites que ton compte peut administrer sur le serveur Piwik.',
+       'explication_restreindre_statut_prive' => 'Choisis ici les statuts d\'utilisateurs qui ne seront pas comptabilisés dans les statistiques dans l\'espace privé',
+       'explication_restreindre_statut_public' => 'Choisis ici les statuts d\'utilisateurs qui ne seront pas comptabilisés dans les statistiques dans la partie publique',
+       'explication_token' => 'Le token d\'identification est disponible dans tes préférences personnelles ou dans la partie API de ton serveur Piwik',
+
+       // I
+       'info_aucun_site_compte' => 'Aucun site n\'est associé à ton compte Piwik.',
+       'info_aucun_site_compte_demander_admin' => 'Tu dois demander à un administrateur de ton serveur Piwik d\'ajouter un site correspondant.',
+
+       // L
+       'label_adresse_serveur' => 'Adresse URL du serveur (https:// ou http://)',
+       'label_comptabiliser_prive' => 'Comptabiliser les visites de l\'espace privé',
+       'label_creer_site' => 'Créer un site sur le serveur Piwik',
+       'label_exclure_ips' => 'Exclure certaines adresses IP',
+       'label_identifiant_site' => 'L\'identifiant de ton site sur le serveur Piwik',
+       'label_mode_insertion' => 'Mode d\'insertion dans les pages publiques',
+       'label_piwik_user' => 'Compte utilisateur Piwik',
+       'label_recuperer_liste' => 'Récupérer la liste des sites sur le serveur Piwik',
+       'label_restreindre_auteurs_prive' => 'Restreindre certains utilisateurs connectés (privé)',
+       'label_restreindre_auteurs_public' => 'Restreindre certains utilisateurs connectés (public)',
+       'label_restreindre_statut_prive' => 'Restreindre certains statuts d\'utilisateurs dans l\'espace privé',
+       'label_restreindre_statut_public' => 'Restreindre certains statuts d\'utilisateurs dans la partie publique',
+       'label_token' => 'Token d\'identification sur le serveur',
+
+       // M
+       'mode_insertion_balise' => 'Insertion par la balise #PIWIK (modification nécessaire de tes squelettes)',
+       'mode_insertion_pipeline' => 'Insertion automatique par le pipeline "insert_head"',
+
+       // P
+       'piwik' => 'Piwik',
+
+       // T
+       'texte_votre_identifiant' => 'Ton identifiant',
+       'textes_url_piwik' => 'Ton serveur piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/lang/piwik_sk.php b/www/plugins/spip_piwik_2_0/lang/piwik_sk.php
new file mode 100644 (file)
index 0000000..a9da1ec
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/piwik?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'action_creer_site' => 'Vytvoriť stránku',
+       'action_recuperer_liste' => 'Získať zoznam stránok',
+
+       // C
+       'cfg_description_piwik' => 'Tu môžete uviesť svoj identifikátor pre piwik, ako aj adresu svojho štatistického servera.',
+       'cfg_erreur_recuperation_data' => 'Pri komunikácii so serverom sa vyskytol problém – prosím, skontrolujte adresu a token',
+       'cfg_erreur_token' => 'Váš identifikačný reťazec je neplatný',
+       'cfg_erreur_user_token' => 'Používateľské meno alebo reťazec nie sú správne.',
+
+       // E
+       'explication_adresse_serveur' => 'Zadajte adresu stránky bez "http://" alebo "https://" a bez lomky na konci',
+       'explication_creer_site' => 'Odkaz vám umožňuje vytvoriť stránku na serveri s Piwikom, ktorá bude potom dostupná na zozname. Pred kliknutím skontrolujte, či ste správne zadali adresu a názov svojej stránky v SPIPe, lebo tieto údaje sa budú neskôr používať.',
+       'explication_exclure_ips' => 'Ak vymenujete niekoľko adries, ktoré majú byť vylúčené, oddeľte ich bodkočiarkami',
+       'explication_identifiant_site' => 'Zoznam dostupných stránok na serveri s Piwikom bol automaticky získaný pomocou odoslaných údajov. Zo zoznamu si vyberte tú, ktorú chcete použiť.',
+       'explication_mode_insertion' => 'Na vloženie kódu potrebného na správne fungovanie zásuvného modulu sú dva spôsoby. Cez "insert_head" (automatický spôsob, čo sa však nedá upraviť) alebo vložením tagu (manuálne, vložením tagu #PIWIK do päty vašich stránok), čo sa dá upraviť celkom podľa vašich želaní.',
+       'explication_recuperer_liste' => 'Tento odkaz sa používa na získavanie zoznamu stránok, ktoré môže váš účet riadiť na vašom serveri s Piwikom.',
+       'explication_restreindre_statut_prive' => 'Vyberte funkcie používateľov, ktorí nebudú zarátaní do štatistík pre súkromnú zónu',
+       'explication_restreindre_statut_public' => 'Vyberte funkcie používateľov, ktorí sa nebudú brať do úvahy pri štatistikách pre verejne prístupnú stránku',
+       'explication_token' => 'Identifikačný token je dostupný vo vašich osobných predvoľbách alebo v časti aplikácie na vašom serveri s Piwikom',
+
+       // I
+       'info_aucun_site_compte' => 'K vášmu účtu na Piwiku nie sú priradené žiadne stránky.',
+       'info_aucun_site_compte_demander_admin' => 'O pridanie zodpovedajúcej stránky musíte požiadať administrátora svojho servera s Piwikom.',
+
+       // L
+       'label_adresse_serveur' => 'Internetová adresa servera (https:// alebo http://)',
+       'label_comptabiliser_prive' => 'Pridať návštevy súkromnej zóny',
+       'label_creer_site' => 'Vytvoriť stránku na serveri s Piwikom',
+       'label_exclure_ips' => 'Vylúčiť určité IP adresy',
+       'label_identifiant_site' => 'Identifikátor vašej stránky na serveri s Piwikom',
+       'label_mode_insertion' => 'Režim vkladania pre verejne prístupné stránky',
+       'label_piwik_user' => 'Používateľský účet Piwiku',
+       'label_recuperer_liste' => 'Získať zoznam stránok na serveri s Piwikom',
+       'label_restreindre_auteurs_prive' => 'Obmedziť prístup určitým prihláseným používateľom (súkromná zóna)',
+       'label_restreindre_auteurs_public' => 'Obmedziť prístup určitým prihláseným používateľom (verejné)',
+       'label_restreindre_statut_prive' => 'Obmedziť prístup do súkromnej zóny pre určité funkcie',
+       'label_restreindre_statut_public' => 'Obmedziť prístup do súkromnej zóny pre určité funkcie',
+       'label_token' => 'Identifikačný reťazec na server',
+
+       // M
+       'mode_insertion_balise' => 'Vložiť pomocou tagu #PIWIK (musíte upraviť svoje šablóny)',
+       'mode_insertion_pipeline' => 'Automatické vkladanie pomocou reťazenia údajov "insert_head"',
+
+       // P
+       'piwik' => 'Piwik',
+
+       // T
+       'texte_votre_identifiant' => 'Váš identifikátor',
+       'textes_url_piwik' => 'Váš server pre piwik'
+);
+
+?>
diff --git a/www/plugins/spip_piwik_2_0/paquet.xml b/www/plugins/spip_piwik_2_0/paquet.xml
new file mode 100644 (file)
index 0000000..454623c
--- /dev/null
@@ -0,0 +1,27 @@
+<paquet
+       prefix="piwik"
+       categorie="statistique"
+       version="0.6.0"
+       etat="stable"
+       compatibilite="[2.0.8;3.0.99]"
+       logo="piwik.png"
+       schema="0.1"
+       documentation="http://www.spip-contrib.net/?article2860"
+>      
+
+       <nom>Piwik</nom>
+       <!-- Interfacer Spip et Piwik -->
+
+       <auteur>jsb</auteur>
+       <auteur lien="http://www.kent1.info" mail="kent1@arscenic.info">kent1</auteur>
+
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GNU/GPL</licence>
+
+       <traduire module="piwik" reference="fr" gestionnaire="salvatore" />
+
+       <pipeline nom="insert_head" inclure="piwik_pipelines.php" />
+       <pipeline nom="header_prive" inclure="piwik_pipelines.php" />
+       <pipeline nom="formulaire_verifier" inclure="piwik_pipelines.php" />
+
+       <necessite nom="saisies" compatibilite="[1.1;[" />
+</paquet>
diff --git a/www/plugins/spip_piwik_2_0/piwik.png b/www/plugins/spip_piwik_2_0/piwik.png
new file mode 100644 (file)
index 0000000..7f6f9e7
Binary files /dev/null and b/www/plugins/spip_piwik_2_0/piwik.png differ
diff --git a/www/plugins/spip_piwik_2_0/piwik_administrations.php b/www/plugins/spip_piwik_2_0/piwik_administrations.php
new file mode 100644 (file)
index 0000000..6abb45c
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Plugin Piwik
+ * 
+ * @package SPIP\Piwik\Installation
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/meta');
+
+/**
+ * Action d'installation et de mise à jour
+ * 
+ * @param string $nom_meta_version_base
+ *             Le nom de la méta de version dans spip_meta
+ * @param float $version_cible
+ *             Le numéro de version vers laquelle effectuer la maj
+ */
+function piwik_upgrade($nom_meta_version_base, $version_cible){
+
+       $version_actuelle = '0.0';
+       if (
+               (!isset($GLOBALS['meta'][$nom_meta_version_base]))
+               || (($version_actuelle = $GLOBALS['meta'][$nom_meta_version_base]) != $version_cible)
+       ){
+               
+               if (version_compare($version_actuelle,'0.0','=')){
+                       /**
+                        * Si la configuration est présente on récupère la liste des sites
+                        */
+                       if(is_array($config = lire_config('piwik',''))
+                               && isset($config['urlpiwik']) && isset($config['token'])
+                       ){
+                               $piwik_recuperer_data = charger_fonction('piwik_recuperer_data','inc');
+                               
+                               /**
+                                * Récupération de la liste des sites où cet utilisateur 
+                                * a les droits d'admin
+                                */
+                               $method = 'SitesManager.getSitesWithAdminAccess';
+                               $datas = $piwik_recuperer_data($config['urlpiwik'],$config['token'],'',$method,'PHP');
+                               if(is_array(unserialize($datas))){
+                                       ecrire_meta('piwik_sites_dispo', $datas);
+                               }
+                       }
+
+                       ecrire_meta($nom_meta_version_base, $version_actuelle=$version_cible, 'non');
+               }
+       }
+}
+
+/**
+ * Action de désinstallation
+ * -* Effacer la configuration
+ * -* Effacer la liste des sites dispo
+ * -* Effacer la meta de version
+ * 
+ * @param float $nom_meta_version_base
+ */
+function piwik_vider_tables($nom_meta_version_base){
+       effacer_meta('piwik');
+       effacer_meta('piwik_sites_dispo');
+       effacer_meta($nom_meta_version_base);
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/piwik_pipelines.php b/www/plugins/spip_piwik_2_0/piwik_pipelines.php
new file mode 100644 (file)
index 0000000..f494b38
--- /dev/null
@@ -0,0 +1,178 @@
+<?php
+/**
+ * Plugin Piwik
+ * 
+ * @package SPIP\Piwik\Pipelines
+ */
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Insertion dans le pipeline insert_head (SPIP)
+ * 
+ * Ajout du code de piwik dans le head si configuré comme tel
+ * 
+ * @param string $flux
+ *             Le contenu de la balise #INSERT_HEAD
+ * @return string $flux
+ *             Le contenu de la balise #INSERT_HEAD modifié
+ * 
+ */
+function piwik_insert_head($flux){
+       $options = array();
+       
+       if(!function_exists('lire_config'))
+               include_spip('inc/config');
+       
+       if(lire_config('piwik/mode_insertion') == 'pipeline'){
+               $options['type'] = 'public';
+               $flux .= piwik_head_js($options);
+       }
+
+       return $flux;
+}
+
+/**
+ * Insertion dans le pipeline header_prive (SPIP)
+ * 
+ * Insertion du code de Piwik dans l'espace privé si configuré comme tel
+ *
+ * @param string $flux
+ *             Le contenu du head privé
+ * @return string $flux
+ *             Le contenu du head privé modifié
+ */
+function piwik_header_prive($flux){
+       $options = array();
+       
+       if(!function_exists('lire_config'))
+               include_spip('inc/config');
+       
+       if(lire_config('piwik/piwik_prive')){
+               if(is_array(lire_config('piwik/restreindre_statut_prive'))){
+                       $options['statuts_restreints'] = lire_config('piwik/restreindre_statut_prive');
+               }
+               if(is_array(lire_config('piwik/restreindre_auteurs_prive'))){
+                       $options['auteurs_restreints'] = lire_config('piwik/restreindre_auteurs_prive');
+               }
+               $options['type'] = 'prive';
+               $flux .= piwik_head_js($options);
+       }
+       return $flux;
+}
+
+/**
+ * La fonction de génération du code du tracker javascript
+ *
+ * @param array $options [optional]
+ *             
+ * @return
+ */
+function piwik_head_js($options=array()){
+       if(!function_exists('lire_config'))
+               include_spip('inc/config');
+
+       $config = lire_config('piwik',array('id_piwik'=>false,'urlpiwik'=>false));
+       $id_piwik = $config['idpiwik'];
+       $url_piwik = $config['urlpiwik'];
+       $afficher_js = true;
+
+       $ret = '';
+
+       if($url_piwik && $id_piwik){
+               if((isset($options['statut_restreint']) && $options['statut_restreint']) || (isset($options['auteurs_restreints']) && $options['auteurs_restreints'])){
+                       $statut = isset($GLOBALS['visiteur_session']['statut']) ? $GLOBALS['visiteur_session']['statut'] : '';
+                       $id_auteur = isset($GLOBALS['visiteur_session']['id_auteur']) ? $GLOBALS['visiteur_session']['id_auteur'] : '';
+                       if(in_array($statut,$options['statuts_restreints'])){
+                               $afficher_js = false;
+                       }
+                       if($afficher_js && in_array($id_auteur,$options['auteurs_restreints'])){
+                               $afficher_js = false;
+                       }
+               }
+
+               if($afficher_js){
+                       $ret .= "
+                               <script type='text/javascript'>var _paq = _paq || []; 
+                                       (function(){ var u=(('https:' == document.location.protocol) ? 'https://$url_piwik/' : 'http://$url_piwik/'); 
+                                       _paq.push(['setSiteId', $id_piwik]); 
+                                       _paq.push(['setTrackerUrl', u+'piwik.php']); 
+                                       _paq.push(['trackPageView']); 
+                                       _paq.push(['enableLinkTracking']); 
+                                       var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.defer=true; g.async=true; g.src=u+'piwik.js'; 
+                                       s.parentNode.insertBefore(g,s); })();
+                               </script>";
+               }
+       }
+
+       return $ret;
+}
+
+/**
+ * Insertion dans le pipeline formulaire_verifier (SPIP)
+ * On vérifie les valeurs des champs fournis
+ * 
+ * @param array $flux
+ *             Le contexte du pipeline
+ * @return array $flux
+ *             Le contexte du pipeline modifié auquel on a ajouté nos erreurs potentielles
+ */
+function piwik_formulaire_verifier($flux){
+       if($flux['args']['form'] == 'configurer_piwik'){
+               $obligatoires = array('token','user','urlpiwik');
+               foreach($obligatoires as $obligatoire){
+                       if(!_request($obligatoire)){
+                               $flux['data'][$obligatoire] = _T('info_obligatoire');
+                       }
+               }
+               
+               $piwik_token = _request('token');
+               if (!$flux['data']['token'] && !preg_match('/^[a-f0-9]{32}$/i',$piwik_token)) {
+                       $flux['data']['token'] = _T('piwik:cfg_erreur_token');
+                       return $flux;
+               }
+               $piwik_url = 'http://'._request('urlpiwik').'/';
+               
+               $piwik_recuperer_data = charger_fonction('piwik_recuperer_data','inc');
+               
+               /**
+                * Vérifier la correspondance nom d'utilisateur/ token
+                * Qui nous permettra par la suite de définir d'autres choses
+                */
+               $method_verif_user = 'UsersManager.getUser';
+               $options_user = array('userLogin'=>_request('user'));
+               $datas_user = $piwik_recuperer_data($piwik_url,$piwik_token,'',$method_verif_user,'PHP',$options_user);
+               if(is_array($datas_user = unserialize($datas_user))){
+                       if(!$flux['data']['user'] && $flux['data']['result'] == 'error'){
+                               $flux['data']['user'] = _T('piwik:cfg_erreur_user_token');
+                       }
+                       /**
+                        * Vérifier que ce token est un token admin
+                        * Si non : mettre une meta comme quoi il n'est pas admin pour créer des sites
+                        */
+                       $method_verif_user_bis = 'UsersManager.getUsers';
+                       $datas_user_bis = $piwik_recuperer_data($piwik_url,$piwik_token,'',$method_verif_user_bis,'PHP');
+                       $datas_user_bis = unserialize($datas_user_bis);
+                       if(is_array($datas_user_bis) && ($datas_user_bis['result'] == 'error')){
+                               ecrire_meta('piwik_admin', 'non');
+                       }else{
+                               ecrire_meta('piwik_admin', 'oui');
+                               unset($flux['data']['user']);
+                       }
+               }
+       
+               /**
+                * Récupération de la liste des sites où cet utilisateur 
+                * a les droits d'admin
+                */
+               $method = 'SitesManager.getSitesWithAdminAccess';
+               $datas = $piwik_recuperer_data($piwik_url,$piwik_token,'',$method,'PHP');
+               if(!$flux['data']['urlpiwik'] && !is_array(unserialize($datas))){
+                       $flux['data']['urlpiwik'] = _T('piwik:cfg_erreur_recuperation_data');
+               }else{
+                       ecrire_meta('piwik_sites_dispo', $datas);       
+               }
+       }
+       return $flux;
+}
+?>
diff --git a/www/plugins/spip_piwik_2_0/plugin.xml b/www/plugins/spip_piwik_2_0/plugin.xml
new file mode 100644 (file)
index 0000000..a3eefee
--- /dev/null
@@ -0,0 +1,33 @@
+<plugin>\r
+       <nom>Piwik</nom>\r
+       <slogan>Interfacer Spip et Piwik</slogan>\r
+       <auteur>jsb, kent1</auteur>\r
+       <version>0.5.1</version>\r
+       <licence>GNU/GPL</licence>\r
+       <etat>stable</etat>\r
+       <version_base>0.1</version_base>\r
+       <description>\r
+               <multi>\r
+                       [fr]Ajoute le script de statistiques Piwik (analyseur de trafic web) sur les pages du site.\r
+                       [en]Adds the Piwik statistics script (web traffic analyzer) on the pages of the site.\r
+               </multi>\r
+       </description>\r
+       <icon>piwik.png</icon>\r
+       <lien>http://www.spip-contrib.net/?article2860</lien>\r
+       <prefix>piwik</prefix>\r
+       <install>piwik_administrations.php</install>\r
+       <pipeline>\r
+               <nom>insert_head</nom>\r
+               <inclure>piwik_pipelines.php</inclure>\r
+       </pipeline>\r
+       <pipeline>\r
+               <nom>header_prive</nom>\r
+               <inclure>piwik_pipelines.php</inclure>\r
+       </pipeline>\r
+       <necessite id="SPIP" version="[2.0.8;3.0.99]" />\r
+       <necessite id='cfg' version='[1.13.0;]' />\r
+       <necessite id='saisies' version='[1.1;]' />\r
+       <necessite id='spip_bonux' version='[1.8;]' />\r
+       <categorie>statistique</categorie>\r
+       <traduire gestionnaire="salvatore" module="piwik" reference="fr" />\r
+</plugin>\r
diff --git a/www/plugins/spip_piwik_2_0/prive/piwik.html b/www/plugins/spip_piwik_2_0/prive/piwik.html
new file mode 100644 (file)
index 0000000..a770c3d
--- /dev/null
@@ -0,0 +1,10 @@
+#CACHE{0}
+<script type="text/javascript"> 
+var _paq = _paq || []; 
+(function(){ var u=(("https:" == document.location.protocol) ? "https://#CONFIG{piwik/urlpiwik}/" : "http://#CONFIG{piwik/urlpiwik}/"); 
+_paq.push(['setSiteId', #CONFIG{piwik/idpiwik}]); 
+_paq.push(['setTrackerUrl', u+'piwik.php']); 
+_paq.push(['trackPageView']); 
+_paq.push(['enableLinkTracking']); 
+var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.defer=true; g.async=true; g.src=u+'piwik.js'; 
+s.parentNode.insertBefore(g,s); })();</script>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/prive/squelettes/contenu/configurer_piwik.html b/www/plugins/spip_piwik_2_0/prive/squelettes/contenu/configurer_piwik.html
new file mode 100644 (file)
index 0000000..4b7ca55
--- /dev/null
@@ -0,0 +1,7 @@
+[(#AUTORISER{configurer,piwik}|sinon_interdire_acces)]
+<h1 class="grostitre"><:piwik:piwik:></h1>
+
+<p class="explication"><:piwik:cfg_description_piwik:></p>
+<div class="ajax">
+#FORMULAIRE_CONFIGURER_PIWIK
+</div>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/saisies/sites_piwik.html b/www/plugins/spip_piwik_2_0/saisies/sites_piwik.html
new file mode 100644 (file)
index 0000000..ae00f84
--- /dev/null
@@ -0,0 +1,32 @@
+[(#REM)
+
+  Parametres :
+  - class : classe(s) css ajoutes au select
+  - multiple : si quelquechose est passe, le select est multiple, sinon, c'est un select simple
+       Dans le cas multiple, defaut et valeur doivent être un array, sinon un int
+  - option_intro : chaine de langue de la premiere ligne vide ? (defaut:"")
+
+  Exemple d'appel :
+       [(#SAISIE{sites_piwik,idpiwik,
+               label=<:piwik:label_identifiant_site:>
+       })]
+]
+<B_selection>
+<select name="#ENV{nom}" id="champ_#ENV{nom}"[ class="(#ENV{class})"]>
+       [<option value="">(#ENV{option_intro})</option>]
+       <BOUCLE_selection(POUR){tableau #CONFIG{piwik_sites_dispo}}>
+               #SET{id_site,''}
+               #SET{name,''}
+               <BOUCLE_selection_bis(POUR){tableau #VALEUR}>
+                       [(#CLE|=={idsite}|oui)#SET{idsite,#VALEUR}]
+                       [(#CLE|=={name}|oui)#SET{name,#VALEUR}]
+                       [(#CLE|=={main_url}|oui)#SET{main_url,#VALEUR}]
+               </BOUCLE_selection_bis>
+               <option value="#GET{idsite}"[(#GET{idsite}|=={#ENV{valeur}}|ou{#GET{main_url}|=={#ENV{defaut}}}|oui) selected="selected"]>#GET{name}</option>
+       </BOUCLE_selection>
+</select>
+</B_selection>
+<p><:piwik:info_aucun_site_compte:></p>
+[(#CONFIG{piwik_admin}|=={non}|oui)
+<p><:piwik:info_aucun_site_compte_demander_admin:></p>]
+<//B_selection>
\ No newline at end of file
diff --git a/www/plugins/spip_piwik_2_0/svn.revision b/www/plugins/spip_piwik_2_0/svn.revision
new file mode 100644 (file)
index 0000000..abbf84a
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/spip_piwik/spip_piwik_2_0
+Revision: 72440
+Dernier commit: 2013-04-29 17:01:34 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/spip_piwik/spip_piwik_2_0</origine>
+<revision>72440</revision>
+<commit>2013-04-29 17:01:34 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/verifier/aide/verifier.html b/www/plugins/verifier/aide/verifier.html
new file mode 100644 (file)
index 0000000..36b9adb
--- /dev/null
@@ -0,0 +1,73 @@
+
+#SET{infos,#VAL|verifier_generer_aide}
+#SET{verifications,#GET{infos}|table_valeur{verifications}}
+#SET{options,#GET{infos}|table_valeur{options}}
+
+[(#ENV{format}|=={brut}|oui)<textarea style="width:100%; height:100%;">]
+
+Sauter à : <a href="#liste_verifications">Toutes les vérifications</a>, <a href="#liste_options_verifications">Toutes les options</a>
+
+<h2 class="h2 spip">Utilisation des options</h2>
+<B_options_tableau>
+<div style="overflow:auto;">
+<table class="spip">
+<thead>
+       <tr class="first_row">
+               <th>Options \ Vérifications</th>
+               <BOUCLE_verifications_tableau_th(POUR){tableau #GET{verifications}}>
+               <th><a href="#verification_#CLE">#CLE</a></th>
+               </BOUCLE_verifications_tableau_th>
+       </tr>
+</thead>
+<tbody>
+       <BOUCLE_options_tableau(POUR){tableau #GET{options}}>
+       <tr class="tr_liste [(#COMPTEUR_BOUCLE|alterner{row_odd,row_even})]">
+               <th><a href="#option_#CLE">#CLE</a></th>
+               <BOUCLE_verifications_tableau(POUR){tableau #GET{verifications}}>
+               <td>[(#CLE|in_array{[(#_options_tableau:VALEUR|table_valeur{utilisee_par})]}|?{'X','-'})]</td>
+               </BOUCLE_verifications_tableau>
+       </tr>
+       </BOUCLE_options_tableau>
+</tbody>
+</table>
+</div>
+</B_options_tableau>
+
+<h2 class="h2 spip" id="liste_verifications">Toutes les vérifications</h2>
+<BOUCLE_verifications(POUR){tableau #GET{verifications}}>
+<h3 class="h3 spip" id="verification_#CLE">[(#VALEUR|table_valeur{titre})] (#CLE)</h3>
+<p class="description">
+       <strong>Description :</strong> [(#VALEUR|table_valeur{description})]
+</p>
+<p class="options">
+       <strong>Options :</strong>
+       <BOUCLE_options_verification(POUR){tableau #VALEUR|table_valeur{options}}{", "}><a href="#option_#CLE">#CLE</a></BOUCLE_options_verification>
+</p>
+</BOUCLE_verifications>
+
+<h2 class="h2 spip" id="liste_options_verifications">Toutes les options</h2>
+<BOUCLE_options(POUR){tableau #GET{options}}>
+[(#SET{label, [(#VALEUR|table_valeur{label}|sinon{[(#VALEUR|table_valeur{label_case})]})]})]
+<h3 class="h3 spip" id="option_#CLE">[(#GET{label}|?{#GET{label} [ ((#CLE))], #CLE})]</h3>
+[<p class="description">
+       <strong>Description :</strong> (#VALEUR|table_valeur{explication}|sinon{[(#VALEUR|table_valeur{label}|?{[(#VALEUR|table_valeur{label_case})]})]})
+</p>]
+<B_utilisee_par>
+<p class="utilisee_par">
+       <strong>Utilisée par :</strong>
+       <BOUCLE_utilisee_par(POUR){tableau #VALEUR|table_valeur{utilisee_par}}{", "}><a href="#verification_#VALEUR">#VALEUR</a></BOUCLE_utilisee_par>
+</p>
+</B_utilisee_par>
+<B_choix>
+<p class="choix_possibles">
+       <strong>Choix possibles :</strong>
+       <ul class="spip">
+               <BOUCLE_choix(POUR){tableau #VALEUR|table_valeur{datas}}>
+               <li>"#CLE" : #VALEUR</li>
+               </BOUCLE_choix>
+       </ul>
+</p>
+</B_choix>
+</BOUCLE_options>
+
+[(#ENV{format}|=={brut}|oui)</textarea>]
diff --git a/www/plugins/verifier/aide/verifier_fonctions.php b/www/plugins/verifier/aide/verifier_fonctions.php
new file mode 100644 (file)
index 0000000..79d7ab5
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+// Sécurité
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+include_spip('inc/verifier');
+include_spip('inc/saisies');
+
+/*
+ * Génère une page d'aide listant toutes les saisies et leurs options
+ */
+function verifier_generer_aide(){
+       // On a déjà la liste par saisie
+       $verifications = verifier_lister_disponibles();
+       
+       // On construit une liste par options
+       $options = array();
+       foreach ($verifications as $type_verif=>$verification){
+               $options_verification = saisies_lister_par_nom($verification['options'], false);
+               foreach ($options_verification as $nom=>$option){
+                       // Si l'option n'existe pas encore
+                       if (!isset($options[$nom])){
+                               $options[$nom] = _T_ou_typo($option['options']);
+                       }
+                       // On ajoute toujours par qui c'est utilisé
+                       $options[$nom]['utilisee_par'][] = $type_verif;
+               }
+               ksort($options_verification);
+               $verifications[$type_verif]['options'] = $options_verification;
+       }
+       ksort($options);
+       
+       return array(
+               'verifications' => $verifications,
+               'options' => $options
+       );
+}
+
+?>
diff --git a/www/plugins/verifier/images/icones-infos.txt b/www/plugins/verifier/images/icones-infos.txt
new file mode 100644 (file)
index 0000000..64b2f53
--- /dev/null
@@ -0,0 +1,2 @@
+les icones proviennent du site http://www.iconfinder.com/icondetails/24333/128/centang_check_checklist_equiry_list_poll_task_todo_write_icon
+elles ont été dessinées par http://linux.softpedia.com/developer/Oliver-Scholtz-93.html
\ No newline at end of file
diff --git a/www/plugins/verifier/images/verifier-128.png b/www/plugins/verifier/images/verifier-128.png
new file mode 100644 (file)
index 0000000..815579d
Binary files /dev/null and b/www/plugins/verifier/images/verifier-128.png differ
diff --git a/www/plugins/verifier/inc/is_email.php b/www/plugins/verifier/inc/is_email.php
new file mode 100644 (file)
index 0000000..8b4a05f
--- /dev/null
@@ -0,0 +1,1179 @@
+<?php\r
+/**\r
+ * To validate an email address according to RFCs 5321, 5322 and others\r
+ * \r
+ * Copyright © 2008-2011, Dominic Sayers                                      <br>\r
+ * Test schema documentation Copyright © 2011, Daniel Marschall                       <br>\r
+ * All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ * \r
+ *     - Redistributions of source code must retain the above copyright notice,\r
+ *       this list of conditions and the following disclaimer.\r
+ *     - Redistributions in binary form must reproduce the above copyright notice,\r
+ *       this list of conditions and the following disclaimer in the documentation\r
+ *       and/or other materials provided with the distribution.\r
+ *     - Neither the name of Dominic Sayers nor the names of its contributors may be\r
+ *       used to endorse or promote products derived from this software without\r
+ *       specific prior written permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR\r
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * \r
+ * @package    is_email\r
+ * @author     Dominic Sayers <dominic@sayers.cc>\r
+ * @copyright  2008-2011 Dominic Sayers\r
+ * @license    http://www.opensource.org/licenses/bsd-license.php BSD License\r
+ * @link       http://www.dominicsayers.com/isemail\r
+ * @version    3.01.1 - Fixed examples and readme.txt\r
+ */\r
+\r
+// The quality of this code has been improved greatly by using PHPLint\r
+// Copyright (c) 2010 Umberto Salsi\r
+// This is free software; see the license for copying conditions.\r
+// More info: http://www.icosaedro.it/phplint/\r
+/*.\r
+       require_module 'standard';\r
+       require_module 'pcre';\r
+.*/\r
+\r
+if (!defined('ISEMAIL_VALID')) {\r
+/*:diagnostic constants start:*/\r
+// This part of the code is generated using data from test/meta.xml. Beware of making manual alterations\r
+       // Categories\r
+       define('ISEMAIL_VALID_CATEGORY', 1);\r
+       define('ISEMAIL_DNSWARN', 7);\r
+       define('ISEMAIL_RFC5321', 15);\r
+       define('ISEMAIL_CFWS', 31);\r
+       define('ISEMAIL_DEPREC', 63);\r
+       define('ISEMAIL_RFC5322', 127);\r
+       define('ISEMAIL_ERR', 255);\r
+\r
+       // Diagnoses\r
+       // Address is valid\r
+       define('ISEMAIL_VALID', 0);\r
+       // Address is valid but a DNS check was not successful\r
+       define('ISEMAIL_DNSWARN_NO_MX_RECORD', 5);\r
+       define('ISEMAIL_DNSWARN_NO_RECORD', 6);\r
+       // Address is valid for SMTP but has unusual elements\r
+       define('ISEMAIL_RFC5321_TLD', 9);\r
+       define('ISEMAIL_RFC5321_TLDNUMERIC', 10);\r
+       define('ISEMAIL_RFC5321_QUOTEDSTRING', 11);\r
+       define('ISEMAIL_RFC5321_ADDRESSLITERAL', 12);\r
+       define('ISEMAIL_RFC5321_IPV6DEPRECATED', 13);\r
+       // Address is valid within the message but cannot be used unmodified for the envelope\r
+       define('ISEMAIL_CFWS_COMMENT', 17);\r
+       define('ISEMAIL_CFWS_FWS', 18);\r
+       // Address contains deprecated elements but may still be valid in restricted contexts\r
+       define('ISEMAIL_DEPREC_LOCALPART', 33);\r
+       define('ISEMAIL_DEPREC_FWS', 34);\r
+       define('ISEMAIL_DEPREC_QTEXT', 35);\r
+       define('ISEMAIL_DEPREC_QP', 36);\r
+       define('ISEMAIL_DEPREC_COMMENT', 37);\r
+       define('ISEMAIL_DEPREC_CTEXT', 38);\r
+       define('ISEMAIL_DEPREC_CFWS_NEAR_AT', 49);\r
+       // The address is only valid according to the broad definition of RFC 5322. It is otherwise invalid.\r
+       define('ISEMAIL_RFC5322_DOMAIN', 65);\r
+       define('ISEMAIL_RFC5322_TOOLONG', 66);\r
+       define('ISEMAIL_RFC5322_LOCAL_TOOLONG', 67);\r
+       define('ISEMAIL_RFC5322_DOMAIN_TOOLONG', 68);\r
+       define('ISEMAIL_RFC5322_LABEL_TOOLONG', 69);\r
+       define('ISEMAIL_RFC5322_DOMAINLITERAL', 70);\r
+       define('ISEMAIL_RFC5322_DOMLIT_OBSDTEXT', 71);\r
+       define('ISEMAIL_RFC5322_IPV6_GRPCOUNT', 72);\r
+       define('ISEMAIL_RFC5322_IPV6_2X2XCOLON', 73);\r
+       define('ISEMAIL_RFC5322_IPV6_BADCHAR', 74);\r
+       define('ISEMAIL_RFC5322_IPV6_MAXGRPS', 75);\r
+       define('ISEMAIL_RFC5322_IPV6_COLONSTRT', 76);\r
+       define('ISEMAIL_RFC5322_IPV6_COLONEND', 77);\r
+       // Address is invalid for any purpose\r
+       define('ISEMAIL_ERR_EXPECTING_DTEXT', 129);\r
+       define('ISEMAIL_ERR_NOLOCALPART', 130);\r
+       define('ISEMAIL_ERR_NODOMAIN', 131);\r
+       define('ISEMAIL_ERR_CONSECUTIVEDOTS', 132);\r
+       define('ISEMAIL_ERR_ATEXT_AFTER_CFWS', 133);\r
+       define('ISEMAIL_ERR_ATEXT_AFTER_QS', 134);\r
+       define('ISEMAIL_ERR_ATEXT_AFTER_DOMLIT', 135);\r
+       define('ISEMAIL_ERR_EXPECTING_QPAIR', 136);\r
+       define('ISEMAIL_ERR_EXPECTING_ATEXT', 137);\r
+       define('ISEMAIL_ERR_EXPECTING_QTEXT', 138);\r
+       define('ISEMAIL_ERR_EXPECTING_CTEXT', 139);\r
+       define('ISEMAIL_ERR_BACKSLASHEND', 140);\r
+       define('ISEMAIL_ERR_DOT_START', 141);\r
+       define('ISEMAIL_ERR_DOT_END', 142);\r
+       define('ISEMAIL_ERR_DOMAINHYPHENSTART', 143);\r
+       define('ISEMAIL_ERR_DOMAINHYPHENEND', 144);\r
+       define('ISEMAIL_ERR_UNCLOSEDQUOTEDSTR', 145);\r
+       define('ISEMAIL_ERR_UNCLOSEDCOMMENT', 146);\r
+       define('ISEMAIL_ERR_UNCLOSEDDOMLIT', 147);\r
+       define('ISEMAIL_ERR_FWS_CRLF_X2', 148);\r
+       define('ISEMAIL_ERR_FWS_CRLF_END', 149);\r
+       define('ISEMAIL_ERR_CR_NO_LF', 150);\r
+// End of generated code\r
+/*:diagnostic constants end:*/\r
+\r
+       // function control\r
+       define('ISEMAIL_THRESHOLD'              , 16);\r
+\r
+       // Email parts\r
+       define('ISEMAIL_COMPONENT_LOCALPART'    , 0);\r
+       define('ISEMAIL_COMPONENT_DOMAIN'       , 1);\r
+       define('ISEMAIL_COMPONENT_LITERAL'      , 2);\r
+       define('ISEMAIL_CONTEXT_COMMENT'        , 3);\r
+       define('ISEMAIL_CONTEXT_FWS'            , 4);\r
+       define('ISEMAIL_CONTEXT_QUOTEDSTRING'   , 5);\r
+       define('ISEMAIL_CONTEXT_QUOTEDPAIR'     , 6);\r
+\r
+       // Miscellaneous string constants\r
+       define('ISEMAIL_STRING_AT'              , '@');\r
+       define('ISEMAIL_STRING_BACKSLASH'       , '\\');\r
+       define('ISEMAIL_STRING_DOT'             , '.');\r
+       define('ISEMAIL_STRING_DQUOTE'          , '"');\r
+       define('ISEMAIL_STRING_OPENPARENTHESIS' , '(');\r
+       define('ISEMAIL_STRING_CLOSEPARENTHESIS', ')');\r
+       define('ISEMAIL_STRING_OPENSQBRACKET'   , '[');\r
+       define('ISEMAIL_STRING_CLOSESQBRACKET'  , ']');\r
+       define('ISEMAIL_STRING_HYPHEN'          , '-');\r
+       define('ISEMAIL_STRING_COLON'           , ':');\r
+       define('ISEMAIL_STRING_DOUBLECOLON'     , '::');\r
+       define('ISEMAIL_STRING_SP'              , ' ');\r
+       define('ISEMAIL_STRING_HTAB'            , "\t");\r
+       define('ISEMAIL_STRING_CR'              , "\r");\r
+       define('ISEMAIL_STRING_LF'              , "\n");\r
+       define('ISEMAIL_STRING_IPV6TAG'         , 'IPv6:');\r
+       // US-ASCII visible characters not valid for atext (http://tools.ietf.org/html/rfc5322#section-3.2.3)\r
+       define('ISEMAIL_STRING_SPECIALS'        , '()<>[]:;@\\,."');\r
+}\r
+\r
+/**\r
+ * Check that an email address conforms to RFCs 5321, 5322 and others\r
+ *\r
+ * As of Version 3.0, we are now distinguishing clearly between a Mailbox\r
+ * as defined by RFC 5321 and an addr-spec as defined by RFC 5322. Depending\r
+ * on the context, either can be regarded as a valid email address. The\r
+ * RFC 5321 Mailbox specification is more restrictive (comments, white space\r
+ * and obsolete forms are not allowed)\r
+ *\r
+ * @param string       $email          The email address to check\r
+ * @param boolean      $checkDNS       If true then a DNS check for MX records will be made\r
+ * @param mixed                $errorlevel     Determines the boundary between valid and invalid addresses.\r
+ *                                     Status codes above this number will be returned as-is,\r
+ *                                     status codes below will be returned as ISEMAIL_VALID. Thus the\r
+ *                                     calling program can simply look for ISEMAIL_VALID if it is\r
+ *                                     only interested in whether an address is valid or not. The\r
+ *                                     errorlevel will determine how "picky" is_email() is about\r
+ *                                     the address.\r
+ *\r
+ *                                     If omitted or passed as false then is_email() will return\r
+ *                                     true or false rather than an integer error or warning.\r
+ *\r
+ *                                     NB Note the difference between $errorlevel = false and\r
+ *                                     $errorlevel = 0\r
+ * @param array                $parsedata      If passed, returns the parsed address components\r
+ */\r
+/*.mixed.*/ function is_email($email, $checkDNS = false, $errorlevel = false, &$parsedata = array()) {\r
+       // Check that $email is a valid address. Read the following RFCs to understand the constraints:\r
+       //      (http://tools.ietf.org/html/rfc5321)\r
+       //      (http://tools.ietf.org/html/rfc5322)\r
+       //      (http://tools.ietf.org/html/rfc4291#section-2.2)\r
+       //      (http://tools.ietf.org/html/rfc1123#section-2.1)\r
+       //      (http://tools.ietf.org/html/rfc3696) (guidance only)\r
+// version 2.0: Enhance $diagnose parameter to $errorlevel\r
+// version 3.0: Introduced status categories\r
+// revision 3.1: BUG: $parsedata was passed by value instead of by reference\r
+\r
+       if (is_bool($errorlevel)) {\r
+               $threshold      = ISEMAIL_VALID;\r
+               $diagnose       = (bool) $errorlevel;\r
+       } else {\r
+               $diagnose       = true;\r
+\r
+               switch ((int) $errorlevel) {\r
+               case E_WARNING: $threshold      = ISEMAIL_THRESHOLD;    break;  // For backward compatibility\r
+               case E_ERROR:   $threshold      = ISEMAIL_VALID;        break;  // For backward compatibility\r
+               default:        $threshold      = (int) $errorlevel;\r
+               }\r
+       }\r
+\r
+       $return_status = array(ISEMAIL_VALID);\r
+\r
+       // Parse the address into components, character by character\r
+       $raw_length     = strlen($email);\r
+       $context        = ISEMAIL_COMPONENT_LOCALPART;  // Where we are\r
+       $context_stack  = array($context);              // Where we have been\r
+       $context_prior  = ISEMAIL_COMPONENT_LOCALPART;  // Where we just came from\r
+       $token          = '';                           // The current character\r
+       $token_prior    = '';                           // The previous character\r
+       $parsedata      = array(\r
+                               ISEMAIL_COMPONENT_LOCALPART     => '',\r
+                               ISEMAIL_COMPONENT_DOMAIN        => ''\r
+                              );                       // For the components of the address\r
+\r
+       $atomlist       = array(\r
+                               ISEMAIL_COMPONENT_LOCALPART     => array(''),\r
+                               ISEMAIL_COMPONENT_DOMAIN        => array('')\r
+                              );                       // For the dot-atom elements of the address\r
+       $element_count  = 0;\r
+       $element_len    = 0;\r
+       $hyphen_flag    = false;                        // Hyphen cannot occur at the end of a subdomain\r
+       $end_or_die     = false;                        // CFWS can only appear at the end of the element\r
+\r
+//-echo "<table style=\"clear:left;\">"; // debug\r
+       for ($i = 0; $i < $raw_length; $i++) {\r
+               $token = $email[$i];\r
+//-echo "<tr><td><strong>$context|",(($end_or_die) ? 'true' : 'false'),"|$token|" . max($return_status) . "</strong></td>"; // debug\r
+\r
+               switch ($context) {\r
+               //-------------------------------------------------------------\r
+               // local-part\r
+               //-------------------------------------------------------------\r
+               case ISEMAIL_COMPONENT_LOCALPART:\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.4.1\r
+                       //   local-part      =   dot-atom / quoted-string / obs-local-part\r
+                       //\r
+                       //   dot-atom        =   [CFWS] dot-atom-text [CFWS]\r
+                       //\r
+                       //   dot-atom-text   =   1*atext *("." 1*atext)\r
+                       //\r
+                       //   quoted-string   =   [CFWS]\r
+                       //                       DQUOTE *([FWS] qcontent) [FWS] DQUOTE\r
+                       //                       [CFWS]\r
+                       //\r
+                       //   obs-local-part  =   word *("." word)\r
+                       //\r
+                       //   word            =   atom / quoted-string\r
+                       //\r
+                       //   atom            =   [CFWS] 1*atext [CFWS]\r
+                       switch ($token) {\r
+                       // Comment\r
+                       case ISEMAIL_STRING_OPENPARENTHESIS:\r
+                               if ($element_len === 0)\r
+                                       // Comments are OK at the beginning of an element\r
+                                       $return_status[]        = ($element_count === 0) ? ISEMAIL_CFWS_COMMENT : ISEMAIL_DEPREC_COMMENT;\r
+                               else {\r
+                                       $return_status[]        = ISEMAIL_CFWS_COMMENT;\r
+                                       $end_or_die             = true; // We can't start a comment in the middle of an element, so this better be the end\r
+                               }\r
+\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_COMMENT;\r
+                               break;\r
+                       // Next dot-atom element\r
+                       case ISEMAIL_STRING_DOT:\r
+                               if ($element_len === 0)\r
+                                       // Another dot, already?\r
+                                       $return_status[] = ($element_count === 0) ? ISEMAIL_ERR_DOT_START : ISEMAIL_ERR_CONSECUTIVEDOTS;        // Fatal error\r
+                               else\r
+                                       // The entire local-part can be a quoted string for RFC 5321\r
+                                       // If it's just one atom that is quoted then it's an RFC 5322 obsolete form\r
+                                       if ($end_or_die) $return_status[] = ISEMAIL_DEPREC_LOCALPART;\r
+\r
+                                       $end_or_die     = false;        // CFWS & quoted strings are OK again now we're at the beginning of an element (although they are obsolete forms)\r
+                                       $element_len    = 0;\r
+                                       $element_count++;\r
+                                       $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;\r
+                                       $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  = '';\r
+\r
+                               break;\r
+                       // Quoted string\r
+                       case ISEMAIL_STRING_DQUOTE:\r
+                               if ($element_len === 0) {\r
+                                       // The entire local-part can be a quoted string for RFC 5321\r
+                                       // If it's just one atom that is quoted then it's an RFC 5322 obsolete form\r
+                                       $return_status[]        = ($element_count === 0) ? ISEMAIL_RFC5321_QUOTEDSTRING : ISEMAIL_DEPREC_LOCALPART;\r
+\r
+                                       $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;\r
+                                       $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;\r
+                                       $element_len++;\r
+                                       $end_or_die             = true; // Quoted string must be the entire element\r
+                                       $context_stack[]        = $context;\r
+                                       $context                = ISEMAIL_CONTEXT_QUOTEDSTRING;\r
+                               } else {\r
+                                       $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error\r
+                               }\r
+\r
+                               break;\r
+                       // Folding White Space\r
+                       case ISEMAIL_STRING_CR:\r
+                       case ISEMAIL_STRING_SP:\r
+                       case ISEMAIL_STRING_HTAB:\r
+                               if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error\r
+\r
+                               if ($element_len === 0)\r
+                                       $return_status[] = ($element_count === 0) ? ISEMAIL_CFWS_FWS : ISEMAIL_DEPREC_FWS;\r
+                               else\r
+                                       $end_or_die = true;     // We can't start FWS in the middle of an element, so this better be the end\r
+\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_FWS;\r
+                               $token_prior            = $token;\r
+\r
+                               break;\r
+                       // @\r
+                       case ISEMAIL_STRING_AT:\r
+                               // At this point we should have a valid local-part\r
+                               if (count($context_stack) !== 1) die('Unexpected item on context stack');\r
+\r
+                               if      ($parsedata[ISEMAIL_COMPONENT_LOCALPART] === '')\r
+                                                               $return_status[]        = ISEMAIL_ERR_NOLOCALPART;      // Fatal error\r
+                               elseif  ($element_len === 0)    $return_status[]        = ISEMAIL_ERR_DOT_END;  // Fatal error\r
+                               // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1\r
+                               //   The maximum total length of a user name or other local-part is 64\r
+                               //   octets.\r
+                               elseif  (strlen($parsedata[ISEMAIL_COMPONENT_LOCALPART]) > 64)\r
+                                                               $return_status[]        = ISEMAIL_RFC5322_LOCAL_TOOLONG;\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.4.1\r
+                               //   Comments and folding white space\r
+                               //   SHOULD NOT be used around the "@" in the addr-spec.\r
+                               //\r
+                               // http://tools.ietf.org/html/rfc2119\r
+                               // 4. SHOULD NOT   This phrase, or the phrase "NOT RECOMMENDED" mean that\r
+                               //    there may exist valid reasons in particular circumstances when the\r
+                               //    particular behavior is acceptable or even useful, but the full\r
+                               //    implications should be understood and the case carefully weighed\r
+                               //    before implementing any behavior described with this label.\r
+                               elseif  (($context_prior === ISEMAIL_CONTEXT_COMMENT) || ($context_prior === ISEMAIL_CONTEXT_FWS))\r
+                                                               $return_status[]        = ISEMAIL_DEPREC_CFWS_NEAR_AT;\r
+\r
+                               // Clear everything down for the domain parsing\r
+                               $context        = ISEMAIL_COMPONENT_DOMAIN;     // Where we are\r
+                               $context_stack  = array($context);              // Where we have been\r
+                               $element_count  = 0;\r
+                               $element_len    = 0;\r
+                               $end_or_die     = false;                        // CFWS can only appear at the end of the element\r
+\r
+                               break;\r
+                       // atext\r
+                       default:\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.3\r
+                               //    atext           =   ALPHA / DIGIT /    ; Printable US-ASCII\r
+                               //                        "!" / "#" /        ;  characters not including\r
+                               //                        "$" / "%" /        ;  specials.  Used for atoms.\r
+                               //                        "&" / "'" /\r
+                               //                        "*" / "+" /\r
+                               //                        "-" / "/" /\r
+                               //                        "=" / "?" /\r
+                               //                        "^" / "_" /\r
+                               //                        "`" / "{" /\r
+                               //                        "|" / "}" /\r
+                               //                        "~"\r
+                               if ($end_or_die) {\r
+                                       // We have encountered atext where it is no longer valid\r
+                                       switch ($context_prior) {\r
+                                       case ISEMAIL_CONTEXT_COMMENT:\r
+                                       case ISEMAIL_CONTEXT_FWS:\r
+                                               $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_CFWS;\r
+                                               break;\r
+                                       case ISEMAIL_CONTEXT_QUOTEDSTRING:\r
+                                               $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_QS;\r
+                                               break;\r
+                                       default:\r
+                                               die ("More atext found where none is allowed, but unrecognised prior context: $context_prior");\r
+                                       }\r
+                               } else {\r
+                                       $context_prior  = $context;\r
+                                       $ord            = ord($token);\r
+\r
+                                       if (($ord < 33) || ($ord > 126) || ($ord === 10) || (!is_bool(strpos(ISEMAIL_STRING_SPECIALS, $token))))\r
+                                               $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error\r
+\r
+                                       $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;\r
+                                       $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;\r
+                                       $element_len++;\r
+                               }\r
+                       }\r
+\r
+                       break;\r
+               //-------------------------------------------------------------\r
+               // Domain\r
+               //-------------------------------------------------------------\r
+               case ISEMAIL_COMPONENT_DOMAIN:\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.4.1\r
+                       //   domain          =   dot-atom / domain-literal / obs-domain\r
+                       //\r
+                       //   dot-atom        =   [CFWS] dot-atom-text [CFWS]\r
+                       //\r
+                       //   dot-atom-text   =   1*atext *("." 1*atext)\r
+                       //\r
+                       //   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]\r
+                       //\r
+                       //   dtext           =   %d33-90 /          ; Printable US-ASCII\r
+                       //                       %d94-126 /         ;  characters not including\r
+                       //                       obs-dtext          ;  "[", "]", or "\"\r
+                       //\r
+                       //   obs-domain      =   atom *("." atom)\r
+                       //\r
+                       //   atom            =   [CFWS] 1*atext [CFWS]\r
+\r
+\r
+                       // http://tools.ietf.org/html/rfc5321#section-4.1.2\r
+                       //   Mailbox        = Local-part "@" ( Domain / address-literal )\r
+                       //\r
+                       //   Domain         = sub-domain *("." sub-domain)\r
+                       //\r
+                       //   address-literal  = "[" ( IPv4-address-literal /\r
+                       //                    IPv6-address-literal /\r
+                       //                    General-address-literal ) "]"\r
+                       //                    ; See Section 4.1.3\r
+\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.4.1\r
+                       //      Note: A liberal syntax for the domain portion of addr-spec is\r
+                       //      given here.  However, the domain portion contains addressing\r
+                       //      information specified by and used in other protocols (e.g.,\r
+                       //      [RFC1034], [RFC1035], [RFC1123], [RFC5321]).  It is therefore\r
+                       //      incumbent upon implementations to conform to the syntax of\r
+                       //      addresses for the context in which they are used.\r
+                       // is_email() author's note: it's not clear how to interpret this in\r
+                       // the context of a general email address validator. The conclusion I\r
+                       // have reached is this: "addressing information" must comply with\r
+                       // RFC 5321 (and in turn RFC 1035), anything that is "semantically\r
+                       // invisible" must comply only with RFC 5322.\r
+                       switch ($token) {\r
+                       // Comment\r
+                       case ISEMAIL_STRING_OPENPARENTHESIS:\r
+                               if ($element_len === 0)\r
+                                       // Comments at the start of the domain are deprecated in the text\r
+                                       // Comments at the start of a subdomain are obs-domain\r
+                                       // (http://tools.ietf.org/html/rfc5322#section-3.4.1)\r
+                                       $return_status[]        = ($element_count === 0) ? ISEMAIL_DEPREC_CFWS_NEAR_AT : ISEMAIL_DEPREC_COMMENT;\r
+                               else {\r
+                                       $return_status[]        = ISEMAIL_CFWS_COMMENT;\r
+                                       $end_or_die             = true; // We can't start a comment in the middle of an element, so this better be the end\r
+                               }\r
+\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_COMMENT;\r
+                               break;\r
+                       // Next dot-atom element\r
+                       case ISEMAIL_STRING_DOT:\r
+                               if ($element_len === 0)\r
+                                       // Another dot, already?\r
+                                       $return_status[]        = ($element_count === 0) ? ISEMAIL_ERR_DOT_START : ISEMAIL_ERR_CONSECUTIVEDOTS; // Fatal error\r
+                               elseif ($hyphen_flag)\r
+                                       // Previous subdomain ended in a hyphen\r
+                                       $return_status[]        = ISEMAIL_ERR_DOMAINHYPHENEND;  // Fatal error\r
+                               else\r
+                                       // Nowhere in RFC 5321 does it say explicitly that the\r
+                                       // domain part of a Mailbox must be a valid domain according\r
+                                       // to the DNS standards set out in RFC 1035, but this *is*\r
+                                       // implied in several places. For instance, wherever the idea\r
+                                       // of host routing is discussed the RFC says that the domain\r
+                                       // must be looked up in the DNS. This would be nonsense unless\r
+                                       // the domain was designed to be a valid DNS domain. Hence we\r
+                                       // must conclude that the RFC 1035 restriction on label length\r
+                                       // also applies to RFC 5321 domains.\r
+                                       //\r
+                                       // http://tools.ietf.org/html/rfc1035#section-2.3.4\r
+                                       // labels          63 octets or less\r
+                                       if ($element_len > 63) $return_status[] = ISEMAIL_RFC5322_LABEL_TOOLONG;\r
+\r
+                                       $end_or_die             = false;        // CFWS is OK again now we're at the beginning of an element (although it may be obsolete CFWS)\r
+                                       $element_len            = 0;\r
+                                       $element_count++;\r
+                                       $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     = '';\r
+                                       $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;\r
+\r
+                               break;\r
+                       // Domain literal\r
+                       case ISEMAIL_STRING_OPENSQBRACKET:\r
+                               if ($parsedata[ISEMAIL_COMPONENT_DOMAIN] === '') {\r
+                                       $end_or_die             = true; // Domain literal must be the only component\r
+                                       $element_len++;\r
+                                       $context_stack[]        = $context;\r
+                                       $context                = ISEMAIL_COMPONENT_LITERAL;\r
+                                       $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;\r
+                                       $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;\r
+                                       $parsedata[ISEMAIL_COMPONENT_LITERAL]                   = '';\r
+                               } else {\r
+                                       $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error\r
+                               }\r
+\r
+                               break;\r
+                       // Folding White Space\r
+                       case ISEMAIL_STRING_CR:\r
+                       case ISEMAIL_STRING_SP:\r
+                       case ISEMAIL_STRING_HTAB:\r
+                               if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error\r
+\r
+                               if ($element_len === 0)\r
+                                       $return_status[]        = ($element_count === 0) ? ISEMAIL_DEPREC_CFWS_NEAR_AT : ISEMAIL_DEPREC_FWS;\r
+                               else {\r
+                                       $return_status[]        = ISEMAIL_CFWS_FWS;\r
+                                       $end_or_die     = true; // We can't start FWS in the middle of an element, so this better be the end\r
+                               }\r
+\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_FWS;\r
+                               $token_prior            = $token;\r
+                               break;\r
+                       // atext\r
+                       default:\r
+                               // RFC 5322 allows any atext...\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.3\r
+                               //    atext           =   ALPHA / DIGIT /    ; Printable US-ASCII\r
+                               //                        "!" / "#" /        ;  characters not including\r
+                               //                        "$" / "%" /        ;  specials.  Used for atoms.\r
+                               //                        "&" / "'" /\r
+                               //                        "*" / "+" /\r
+                               //                        "-" / "/" /\r
+                               //                        "=" / "?" /\r
+                               //                        "^" / "_" /\r
+                               //                        "`" / "{" /\r
+                               //                        "|" / "}" /\r
+                               //                        "~"\r
+\r
+                               // But RFC 5321 only allows letter-digit-hyphen to comply with DNS rules (RFCs 1034 & 1123)\r
+                               // http://tools.ietf.org/html/rfc5321#section-4.1.2\r
+                               //   sub-domain     = Let-dig [Ldh-str]\r
+                               //\r
+                               //   Let-dig        = ALPHA / DIGIT\r
+                               //\r
+                               //   Ldh-str        = *( ALPHA / DIGIT / "-" ) Let-dig\r
+                               //\r
+                               if ($end_or_die) {\r
+                                       // We have encountered atext where it is no longer valid\r
+                                       switch ($context_prior) {\r
+                                       case ISEMAIL_CONTEXT_COMMENT:\r
+                                       case ISEMAIL_CONTEXT_FWS:\r
+                                               $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_CFWS;\r
+                                               break;\r
+                                       case ISEMAIL_COMPONENT_LITERAL:\r
+                                               $return_status[]        = ISEMAIL_ERR_ATEXT_AFTER_DOMLIT;\r
+                                               break;\r
+                                       default:\r
+                                               die ("More atext found where none is allowed, but unrecognised prior context: $context_prior");\r
+                                       }\r
+                               }\r
+\r
+                               $ord            = ord($token);\r
+                               $hyphen_flag    = false;        // Assume this token isn't a hyphen unless we discover it is\r
+\r
+                               if (($ord < 33) || ($ord > 126) || (!is_bool(strpos(ISEMAIL_STRING_SPECIALS, $token)))) {\r
+                                       $return_status[]        = ISEMAIL_ERR_EXPECTING_ATEXT;  // Fatal error\r
+                               } elseif ($token === ISEMAIL_STRING_HYPHEN) {\r
+                                       if ($element_len === 0) {\r
+                                               // Hyphens can't be at the beginning of a subdomain\r
+                                               $return_status[]        = ISEMAIL_ERR_DOMAINHYPHENSTART;        // Fatal error\r
+                                       }\r
+\r
+                                       $hyphen_flag = true;\r
+                               } elseif (!(($ord > 47 && $ord < 58) || ($ord > 64 && $ord < 91) || ($ord > 96 && $ord < 123))) {\r
+                                       // Not an RFC 5321 subdomain, but still OK by RFC 5322\r
+                                       $return_status[]        = ISEMAIL_RFC5322_DOMAIN;\r
+                               }\r
+\r
+                               $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;\r
+                               $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;\r
+                               $element_len++;\r
+                       }\r
+\r
+                       break;\r
+               //-------------------------------------------------------------\r
+               // Domain literal\r
+               //-------------------------------------------------------------\r
+               case ISEMAIL_COMPONENT_LITERAL:\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.4.1\r
+                       //   domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]\r
+                       //\r
+                       //   dtext           =   %d33-90 /          ; Printable US-ASCII\r
+                       //                       %d94-126 /         ;  characters not including\r
+                       //                       obs-dtext          ;  "[", "]", or "\"\r
+                       //\r
+                       //   obs-dtext       =   obs-NO-WS-CTL / quoted-pair\r
+                       switch ($token) {\r
+                       // End of domain literal\r
+                       case ISEMAIL_STRING_CLOSESQBRACKET:\r
+                               if ((int) max($return_status) < ISEMAIL_DEPREC) {\r
+                                       // Could be a valid RFC 5321 address literal, so let's check\r
+\r
+                                       // http://tools.ietf.org/html/rfc5321#section-4.1.2\r
+                                       //   address-literal  = "[" ( IPv4-address-literal /\r
+                                       //                    IPv6-address-literal /\r
+                                       //                    General-address-literal ) "]"\r
+                                       //                    ; See Section 4.1.3\r
+                                       //\r
+                                       // http://tools.ietf.org/html/rfc5321#section-4.1.3\r
+                                       //   IPv4-address-literal  = Snum 3("."  Snum)\r
+                                       //\r
+                                       //   IPv6-address-literal  = "IPv6:" IPv6-addr\r
+                                       //\r
+                                       //   General-address-literal  = Standardized-tag ":" 1*dcontent\r
+                                       //\r
+                                       //   Standardized-tag  = Ldh-str\r
+                                       //                     ; Standardized-tag MUST be specified in a\r
+                                       //                     ; Standards-Track RFC and registered with IANA\r
+                                       //\r
+                                       //   dcontent       = %d33-90 / ; Printable US-ASCII\r
+                                       //                  %d94-126 ; excl. "[", "\", "]"\r
+                                       //\r
+                                       //   Snum           = 1*3DIGIT\r
+                                       //                  ; representing a decimal integer\r
+                                       //                  ; value in the range 0 through 255\r
+                                       //\r
+                                       //   IPv6-addr      = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp\r
+                                       //\r
+                                       //   IPv6-hex       = 1*4HEXDIG\r
+                                       //\r
+                                       //   IPv6-full      = IPv6-hex 7(":" IPv6-hex)\r
+                                       //\r
+                                       //   IPv6-comp      = [IPv6-hex *5(":" IPv6-hex)] "::"\r
+                                       //                  [IPv6-hex *5(":" IPv6-hex)]\r
+                                       //                  ; The "::" represents at least 2 16-bit groups of\r
+                                       //                  ; zeros.  No more than 6 groups in addition to the\r
+                                       //                  ; "::" may be present.\r
+                                       //\r
+                                       //   IPv6v4-full    = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal\r
+                                       //\r
+                                       //   IPv6v4-comp    = [IPv6-hex *3(":" IPv6-hex)] "::"\r
+                                       //                  [IPv6-hex *3(":" IPv6-hex) ":"]\r
+                                       //                  IPv4-address-literal\r
+                                       //                  ; The "::" represents at least 2 16-bit groups of\r
+                                       //                  ; zeros.  No more than 4 groups in addition to the\r
+                                       //                  ; "::" and IPv4-address-literal may be present.\r
+                                       //\r
+                                       // is_email() author's note: We can't use ip2long() to validate\r
+                                       // IPv4 addresses because it accepts abbreviated addresses\r
+                                       // (xxx.xxx.xxx), expanding the last group to complete the address.\r
+                                       // filter_var() validates IPv6 address inconsistently (up to PHP 5.3.3\r
+                                       // at least) -- see http://bugs.php.net/bug.php?id=53236 for example\r
+                                       $max_groups     = 8;\r
+                                       $matchesIP      = array();\r
+                       /*.mixed.*/     $index          = false;\r
+                                       $addressliteral = $parsedata[ISEMAIL_COMPONENT_LITERAL];\r
+\r
+                                       // Extract IPv4 part from the end of the address-literal (if there is one)\r
+                                       if (preg_match('/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/', $addressliteral, $matchesIP) > 0) {\r
+                                               $index = strrpos($addressliteral, $matchesIP[0]);\r
+                                               if ($index !== 0) $addressliteral = substr($addressliteral, 0, $index) . '0:0'; // Convert IPv4 part to IPv6 format for further testing\r
+                                       }\r
+\r
+                                       if ($index === 0) {\r
+                                               // Nothing there except a valid IPv4 address, so...\r
+                                               $return_status[]        = ISEMAIL_RFC5321_ADDRESSLITERAL;\r
+                                       } elseif (strncasecmp($addressliteral, ISEMAIL_STRING_IPV6TAG, 5) !== 0) {\r
+                                               $return_status[]        = ISEMAIL_RFC5322_DOMAINLITERAL;\r
+                                       } else {\r
+                                               $IPv6           = substr($addressliteral, 5);\r
+                                               $matchesIP      = explode(ISEMAIL_STRING_COLON, $IPv6); // Revision 2.7: Daniel Marschall's new IPv6 testing strategy\r
+                                               $groupCount     = count($matchesIP);\r
+                                               $index          = strpos($IPv6,ISEMAIL_STRING_DOUBLECOLON);\r
+\r
+                                               if ($index === false) {\r
+                                                       // We need exactly the right number of groups\r
+                                                       if ($groupCount !== $max_groups)\r
+                                                               $return_status[]        = ISEMAIL_RFC5322_IPV6_GRPCOUNT;\r
+                                               } else {\r
+                                                       if ($index !== strrpos($IPv6,ISEMAIL_STRING_DOUBLECOLON))\r
+                                                               $return_status[]        = ISEMAIL_RFC5322_IPV6_2X2XCOLON;\r
+                                                       else {\r
+                                                               if ($index === 0 || $index === (strlen($IPv6) - 2)) $max_groups++;      // RFC 4291 allows :: at the start or end of an address with 7 other groups in addition\r
+\r
+                                                               if ($groupCount > $max_groups)\r
+                                                                       $return_status[]        = ISEMAIL_RFC5322_IPV6_MAXGRPS;\r
+                                                               elseif ($groupCount === $max_groups)\r
+                                                                       $return_status[]        = ISEMAIL_RFC5321_IPV6DEPRECATED;       // Eliding a single "::"\r
+                                                       }\r
+                                               }\r
+\r
+                                               // Revision 2.7: Daniel Marschall's new IPv6 testing strategy\r
+                                               if ((substr($IPv6, 0,  1) === ISEMAIL_STRING_COLON) && (substr($IPv6, 1,  1) !== ISEMAIL_STRING_COLON))\r
+                                                       $return_status[]        = ISEMAIL_RFC5322_IPV6_COLONSTRT;       // Address starts with a single colon\r
+                                               elseif ((substr($IPv6, -1) === ISEMAIL_STRING_COLON) && (substr($IPv6, -2, 1) !== ISEMAIL_STRING_COLON))\r
+                                                       $return_status[]        = ISEMAIL_RFC5322_IPV6_COLONEND;        // Address ends with a single colon\r
+                                               elseif (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0)\r
+                                                       $return_status[]        = ISEMAIL_RFC5322_IPV6_BADCHAR; // Check for unmatched characters\r
+                                               else\r
+                                                       $return_status[]        = ISEMAIL_RFC5321_ADDRESSLITERAL;\r
+                                       }\r
+                               } else\r
+                                       $return_status[]        = ISEMAIL_RFC5322_DOMAINLITERAL;\r
+\r
+\r
+                               $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;\r
+                               $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;\r
+                               $element_len++;\r
+                               $context_prior          = $context;\r
+                               $context                = (int) array_pop($context_stack);\r
+                               break;\r
+                       case ISEMAIL_STRING_BACKSLASH:\r
+                               $return_status[]        = ISEMAIL_RFC5322_DOMLIT_OBSDTEXT;\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_QUOTEDPAIR;\r
+                               break;\r
+                       // Folding White Space\r
+                       case ISEMAIL_STRING_CR:\r
+                       case ISEMAIL_STRING_SP:\r
+                       case ISEMAIL_STRING_HTAB:\r
+                               if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error\r
+\r
+                               $return_status[]        = ISEMAIL_CFWS_FWS;\r
+\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_FWS;\r
+                               $token_prior            = $token;\r
+                               break;\r
+                       // dtext\r
+                       default:\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.4.1\r
+                               //   dtext           =   %d33-90 /          ; Printable US-ASCII\r
+                               //                       %d94-126 /         ;  characters not including\r
+                               //                       obs-dtext          ;  "[", "]", or "\"\r
+                               //\r
+                               //   obs-dtext       =   obs-NO-WS-CTL / quoted-pair\r
+                               //\r
+                               //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control\r
+                               //                       %d11 /             ;  characters that do not\r
+                               //                       %d12 /             ;  include the carriage\r
+                               //                       %d14-31 /          ;  return, line feed, and\r
+                               //                       %d127              ;  white space characters\r
+                               $ord = ord($token);\r
+\r
+                               // CR, LF, SP & HTAB have already been parsed above\r
+                               if (($ord > 127) || ($ord === 0) || ($token === ISEMAIL_STRING_OPENSQBRACKET)) {\r
+                                       $return_status[]        = ISEMAIL_ERR_EXPECTING_DTEXT;  // Fatal error\r
+                                       break;\r
+                               } elseif (($ord < 33) || ($ord === 127)) {\r
+                                       $return_status[]        = ISEMAIL_RFC5322_DOMLIT_OBSDTEXT;\r
+                               }\r
+\r
+                               $parsedata[ISEMAIL_COMPONENT_LITERAL]                   .= $token;\r
+                               $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;\r
+                               $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;\r
+                               $element_len++;\r
+                       }\r
+\r
+                       break;\r
+               //-------------------------------------------------------------\r
+               // Quoted string\r
+               //-------------------------------------------------------------\r
+               case ISEMAIL_CONTEXT_QUOTEDSTRING:\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.2.4\r
+                       //   quoted-string   =   [CFWS]\r
+                       //                       DQUOTE *([FWS] qcontent) [FWS] DQUOTE\r
+                       //                       [CFWS]\r
+                       //\r
+                       //   qcontent        =   qtext / quoted-pair\r
+                       switch ($token) {\r
+                       // Quoted pair\r
+                       case ISEMAIL_STRING_BACKSLASH:\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_QUOTEDPAIR;\r
+                               break;\r
+                       // Folding White Space\r
+                       // Inside a quoted string, spaces are allowed as regular characters.\r
+                       // It's only FWS if we include HTAB or CRLF\r
+                       case ISEMAIL_STRING_CR:\r
+                       case ISEMAIL_STRING_HTAB:\r
+                               if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error\r
+\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.2\r
+                               //   Runs of FWS, comment, or CFWS that occur between lexical tokens in a\r
+                               //   structured header field are semantically interpreted as a single\r
+                               //   space character.\r
+\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.4\r
+                               //   the CRLF in any FWS/CFWS that appears within the quoted-string [is]\r
+                               //   semantically "invisible" and therefore not part of the quoted-string\r
+                               $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= ISEMAIL_STRING_SP;\r
+                               $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= ISEMAIL_STRING_SP;\r
+                               $element_len++;\r
+\r
+                               $return_status[]                = ISEMAIL_CFWS_FWS;\r
+                               $context_stack[]                = $context;\r
+                               $context                        = ISEMAIL_CONTEXT_FWS;\r
+                               $token_prior                    = $token;\r
+                               break;\r
+                       // End of quoted string\r
+                       case ISEMAIL_STRING_DQUOTE:\r
+                               $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;\r
+                               $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;\r
+                               $element_len++;\r
+                               $context_prior                  = $context;\r
+                               $context                        = (int) array_pop($context_stack);\r
+                               break;\r
+                       // qtext\r
+                       default:\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.4\r
+                               //   qtext           =   %d33 /             ; Printable US-ASCII\r
+                               //                       %d35-91 /          ;  characters not including\r
+                               //                       %d93-126 /         ;  "\" or the quote character\r
+                               //                       obs-qtext\r
+                               //\r
+                               //   obs-qtext       =   obs-NO-WS-CTL\r
+                               //\r
+                               //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control\r
+                               //                       %d11 /             ;  characters that do not\r
+                               //                       %d12 /             ;  include the carriage\r
+                               //                       %d14-31 /          ;  return, line feed, and\r
+                               //                       %d127              ;  white space characters\r
+                               $ord = ord($token);\r
+\r
+                               if (($ord > 127) || ($ord === 0) || ($ord === 10)) {\r
+                                       $return_status[]        = ISEMAIL_ERR_EXPECTING_QTEXT;  // Fatal error\r
+                               } elseif (($ord < 32) || ($ord === 127))\r
+                                       $return_status[]        = ISEMAIL_DEPREC_QTEXT;\r
+\r
+                               $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;\r
+                               $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;\r
+                               $element_len++;\r
+                       }\r
+\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.4.1\r
+                       //   If the\r
+                       //   string can be represented as a dot-atom (that is, it contains no\r
+                       //   characters other than atext characters or "." surrounded by atext\r
+                       //   characters), then the dot-atom form SHOULD be used and the quoted-\r
+                       //   string form SHOULD NOT be used.\r
+// To do\r
+                       break;\r
+               //-------------------------------------------------------------\r
+               // Quoted pair\r
+               //-------------------------------------------------------------\r
+               case ISEMAIL_CONTEXT_QUOTEDPAIR:\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.2.1\r
+                       //   quoted-pair     =   ("\" (VCHAR / WSP)) / obs-qp\r
+                       //\r
+                       //   VCHAR           =  %d33-126            ; visible (printing) characters\r
+                       //   WSP             =  SP / HTAB           ; white space\r
+                       //\r
+                       //   obs-qp          =   "\" (%d0 / obs-NO-WS-CTL / LF / CR)\r
+                       //\r
+                       //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control\r
+                       //                       %d11 /             ;  characters that do not\r
+                       //                       %d12 /             ;  include the carriage\r
+                       //                       %d14-31 /          ;  return, line feed, and\r
+                       //                       %d127              ;  white space characters\r
+                       //\r
+                       // i.e. obs-qp       =  "\" (%d0-8, %d10-31 / %d127)\r
+                       $ord = ord($token);\r
+\r
+                       if      ($ord > 127)\r
+                                       $return_status[]        = ISEMAIL_ERR_EXPECTING_QPAIR;  // Fatal error\r
+                       elseif  ((($ord < 31) && ($ord !== 9)) || ($ord === 127))       // SP & HTAB are allowed\r
+                                       $return_status[]        = ISEMAIL_DEPREC_QP;\r
+\r
+                       // At this point we know where this qpair occurred so\r
+                       // we could check to see if the character actually\r
+                       // needed to be quoted at all.\r
+                       // http://tools.ietf.org/html/rfc5321#section-4.1.2\r
+                       //   the sending system SHOULD transmit the\r
+                       //   form that uses the minimum quoting possible.\r
+// To do: check whether the character needs to be quoted (escaped) in this context\r
+                       $context_prior  = $context;\r
+                       $context        = (int) array_pop($context_stack);      // End of qpair\r
+                       $token          = ISEMAIL_STRING_BACKSLASH . $token;\r
+\r
+                       switch ($context) {\r
+                       case ISEMAIL_CONTEXT_COMMENT:\r
+                               break;\r
+                       case ISEMAIL_CONTEXT_QUOTEDSTRING:\r
+                               $parsedata[ISEMAIL_COMPONENT_LOCALPART]                 .= $token;\r
+                               $atomlist[ISEMAIL_COMPONENT_LOCALPART][$element_count]  .= $token;\r
+                               $element_len    += 2;   // The maximum sizes specified by RFC 5321 are octet counts, so we must include the backslash\r
+                               break;\r
+                       case ISEMAIL_COMPONENT_LITERAL:\r
+                               $parsedata[ISEMAIL_COMPONENT_DOMAIN]                    .= $token;\r
+                               $atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count]     .= $token;\r
+                               $element_len    += 2;   // The maximum sizes specified by RFC 5321 are octet counts, so we must include the backslash\r
+                               break;\r
+                       default:\r
+                               die("Quoted pair logic invoked in an invalid context: $context");\r
+                       }\r
+\r
+                       break;\r
+               //-------------------------------------------------------------\r
+               // Comment\r
+               //-------------------------------------------------------------\r
+               case ISEMAIL_CONTEXT_COMMENT:\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.2.2\r
+                       //   comment         =   "(" *([FWS] ccontent) [FWS] ")"\r
+                       //\r
+                       //   ccontent        =   ctext / quoted-pair / comment\r
+                       switch ($token) {\r
+                       // Nested comment\r
+                       case ISEMAIL_STRING_OPENPARENTHESIS:\r
+                               // Nested comments are OK\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_COMMENT;\r
+                               break;\r
+                       // End of comment\r
+                       case ISEMAIL_STRING_CLOSEPARENTHESIS:\r
+                               $context_prior          = $context;\r
+                               $context                = (int) array_pop($context_stack);\r
+\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.2\r
+                               //   Runs of FWS, comment, or CFWS that occur between lexical tokens in a\r
+                               //   structured header field are semantically interpreted as a single\r
+                               //   space character.\r
+                               //\r
+                               // is_email() author's note: This *cannot* mean that we must add a\r
+                               // space to the address wherever CFWS appears. This would result in\r
+                               // any addr-spec that had CFWS outside a quoted string being invalid\r
+                               // for RFC 5321.\r
+//                             if (($context === ISEMAIL_COMPONENT_LOCALPART) || ($context === ISEMAIL_COMPONENT_DOMAIN)) {\r
+//                                     $parsedata[$context]                    .= ISEMAIL_STRING_SP;\r
+//                                     $atomlist[$context][$element_count]     .= ISEMAIL_STRING_SP;\r
+//                                     $element_len++;\r
+//                             }\r
+\r
+                               break;\r
+                       // Quoted pair\r
+                       case ISEMAIL_STRING_BACKSLASH:\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_QUOTEDPAIR;\r
+                               break;\r
+                       // Folding White Space\r
+                       case ISEMAIL_STRING_CR:\r
+                       case ISEMAIL_STRING_SP:\r
+                       case ISEMAIL_STRING_HTAB:\r
+                               if (($token === ISEMAIL_STRING_CR) && ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))) {$return_status[] = ISEMAIL_ERR_CR_NO_LF; break;} // Fatal error\r
+\r
+                               $return_status[]        = ISEMAIL_CFWS_FWS;\r
+\r
+                               $context_stack[]        = $context;\r
+                               $context                = ISEMAIL_CONTEXT_FWS;\r
+                               $token_prior            = $token;\r
+                               break;\r
+                       // ctext\r
+                       default:\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.3\r
+                               //   ctext           =   %d33-39 /          ; Printable US-ASCII\r
+                               //                       %d42-91 /          ;  characters not including\r
+                               //                       %d93-126 /         ;  "(", ")", or "\"\r
+                               //                       obs-ctext\r
+                               //\r
+                               //   obs-ctext       =   obs-NO-WS-CTL\r
+                               //\r
+                               //   obs-NO-WS-CTL   =   %d1-8 /            ; US-ASCII control\r
+                               //                       %d11 /             ;  characters that do not\r
+                               //                       %d12 /             ;  include the carriage\r
+                               //                       %d14-31 /          ;  return, line feed, and\r
+                               //                       %d127              ;  white space characters\r
+                               $ord = ord($token);\r
+\r
+                               if (($ord > 127) || ($ord === 0) || ($ord === 10)) {\r
+                                       $return_status[]        = ISEMAIL_ERR_EXPECTING_CTEXT;  // Fatal error\r
+                                       break;\r
+                               } elseif (($ord < 32) || ($ord === 127)) {\r
+                                       $return_status[]        = ISEMAIL_DEPREC_CTEXT;\r
+                               }\r
+                       }\r
+\r
+                       break;\r
+               //-------------------------------------------------------------\r
+               // Folding White Space\r
+               //-------------------------------------------------------------\r
+               case ISEMAIL_CONTEXT_FWS:\r
+                       // http://tools.ietf.org/html/rfc5322#section-3.2.2\r
+                       //   FWS             =   ([*WSP CRLF] 1*WSP) /  obs-FWS\r
+                       //                                          ; Folding white space\r
+\r
+                       // But note the erratum:\r
+                       // http://www.rfc-editor.org/errata_search.php?rfc=5322&eid=1908:\r
+                       //   In the obsolete syntax, any amount of folding white space MAY be\r
+                       //   inserted where the obs-FWS rule is allowed.  This creates the\r
+                       //   possibility of having two consecutive "folds" in a line, and\r
+                       //   therefore the possibility that a line which makes up a folded header\r
+                       //   field could be composed entirely of white space.\r
+                       //\r
+                       //   obs-FWS         =   1*([CRLF] WSP)\r
+                       if ($token_prior === ISEMAIL_STRING_CR) {\r
+                               if ($token === ISEMAIL_STRING_CR) {\r
+                                       $return_status[]        = ISEMAIL_ERR_FWS_CRLF_X2;      // Fatal error\r
+                                       break;\r
+                               }\r
+\r
+                               if (isset($crlf_count)) {\r
+                                       if (++$crlf_count > 1)\r
+                                               $return_status[]        = ISEMAIL_DEPREC_FWS;   // Multiple folds = obsolete FWS\r
+                               } else $crlf_count = 1;\r
+                       }\r
+\r
+                       switch ($token) {\r
+                       case ISEMAIL_STRING_CR:\r
+                               if ((++$i === $raw_length) || ($email[$i] !== ISEMAIL_STRING_LF))\r
+                                       $return_status[]        = ISEMAIL_ERR_CR_NO_LF; // Fatal error\r
+\r
+                               break;\r
+                       case ISEMAIL_STRING_SP:\r
+                       case ISEMAIL_STRING_HTAB:\r
+                               break;\r
+                       default:\r
+                               if ($token_prior === ISEMAIL_STRING_CR) {\r
+                                       $return_status[]        = ISEMAIL_ERR_FWS_CRLF_END;     // Fatal error\r
+                                       break;\r
+                               }\r
+\r
+                               if (isset($crlf_count)) unset($crlf_count);\r
+\r
+                               $context_prior                                  = $context;\r
+                               $context                                        = (int) array_pop($context_stack);      // End of FWS\r
+\r
+                               // http://tools.ietf.org/html/rfc5322#section-3.2.2\r
+                               //   Runs of FWS, comment, or CFWS that occur between lexical tokens in a\r
+                               //   structured header field are semantically interpreted as a single\r
+                               //   space character.\r
+                               //\r
+                               // is_email() author's note: This *cannot* mean that we must add a\r
+                               // space to the address wherever CFWS appears. This would result in\r
+                               // any addr-spec that had CFWS outside a quoted string being invalid\r
+                               // for RFC 5321.\r
+//                             if (($context === ISEMAIL_COMPONENT_LOCALPART) || ($context === ISEMAIL_COMPONENT_DOMAIN)) {\r
+//                                     $parsedata[$context]                    .= ISEMAIL_STRING_SP;\r
+//                                     $atomlist[$context][$element_count]     .= ISEMAIL_STRING_SP;\r
+//                                     $element_len++;\r
+//                             }\r
+\r
+                               $i--;   // Look at this token again in the parent context\r
+                       }\r
+\r
+                       $token_prior = $token;\r
+                       break;\r
+               //-------------------------------------------------------------\r
+               // A context we aren't expecting\r
+               //-------------------------------------------------------------\r
+               default:\r
+                       die("Unknown context: $context");\r
+               }\r
+\r
+//-echo "<td>$context|",(($end_or_die) ? 'true' : 'false'),"|$token|" . max($return_status) . "</td></tr>"; // debug\r
+               if ((int) max($return_status) > ISEMAIL_RFC5322) break; // No point going on if we've got a fatal error\r
+       }\r
+\r
+       // Some simple final tests\r
+       if ((int) max($return_status) < ISEMAIL_RFC5322) {\r
+               if      ($context       === ISEMAIL_CONTEXT_QUOTEDSTRING)       $return_status[]        = ISEMAIL_ERR_UNCLOSEDQUOTEDSTR;        // Fatal error\r
+               elseif  ($context       === ISEMAIL_CONTEXT_QUOTEDPAIR)         $return_status[]        = ISEMAIL_ERR_BACKSLASHEND;             // Fatal error\r
+               elseif  ($context       === ISEMAIL_CONTEXT_COMMENT)            $return_status[]        = ISEMAIL_ERR_UNCLOSEDCOMMENT;          // Fatal error\r
+               elseif  ($context       === ISEMAIL_COMPONENT_LITERAL)          $return_status[]        = ISEMAIL_ERR_UNCLOSEDDOMLIT;           // Fatal error\r
+               elseif  ($token         === ISEMAIL_STRING_CR)                  $return_status[]        = ISEMAIL_ERR_FWS_CRLF_END;             // Fatal error\r
+               elseif  ($parsedata[ISEMAIL_COMPONENT_DOMAIN]   === '')         $return_status[]        = ISEMAIL_ERR_NODOMAIN;                 // Fatal error\r
+               elseif  ($element_len   === 0)                                  $return_status[]        = ISEMAIL_ERR_DOT_END;                  // Fatal error\r
+               elseif  ($hyphen_flag)                                          $return_status[]        = ISEMAIL_ERR_DOMAINHYPHENEND;          // Fatal error\r
+               // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.2\r
+               //   The maximum total length of a domain name or number is 255 octets.\r
+               elseif  (strlen($parsedata[ISEMAIL_COMPONENT_DOMAIN]) > 255)\r
+                                                                               $return_status[]        = ISEMAIL_RFC5322_DOMAIN_TOOLONG;\r
+               // http://tools.ietf.org/html/rfc5321#section-4.1.2\r
+               //   Forward-path   = Path\r
+               //\r
+               //   Path           = "<" [ A-d-l ":" ] Mailbox ">"\r
+               //\r
+               // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.3\r
+               //   The maximum total length of a reverse-path or forward-path is 256\r
+               //   octets (including the punctuation and element separators).\r
+               //\r
+               // Thus, even without (obsolete) routing information, the Mailbox can\r
+               // only be 254 characters long. This is confirmed by this verified\r
+               // erratum to RFC 3696:\r
+               //\r
+               // http://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690\r
+               //   However, there is a restriction in RFC 2821 on the length of an\r
+               //   address in MAIL and RCPT commands of 254 characters.  Since addresses\r
+               //   that do not fit in those fields are not normally useful, the upper\r
+               //   limit on address lengths should normally be considered to be 254.\r
+               elseif  (strlen($parsedata[ISEMAIL_COMPONENT_LOCALPART] . ISEMAIL_STRING_AT . $parsedata[ISEMAIL_COMPONENT_DOMAIN]) > 254)\r
+                                                                               $return_status[]        = ISEMAIL_RFC5322_TOOLONG;\r
+               // http://tools.ietf.org/html/rfc1035#section-2.3.4\r
+               // labels          63 octets or less\r
+               elseif ($element_len > 63)                                      $return_status[]        = ISEMAIL_RFC5322_LABEL_TOOLONG;\r
+       }\r
+\r
+       // Check DNS?\r
+       $dns_checked = false;\r
+\r
+       if ($checkDNS && ((int) max($return_status) < ISEMAIL_DNSWARN) && function_exists('dns_get_record')) {\r
+               // http://tools.ietf.org/html/rfc5321#section-2.3.5\r
+               //   Names that can\r
+               //   be resolved to MX RRs or address (i.e., A or AAAA) RRs (as discussed\r
+               //   in Section 5) are permitted, as are CNAME RRs whose targets can be\r
+               //   resolved, in turn, to MX or address RRs.\r
+               //\r
+               // http://tools.ietf.org/html/rfc5321#section-5.1\r
+               //   The lookup first attempts to locate an MX record associated with the\r
+               //   name.  If a CNAME record is found, the resulting name is processed as\r
+               //   if it were the initial name. ... If an empty list of MXs is returned,\r
+               //   the address is treated as if it was associated with an implicit MX\r
+               //   RR, with a preference of 0, pointing to that host.\r
+               //\r
+               // is_email() author's note: We will regard the existence of a CNAME to be\r
+               // sufficient evidence of the domain's existence. For performance reasons\r
+               // we will not repeat the DNS lookup for the CNAME's target, but we will\r
+               // raise a warning because we didn't immediately find an MX record.\r
+               if ($element_count === 0) $parsedata[ISEMAIL_COMPONENT_DOMAIN] .= '.';          // Checking TLD DNS seems to work only if you explicitly check from the root\r
+\r
+               $result = @dns_get_record($parsedata[ISEMAIL_COMPONENT_DOMAIN], DNS_MX);        // Not using checkdnsrr because of a suspected bug in PHP 5.3 (http://bugs.php.net/bug.php?id=51844)\r
+\r
+               if ((is_bool($result) && !(bool) $result))\r
+                       $return_status[] = ISEMAIL_DNSWARN_NO_RECORD;                   // Domain can't be found in DNS\r
+               else {\r
+                       if (count($result) === 0) {\r
+                               $return_status[]        = ISEMAIL_DNSWARN_NO_MX_RECORD;         // MX-record for domain can't be found\r
+                               $result                 = @dns_get_record($parsedata[ISEMAIL_COMPONENT_DOMAIN], DNS_A + DNS_CNAME);\r
+\r
+                               if (count($result) === 0)\r
+                                       $return_status[] = ISEMAIL_DNSWARN_NO_RECORD;           // No usable records for the domain can be found\r
+                       } else $dns_checked = true;\r
+               }\r
+       }\r
+\r
+       // Check for TLD addresses\r
+       // -----------------------\r
+       // TLD addresses are specifically allowed in RFC 5321 but they are\r
+       // unusual to say the least. We will allocate a separate\r
+       // status to these addresses on the basis that they are more likely\r
+       // to be typos than genuine addresses (unless we've already\r
+       // established that the domain does have an MX record)\r
+       //\r
+       // http://tools.ietf.org/html/rfc5321#section-2.3.5\r
+       //   In the case\r
+       //   of a top-level domain used by itself in an email address, a single\r
+       //   string is used without any dots.  This makes the requirement,\r
+       //   described in more detail below, that only fully-qualified domain\r
+       //   names appear in SMTP transactions on the public Internet,\r
+       //   particularly important where top-level domains are involved.\r
+       //\r
+       // TLD format\r
+       // ----------\r
+       // The format of TLDs has changed a number of times. The standards\r
+       // used by IANA have been largely ignored by ICANN, leading to\r
+       // confusion over the standards being followed. These are not defined\r
+       // anywhere, except as a general component of a DNS host name (a label).\r
+       // However, this could potentially lead to 123.123.123.123 being a\r
+       // valid DNS name (rather than an IP address) and thereby creating\r
+       // an ambiguity. The most authoritative statement on TLD formats that\r
+       // the author can find is in a (rejected!) erratum to RFC 1123\r
+       // submitted by John Klensin, the author of RFC 5321:\r
+       //\r
+       // http://www.rfc-editor.org/errata_search.php?rfc=1123&eid=1353\r
+       //   However, a valid host name can never have the dotted-decimal\r
+       //   form #.#.#.#, since this change does not permit the highest-level\r
+       //   component label to start with a digit even if it is not all-numeric.\r
+       if (!$dns_checked && ((int) max($return_status) < ISEMAIL_DNSWARN)) {\r
+               if      ($element_count === 0)  $return_status[]        = ISEMAIL_RFC5321_TLD;\r
+\r
+               if      (is_numeric($atomlist[ISEMAIL_COMPONENT_DOMAIN][$element_count][0]))\r
+                                               $return_status[]        = ISEMAIL_RFC5321_TLDNUMERIC;\r
+       }\r
+\r
+       $return_status          = array_unique($return_status);\r
+       $final_status           = (int) max($return_status);\r
+\r
+       if (count($return_status) !== 1) array_shift($return_status); // remove redundant ISEMAIL_VALID\r
+\r
+       $parsedata['status']    = $return_status;\r
+\r
+       if ($final_status < $threshold) $final_status = ISEMAIL_VALID;\r
+\r
+       return ($diagnose) ? $final_status : ($final_status < ISEMAIL_THRESHOLD);\r
+}\r
+?>\r
diff --git a/www/plugins/verifier/inc/verifier.php b/www/plugins/verifier/inc/verifier.php
new file mode 100644 (file)
index 0000000..7c11864
--- /dev/null
@@ -0,0 +1,106 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Fonction de base de l'API de vérification.
+ * @param mixed $valeur La valeur a verifier.
+ * @param string $type Le type de verification a appliquer.
+ * @param array $options Un eventuel tableau d'options suivant le type.
+ * @param array $valeur_normalisee
+ *             Si des options de verification modifient la valeur entrante (normalisent),
+ *             alors la valeur modifie sera stockee dans cette variable.
+ * @return string Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function inc_verifier_dist($valeur, $type, $options=null, &$valeur_normalisee=null){
+
+       // On vérifie que les options sont bien un tableau
+       if (!is_array($options))
+               $options = array();
+
+       // Si la valeur est vide, il n'y a rien a verifier donc c'est bon
+       if (is_null($valeur) or (is_string($valeur) and $valeur == '')) return '';
+       // Si c'est une date avec horaire c'est un tableau
+       if (is_array($valeur) and isset($valeur['date']) and $valeur[date] == '') return '';
+
+       // On cherche si une fonction correspondant au type existe
+       if ($verifier = charger_fonction($type, 'verifier',true)){
+               $erreur = $verifier($valeur, $options, $valeur_normalisee);
+       }
+
+       // On passe le tout dans le pipeline du meme nom
+       $erreur = pipeline(
+               'verifier',
+               array(
+                       'args' => array(
+                               'valeur' => $valeur,
+                               'type' => $type,
+                               'options' => $options,
+                       ),
+                       'data' => $erreur
+               )
+       );
+
+       return $erreur;
+}
+
+/**
+ * Liste toutes les vérifications possibles
+ * 
+ * @param string $repertoire
+ *             Dans quel repertoire chercher les yaml.
+ * 
+ * @return Retourne un tableau listant les vérifications et leurs options
+ */
+function verifier_lister_disponibles($repertoire='verifier'){
+       static $verifications = array();
+
+       if (!isset($verifications[$repertoire])) {
+               $verifications[$repertoire] = array();
+               $liste = find_all_in_path("$repertoire/", '.+[.]yaml$');
+
+               if (count($liste)){
+                       foreach ($liste as $fichier=>$chemin){
+                               $type = preg_replace(',[.]yaml$,i', '', $fichier);
+                               $dossier = str_replace($fichier, '', $chemin);
+                               // On ne garde que les vérifications qui ont bien la fonction !
+                               if (charger_fonction($type, $repertoire, true)
+                                       and (
+                                               is_array($verif = verifier_charger_infos($type, $repertoire))
+                                       )
+                               ) {
+                                       $verifications[$repertoire][$type] = $verif;
+                               }
+                       }
+               }
+       }
+
+       return $verifications[$repertoire];
+}
+
+
+/**
+ * Charger les informations contenues dans le yaml d'une vérification
+ *
+ * @param string $type_verif
+ *             Le type de la vérification
+ * 
+ * @param string $repertoire
+ *             Dans quel repertoire chercher les yaml.
+ * 
+ * @return array Un tableau contenant le YAML décodé
+ */
+function verifier_charger_infos($type_verif, $repertoire='verifier'){
+       include_spip('inc/yaml');
+       $fichier = find_in_path("$repertoire/$type_verif.yaml");
+       $verif = yaml_decode_file($fichier);
+       if (is_array($verif)){
+               $verif['titre']       = (isset($verif['titre'])       and $verif['titre'])       ? _T_ou_typo($verif['titre']) : $type_verif;
+               $verif['description'] = (isset($verif['description']) and $verif['description']) ? _T_ou_typo($verif['description']) : '';
+               $verif['icone']       = (isset($verif['icone'])       and $verif['icone'])       ? _T_ou_typo($verif['icone']) : '';
+       }
+       return $verif;
+}
+
+?>
diff --git a/www/plugins/verifier/lang/paquet-verifier.xml b/www/plugins/verifier/lang/paquet-verifier.xml
new file mode 100644 (file)
index 0000000..0e789a8
--- /dev/null
@@ -0,0 +1,18 @@
+<traduction module="paquet-verifier" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/verifier/lang/" reference="fr">
+       <langue code="de" url="http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=de">
+               <traducteur nom="klaus++" lien="http://trad.spip.net/auteur/klaus" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=ru">
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/verifier/lang/paquet-verifier_de.php b/www/plugins/verifier/lang/paquet-verifier_de.php
new file mode 100644 (file)
index 0000000..9bcbc7b
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // V
+       'verifier_description' => 'Stellt die Funktion<code>verifier($wert, $typ, $optionen, $normalisierter_wert)</code>bereit, mit der ein Werts auf Gültigkeit geprüft werden kann.',
+       'verifier_nom' => 'API Wertprüfung',
+       'verifier_slogan' => 'API zur Prüfung von Werten'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/paquet-verifier_en.php b/www/plugins/verifier/lang/paquet-verifier_en.php
new file mode 100644 (file)
index 0000000..84b56a3
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // V
+       'verifier_description' => 'Provides a unique function <code>verifier($value, $type, $options,&$valeur_normalisee)</code> to test the validity of a value.',
+       'verifier_nom' => 'Control API',
+       'verifier_slogan' => 'A generic API to control a value'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/paquet-verifier_es.php b/www/plugins/verifier/lang/paquet-verifier_es.php
new file mode 100644 (file)
index 0000000..d2983be
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // V
+       'verifier_description' => 'Proporciona una función única <code>verifier($valeur, $type, $options, &$valeur_normalisee)</code> para probar la validez de un valor',
+       'verifier_nom' => 'API de verificación',
+       'verifier_slogan' => 'Una API genérica para verificar un valor'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/paquet-verifier_fr.php b/www/plugins/verifier/lang/paquet-verifier_fr.php
new file mode 100644 (file)
index 0000000..e9d7243
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/verifier/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // V
+       'verifier_description' => 'Fournit une fonction unique <code>verifier($valeur, $type, $options, &$valeur_normalisee)</code> permettant de tester la validité d\'une valeur.',
+       'verifier_nom' => 'API de vérification',
+       'verifier_slogan' => 'Une API générique pour vérifier une valeur'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/paquet-verifier_ru.php b/www/plugins/verifier/lang/paquet-verifier_ru.php
new file mode 100644 (file)
index 0000000..b43eab8
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // V
+       'verifier_description' => 'Позволяет использовать функцию <code>verifier($valeur, $type, $options, &$valeur_normalisee)</code> для проверки данных на соответствие заданному формату.',
+       'verifier_nom' => 'API для валидации данных (verifier)',
+       'verifier_slogan' => 'Плагин обеспечивает API для валидации данных. Необходим для работы многих плагинов.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/paquet-verifier_sk.php b/www/plugins/verifier/lang/paquet-verifier_sk.php
new file mode 100644 (file)
index 0000000..17d95e4
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-verifier?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // V
+       'verifier_description' => 'Poskytuje jedinečnú funkciu <code>verifier($hodnota, $typ, $podmienky),</code> ktorá umožňuje otestovať platnosť hodnoty.',
+       'verifier_nom' => 'Aplikácia na overenie',
+       'verifier_slogan' => 'Spoločná aplikácia na overenie hodnoty'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier.xml b/www/plugins/verifier/lang/verifier.xml
new file mode 100644 (file)
index 0000000..81f2aac
--- /dev/null
@@ -0,0 +1,36 @@
+<traduction module="verifier" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/verifier/lang/" reference="fr">
+       <langue code="ca" />
+       <langue code="de" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=de">
+               <traducteur nom="klaus++" lien="http://trad.spip.net/auteur/klaus" />
+       </langue>
+       <langue code="en" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=en">
+               <traducteur nom="drBouvierLeduc" lien="http://trad.spip.net/auteur/drbouvierleduc" />
+               <traducteur nom="George" lien="http://trad.spip.net/auteur/جورج-قندلفت" />
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+               <traducteur nom="Mark" lien="http://trad.spip.net/auteur/mark" />
+               <traducteur nom="RastaPopoulos" lien="http://trad.spip.net/auteur/rastapopoulos" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="fr_tu" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=fr_tu">
+               <traducteur nom="beatnick" lien="http://trad.spip.net/auteur/beatnick" />
+               <traducteur nom="stefdn" lien="http://trad.spip.net/auteur/stefdn" />
+       </langue>
+       <langue code="it" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=it">
+               <traducteur nom="Cap" lien="http://trad.spip.net/auteur/cap" />
+       </langue>
+       <langue code="pt_br" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=pt_br">
+               <traducteur nom="Ricardo Porto" lien="http://trad.spip.net/auteur/ricardo-porto" />
+       </langue>
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=ru">
+               <traducteur nom="nazar" lien="http://trad.spip.net/auteur/nazar" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/verifier?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/verifier/lang/verifier_ca.php b/www/plugins/verifier/lang/verifier_ca.php
new file mode 100644 (file)
index 0000000..7628f12
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=ca
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Ce code postal est incorrect.', # NEW
+       'erreur_comparaison_egal' => 'La valeur doit être égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_egal_type' => 'La valeur doit être égale et de même type que le champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand' => 'La valeur doit être supérieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand_egal' => 'La valeur doit être supérieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit' => 'La valeur doit être inférieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit_egal' => 'La valeur doit être inférieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_couleur' => 'Le code couleur n\'est pas valide.', # NEW
+       'erreur_date' => 'El format de la data no és correcte.',
+       'erreur_date_format' => 'Le format de la date n\'est pas accepté.', # NEW
+       'erreur_decimal' => 'La valeur doit être un nombre décimal.', # NEW
+       'erreur_decimal_nb_decimales' => 'Le nombre ne doit pas avoir plus de @nb_decimales@ chiffres après la virgule.', # NEW
+       'erreur_email' => 'L\'adreça de correu electrònic <em>@email@</em> no té un format vàlid.',
+       'erreur_email_nondispo' => 'L\'adreça de correu electrònic <em>@email@</em> ja s\'utilitza.',
+       'erreur_entier' => 'El valor ha de ser un nombre enter.',
+       'erreur_entier_entre' => 'El valor ha d\'estar comprès entre @min@ i @max@.',
+       'erreur_entier_max' => 'El valor ha de ser inferior a @max@.',
+       'erreur_entier_min' => 'El valor ha de ser superior a @min@.',
+       'erreur_heure' => 'L’horaire indiquée n’existe pas.', # NEW
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.', # NEW
+       'erreur_id_document' => 'Aquest identificador de document no és vàlid.',
+       'erreur_inconnue_generique' => 'Le format n\'est pas correct.', # NEW
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)', # NEW
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # NEW
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # NEW
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).', # NEW
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).', # NEW
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.', # NEW
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.', # NEW
+       'erreur_numerique' => 'El format del número no és vàlid.',
+       'erreur_regex' => 'El format de la cadena no és vàlida.',
+       'erreur_siren' => 'Número SIREN no vàlid.',
+       'erreur_siret' => 'Número SIRET no vàlid.',
+       'erreur_taille_egal' => 'El valor ha de tenir exactament @egal@ caràcters.', # MODIF
+       'erreur_taille_entre' => 'El valor ha d\'estar comprès entre @min@ i @max@ caràcters.', # MODIF
+       'erreur_taille_max' => 'El valor ha de comprendre com a molt @max@ caràcters.', # MODIF
+       'erreur_taille_min' => 'El valor ha de tenir com a mínim @min@ caràcters.', # MODIF
+       'erreur_telephone' => 'El número no és vàlid.',
+       'erreur_url' => 'L\'adreça no és vàlida.', # MODIF
+       'erreur_url_protocole' => 'L\'adresse saisie <em>(@url@)</em> doit commencer par @protocole@', # NEW
+       'erreur_url_protocole_exact' => 'L\'adresse saisie <em>(@url@)</em> ne commence pas par un protocole valide (http:// par exemple)', # NEW
+
+       // N
+       'normaliser_option_date' => 'Normaliser la date ?', # NEW
+       'normaliser_option_date_aucune' => 'Non', # NEW
+       'normaliser_option_date_en_datetime' => 'Au format «Datetime» (pour SQL)', # NEW
+
+       // O
+       'option_couleur_normaliser_label' => 'Normaliser le code couleur ?', # NEW
+       'option_couleur_type_hexa' => 'Code couleur au format héxadécimal', # NEW
+       'option_couleur_type_label' => 'Type de vérification à effectuer', # NEW
+       'option_decimal_nb_decimales_label' => 'Nombre de décimales après la virgule', # NEW
+       'option_email_disponible_label' => 'Adreça disponible',
+       'option_email_disponible_label_case' => 'Verificar que l\'adreça no l\'utilitzi ja un altre usuari',
+       'option_email_mode_5322' => 'Verificació la més compatible amb els estàndards disponibles ',
+       'option_email_mode_label' => 'Mitjà de verificació dels correus electrònics',
+       'option_email_mode_normal' => 'Verificació normal d\'SPIP',
+       'option_email_mode_strict' => 'Verificació menys permissiva',
+       'option_entier_max_label' => 'Valor màxim',
+       'option_entier_min_label' => 'Valor mínim',
+       'option_regex_modele_label' => 'El valor ha de coincidir amb la màscara de la següent',
+       'option_siren_siret_mode_label' => 'Què voleu verificar?',
+       'option_siren_siret_mode_siren' => 'el SIREN',
+       'option_siren_siret_mode_siret' => 'el SIRET',
+       'option_taille_max_label' => 'Mida màxima',
+       'option_taille_min_label' => 'Mida mínima',
+       'option_url_mode_complet' => 'Vérification complète de l\'url', # NEW
+       'option_url_mode_label' => 'Mode de vérification des urls', # NEW
+       'option_url_mode_php_filter' => 'Vérification complète de l\'url via le filtre FILTER_VALIDATE_URL de php', # NEW
+       'option_url_mode_protocole_seul' => 'Vérification uniquement de la présence d\'un protocole', # NEW
+       'option_url_protocole_label' => 'Nom du protocole à vérifier', # NEW
+       'option_url_type_protocole_exact' => 'Saisir un protocole ci-dessous :', # NEW
+       'option_url_type_protocole_ftp' => 'Protocoles ftp : ftp ou sftp', # NEW
+       'option_url_type_protocole_label' => 'Type de protocole à vérifier', # NEW
+       'option_url_type_protocole_mail' => 'Protocoles mail : imap, pop3 ou smtp', # NEW
+       'option_url_type_protocole_tous' => 'Tous protocoles acceptés', # NEW
+       'option_url_type_protocole_web' => 'Protocoles web : http ou https', # NEW
+
+       // T
+       'type_couleur' => 'Couleur', # NEW
+       'type_couleur_description' => 'Vérifie que la valeur est un code couleur.', # NEW
+       'type_date' => 'Data',
+       'type_date_description' => 'Verifica que el valor és una data en format JJ/MM/AAAA. El separador és lliure (".", "/", etc.).',
+       'type_decimal' => 'Nombre décimal', # NEW
+       'type_decimal_description' => 'Vérifie que la valeur est un nombre décimal, avec la possibilité de restreindre entre deux valeurs et de préciser le nombre de décimales après la virgule.', # NEW
+       'type_email' => 'Adreça de correu electrònic',
+       'type_email_description' => 'Verifica que el format de l\'adreça de correu electrònica sigui correcte.',
+       'type_email_disponible' => 'Disponibilitat d\'una adreça de correu electrònic',
+       'type_email_disponible_description' => 'Verifica que l\'adreça de correu electrònica no sigui utilitzada ja per un altre usuari del sistema.',
+       'type_entier' => 'Número enter', # MODIF
+       'type_entier_description' => 'Verifica que el valor sigui un número enter, amb la possibilitat de restringir entre dos valors.',
+       'type_regex' => 'Expressió regular ',
+       'type_regex_description' => 'Verifica que el valor correspon a la màscara demanada. Per l\'ús de màscares, aneu a <a href="http://fr2.php.net/manual/fr/reference.pcre.pattern.syntax.php">l\'ajuda en línia de PHP</a>.',
+       'type_siren_siret' => 'SIREN o SIRET',
+       'type_siren_siret_description' => 'Verifica queel valor és un número vàlid del <a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des ENtreprises</a> francès.',
+       'type_taille' => 'Mida',
+       'type_taille_description' => 'Verifica que la mida del valor correspon al mínim i/o al màxim demanat.',
+       'type_telephone' => 'Número de telèfon',
+       'type_telephone_description' => 'Verifica que el número de telèfon correspon a un esquema reconegut.',
+       'type_url' => 'URL', # NEW
+       'type_url_description' => 'Vérifie que l\'url correspond à un schéma reconnu.' # NEW
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_de.php b/www/plugins/verifier/lang/verifier_de.php
new file mode 100644 (file)
index 0000000..dee32b4
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Ungültige Postleitzahl',
+       'erreur_comparaison_egal' => 'La valeur doit être égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_egal_type' => 'La valeur doit être égale et de même type que le champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand' => 'La valeur doit être supérieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand_egal' => 'La valeur doit être supérieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit' => 'La valeur doit être inférieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit_egal' => 'La valeur doit être inférieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_couleur' => 'Le code couleur n\'est pas valide.', # NEW
+       'erreur_date' => 'Fromat des Datums ungültig',
+       'erreur_date_format' => 'Dieses Datumsformat wird nicht akzeptiert',
+       'erreur_decimal' => 'Der Wert muß einen Dezimalzahl sein',
+       'erreur_decimal_nb_decimales' => 'Die Zahl darf nicht mehr als @nb_decimales@ Nachkommastellen haben.',
+       'erreur_email' => 'Die Mailadresse  <em>@email@</em> hat einen Syntaxfehler.',
+       'erreur_email_nondispo' => 'Die Mailadresse <em>@email@</em>  wird bereits verwendet.',
+       'erreur_entier' => 'Der Wert muß eine ganze Zahl sein.',
+       'erreur_entier_entre' => 'Der Wert muß zwischen  @min@ und @max@ liegen.',
+       'erreur_entier_max' => 'Der Wert muß kleiner als @max@ sein.',
+       'erreur_entier_min' => 'Der Wert muß größer als @min@ sein.',
+       'erreur_heure' => 'L’horaire indiquée n’existe pas.', # NEW
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.', # NEW
+       'erreur_id_document' => 'Diese Dokumenten-ID ist ungültig',
+       'erreur_inconnue_generique' => 'Le format n\'est pas correct.', # NEW
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)', # NEW
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # NEW
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # NEW
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).', # NEW
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).', # NEW
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.', # NEW
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.', # NEW
+       'erreur_numerique' => 'Zahlenformat ungültig',
+       'erreur_regex' => 'Zeichenkettenformat ungültig',
+       'erreur_siren' => 'SIREN Nummer ungültig',
+       'erreur_siret' => 'SIRET Nummer ungültig',
+       'erreur_taille_egal' => 'Der Wert muß exakt @egal@ Zeichen haben.', # MODIF
+       'erreur_taille_entre' => 'Der Wert muß zwischen @min@ und @max@ Zeichen haben.', # MODIF
+       'erreur_taille_max' => 'Der Wert darf maximal @max@ Zeichen haben.', # MODIF
+       'erreur_taille_min' => 'Der Wert muß mindestens @min@ Zeichen haben.', # MODIF
+       'erreur_telephone' => 'Zahl ungültig',
+       'erreur_url' => 'Die Adresse <em>@url@</em> ist ungültig.',
+       'erreur_url_protocole' => 'Die eingegebene Adresse <em>(@url@)</em> muß mit @protocole@ beginnen.',
+       'erreur_url_protocole_exact' => 'Die eingegebene Adresse <em>(@url@)</em> beginnt nicht mit einem gültigen Protokoll (zum Beispiel http:// ).',
+
+       // N
+       'normaliser_option_date' => 'Normaliser la date ?', # NEW
+       'normaliser_option_date_aucune' => 'Non', # NEW
+       'normaliser_option_date_en_datetime' => 'Au format «Datetime» (pour SQL)', # NEW
+
+       // O
+       'option_couleur_normaliser_label' => 'Normaliser le code couleur ?', # NEW
+       'option_couleur_type_hexa' => 'Code couleur au format héxadécimal', # NEW
+       'option_couleur_type_label' => 'Type de vérification à effectuer', # NEW
+       'option_decimal_nb_decimales_label' => 'Dezimalstellen nach dem Komma',
+       'option_email_disponible_label' => 'Adresse verfügbar',
+       'option_email_disponible_label_case' => 'Überprüfen, ob die Adresse bereits verwendet wird.',
+       'option_email_mode_5322' => 'Streng standardgemäße Überprüfung',
+       'option_email_mode_label' => 'Art der Mailprüfung',
+       'option_email_mode_normal' => 'Normale SPIP-Prüfung',
+       'option_email_mode_strict' => 'Strengere Prüfung',
+       'option_entier_max_label' => 'Maximalwert',
+       'option_entier_min_label' => 'Minimalwert',
+       'option_regex_modele_label' => 'Der Wert muß mit der folgenden Maske übereinstimmen.',
+       'option_siren_siret_mode_label' => 'Was möchten sie überprüfen?',
+       'option_siren_siret_mode_siren' => 'SIREN (frz. Unternehmens ID)',
+       'option_siren_siret_mode_siret' => 'SIRET (frz. geographische Unternehmens ID)',
+       'option_taille_max_label' => 'Maximalgröße',
+       'option_taille_min_label' => 'Minimalgröße',
+       'option_url_mode_complet' => 'Vollständige Prüfung des URL',
+       'option_url_mode_label' => 'Art der URL-Prüfung',
+       'option_url_mode_php_filter' => 'Vollständige Prüfung des URL mit dem PHP-Filter FILTER_VALIDATE_URL',
+       'option_url_mode_protocole_seul' => 'Nur die Angabe eines Protokolls prüfen',
+       'option_url_protocole_label' => 'Names des überprüften Protokolls',
+       'option_url_type_protocole_exact' => 'Geben Sie hier ein Protokoll an:',
+       'option_url_type_protocole_ftp' => 'FTP-Protokolle: ftp oder sftp',
+       'option_url_type_protocole_label' => 'Typ des erforderlichen Protokolls',
+       'option_url_type_protocole_mail' => 'Mail-Protokolle: imap, pop3 oder smtp',
+       'option_url_type_protocole_tous' => 'Alle Protokolle werden akzeptiert',
+       'option_url_type_protocole_web' => 'Web-Protokolle: http oder https',
+
+       // T
+       'type_couleur' => 'Couleur', # NEW
+       'type_couleur_description' => 'Vérifie que la valeur est un code couleur.', # NEW
+       'type_date' => 'Datum',
+       'type_date_description' => 'Überprüft den Wert auf das Datumsformat  JJ/MM/AAAA. Verschiedene Trenner sind möglich (".", "/", etc).',
+       'type_decimal' => 'Dezimalzahl',
+       'type_decimal_description' => 'Prüft ob der Wert eine Dezimalzahl ist und ermöglicht, einen Wertebereich und die Anzahl der Nachkommastellen festzulegen.',
+       'type_email' => 'Mailadresse',
+       'type_email_description' => 'Überprüft das Format der Mailadresse',
+       'type_email_disponible' => 'Verfügbarkeit einer Mailadresse',
+       'type_email_disponible_description' => 'Überprüft ob die Mailadresse bereits von einem anderen Nutzer des System verwendet wird.',
+       'type_entier' => 'Ganzzahl',
+       'type_entier_description' => 'Überprüft ob der Wert eine Ganzzahl ist; bietet die Möglichkeit, einen Bereich zwischen zwei Zahlen anzugeben.',
+       'type_regex' => 'Regulärer Ausdruck',
+       'type_regex_description' => 'Prüft ob der Wert mit der vorgegebenen Maske übereinstimmt. Zur Verwendung der Masken <a href="http://www.php.net/manual/de/reference.pcre.pattern.syntax.php">lesen sie bitte die PHP Dokumentation</a>.',
+       'type_siren_siret' => 'SIREN oder SIRET',
+       'type_siren_siret_description' => 'Prüft ob der Wert eine gültige Nummer des <a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des Entreprises</a> ist.',
+       'type_taille' => 'Größe',
+       'type_taille_description' => 'Überprüft ob der Wert zum geforderten Minimal- oder Maximalwert paßt.',
+       'type_telephone' => 'Telefonnummer',
+       'type_telephone_description' => 'Prüft ob die Telefonnummer einem bekannten Schema entspricht.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Prüft ob der URL einem anerkannten Schema entspricht.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_en.php b/www/plugins/verifier/lang/verifier_en.php
new file mode 100644 (file)
index 0000000..ded9950
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'This post code is invalid.',
+       'erreur_comparaison_egal' => 'The value must be equal to the field "@nom_champ@"',
+       'erreur_comparaison_egal_type' => 'The value must be equal and the same type as the field "@nom_champ@"',
+       'erreur_comparaison_grand' => 'The value must be greater than the field "@nom_champ@"',
+       'erreur_comparaison_grand_egal' => 'The value must be greater than or equal to the field "@nom_champ@"',
+       'erreur_comparaison_petit' => 'The value must be lower than the field "@nom_champ@"',
+       'erreur_comparaison_petit_egal' => 'The value must be lower than or equal to the field "@nom_champ@"',
+       'erreur_couleur' => 'The color code is invalid.',
+       'erreur_date' => 'The date is invalid.',
+       'erreur_date_format' => 'The date format is invalid.',
+       'erreur_decimal' => 'The value must be a decimal number.',
+       'erreur_decimal_nb_decimales' => 'The number must have more than @nb_decimales@ digits after the decimal point.',
+       'erreur_email' => 'The email address <em>@email@</em> is not correctly formatted.',
+       'erreur_email_nondispo' => 'The email address <em>@email@</em> has already been used.',
+       'erreur_entier' => 'The value must be an integer.',
+       'erreur_entier_entre' => 'The value must be between @min@ and @max@.',
+       'erreur_entier_max' => 'The value must be less than @max@.',
+       'erreur_entier_min' => 'The value must be greater than @min@.',
+       'erreur_heure' => 'The timetable specified does not exist.',
+       'erreur_heure_format' => 'The time format is not valid.',
+       'erreur_id_document' => 'This document identifier is not valid.',
+       'erreur_inconnue_generique' => 'The format is invalid.',
+       'erreur_isbn' => 'the ISBN number is not valid (ex: 978-2-1234-5680-3 or 2-1234-5680-X)',
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # a 13 digits ISBN number must not end with an X.
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # the first segment must be 978 or 979.
+       'erreur_isbn_nb_caracteres' => 'the ISBN number must have 10 ou 13 caracters, not including the hyphens (curently @nb@).',
+       'erreur_isbn_nb_segments' => 'the ISBN number must have 4 or 5 segments (curently @nb@).',
+       'erreur_isbn_segment' => 'the segment "@segment@" has @nb@ exceeding caracter(s).',
+       'erreur_isbn_segment_lettre' => 'the segment "@segment@" must not have any letter.',
+       'erreur_numerique' => 'The number format is invalid.',
+       'erreur_regex' => 'The regex string is incorrectly formatted.',
+       'erreur_siren' => 'The SIREN number is invalid.',
+       'erreur_siret' => 'The SIRET number is invalid.',
+       'erreur_taille_egal' => 'The value must have exactly @egal@ characters (currently @nb@).',
+       'erreur_taille_entre' => 'The value must have between @min@ and @max@ characters (currently @nb@).',
+       'erreur_taille_max' => 'The value must have no more than @max@ characters (currently @nb@).',
+       'erreur_taille_min' => 'The value must have no less than @min@ characters (currently @nb@).',
+       'erreur_telephone' => 'The telephone number is invalid.',
+       'erreur_url' => 'The URL address <em>@url@</em> is invalid.',
+       'erreur_url_protocole' => 'The address entered <em>(@url@)</em> must start with @protocole@',
+       'erreur_url_protocole_exact' => 'The address entered <em>(@url@)</em> does not start with a valid protocol (e.g. http://)',
+
+       // N
+       'normaliser_option_date' => 'Normalize the date?',
+       'normaliser_option_date_aucune' => 'No',
+       'normaliser_option_date_en_datetime' => '"Datetime" format (for SQL)',
+
+       // O
+       'option_couleur_normaliser_label' => 'Normalize the color code?',
+       'option_couleur_type_hexa' => 'Color code in hexadecimal format',
+       'option_couleur_type_label' => 'Checking type to be made',
+       'option_decimal_nb_decimales_label' => 'Number of decimal places',
+       'option_email_disponible_label' => 'Available address',
+       'option_email_disponible_label_case' => 'Check that the address has not already be used by another user',
+       'option_email_mode_5322' => 'Check against the strictest standards available',
+       'option_email_mode_label' => 'Email checking mode',
+       'option_email_mode_normal' => 'Normal SPIP checking',
+       'option_email_mode_strict' => 'Less permissive checking',
+       'option_entier_max_label' => 'Maximum value',
+       'option_entier_min_label' => 'Minimum value',
+       'option_regex_modele_label' => 'The value must match the following expression',
+       'option_siren_siret_mode_label' => 'What do you verify?',
+       'option_siren_siret_mode_siren' => 'SIREN number',
+       'option_siren_siret_mode_siret' => 'SIRET number',
+       'option_taille_max_label' => 'Maximum size',
+       'option_taille_min_label' => 'Minimum size',
+       'option_url_mode_complet' => 'Full verification of the URL',
+       'option_url_mode_label' => 'URL verification mode',
+       'option_url_mode_php_filter' => 'Full URL verification using the PHP filter FILTER_VALIDATE_URL',
+       'option_url_mode_protocole_seul' => 'Verification of the existence of a protocol only',
+       'option_url_protocole_label' => 'Name of the protocol to be verified',
+       'option_url_type_protocole_exact' => 'Enter a protocol below:',
+       'option_url_type_protocole_ftp' => 'File transfer protocols: FTP or SFTP',
+       'option_url_type_protocole_label' => 'Type of protocol to be verified',
+       'option_url_type_protocole_mail' => 'Mail protocols: IMAP, POP3 or SMTP',
+       'option_url_type_protocole_tous' => 'All accepted protocols',
+       'option_url_type_protocole_web' => 'Web protocols: HTTP or HTTPS',
+
+       // T
+       'type_couleur' => 'Colour',
+       'type_couleur_description' => 'Check if the value is a color code.',
+       'type_date' => 'Date',
+       'type_date_description' => 'Check that the value is date in the DD/MM/YYYY format. The separator character can be anything (".", "/", etc).',
+       'type_decimal' => 'Decimal number',
+       'type_decimal_description' => 'Check that the value is a decimal number, with options to restrict the value to a given range and to specify the required number of decmial places.',
+       'type_email' => 'Email address',
+       'type_email_description' => 'Check that the email address is correctly formatted.',
+       'type_email_disponible' => 'Availability of an email address',
+       'type_email_disponible_description' => 'Check that the email address has not already been used by another system user.',
+       'type_entier' => 'Integer',
+       'type_entier_description' => 'Check that the value is an integer, with the option of being restricted between two range values.',
+       'type_regex' => 'Regular expression',
+       'type_regex_description' => 'Check that the value matches the defined expression. For more information on using regular expressions, please refer to <a href="http://fr2.php.net/manual/en/reference.pcre.pattern.syntax.php">the online PHP help</a>.',
+       'type_siren_siret' => 'SIREN or SIRET',
+       'type_siren_siret_description' => 'Check that the value is a valid number from the French <a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des ENtreprises</a> (Company Registry ID System).',
+       'type_taille' => 'Size',
+       'type_taille_description' => 'Check that the size of the value corresponds to the minimum and/or maximum specified.',
+       'type_telephone' => 'Telephone number',
+       'type_telephone_description' => 'Check that the telephone number matches a recognised telephone number format.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Verify that the URL matches a recognised format.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_es.php b/www/plugins/verifier/lang/verifier_es.php
new file mode 100644 (file)
index 0000000..41cf738
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Este código postal es incorrecto',
+       'erreur_comparaison_egal' => 'El valor debe ser igual al campo "@nom_champ@"',
+       'erreur_comparaison_egal_type' => 'El valor debe ser igual y del mismo tipo que el campo "@nom_champ@"',
+       'erreur_comparaison_grand' => 'El valor debe ser superior al campo "@nom_champ@"',
+       'erreur_comparaison_grand_egal' => 'El valor debe ser superior o igual al campo "@nom_champ@"',
+       'erreur_comparaison_petit' => 'El valor debe ser inferior al campo "@nom_champ@"',
+       'erreur_comparaison_petit_egal' => 'El valor debe ser inferior o igual al campo "@nom_champ@"',
+       'erreur_couleur' => 'El código color no es válido.',
+       'erreur_date' => 'La fecha no es válida',
+       'erreur_date_format' => 'No se acepta este formato de fecha.',
+       'erreur_decimal' => 'El valor debe ser un número decimal.',
+       'erreur_decimal_nb_decimales' => 'El número no debe tener más de @nb_decimales@ cifras tras la coma.',
+       'erreur_email' => 'La dirección de correo electrónico <em>@email@</em> no tiene un formato válido.',
+       'erreur_email_nondispo' => 'La dirección de correo electrónico <em>@email@</em> ya está en uso.',
+       'erreur_entier' => 'El valor debe ser un número entero.',
+       'erreur_entier_entre' => 'El valor deber ser entre @min@ y @max@.',
+       'erreur_entier_max' => 'El valor debe ser inferior a @max@.',
+       'erreur_entier_min' => 'El valor debe ser superior a @min@.',
+       'erreur_heure' => 'El horario indicado no existe.',
+       'erreur_heure_format' => 'El formato de la hora no es válido.',
+       'erreur_id_document' => 'Este identificador de documento no es válido.',
+       'erreur_inconnue_generique' => 'El formato no es correcto.',
+       'erreur_isbn' => 'El número ISBN no es válido (ejemplo: 978-2-1234-5680-3 o 2-1234-5680-X)',
+       'erreur_isbn_13_X' => 'Un número ISBN-13 no puede terminar por X.',
+       'erreur_isbn_G' => 'El primer segmento debe ser igual a 978 o 979.',
+       'erreur_isbn_nb_caracteres' => 'El número ISBN debe tener 10 o 13 caracteres, sin contar los guiones (actualmente @nb@).',
+       'erreur_isbn_nb_segments' => 'El número ISBN debe tener 4 o 5 segmentos (actualmente @nb@).',
+       'erreur_isbn_segment' => 'El segmento "@segment@" tiene @nb@ cifra(s) como mucho.',
+       'erreur_isbn_segment_lettre' => 'El segmento "@segment@" no debe contener letras.',
+       'erreur_numerique' => 'El formato del número no es válido.',
+       'erreur_regex' => 'El formato de la cadena no es válido.',
+       'erreur_siren' => 'Este número de SIREN no es válido.',
+       'erreur_siret' => 'El número de SIRET no es válido.',
+       'erreur_taille_egal' => 'El valor debe tener exactamente @egal@ caracteres (actualmente @nb@).',
+       'erreur_taille_entre' => 'El valor debe tener entre @min@ y @max@ caracteres (actualmente @nb@).',
+       'erreur_taille_max' => 'El valor debe tener como máximo @max@ caracteres (actualmente @nb@).',
+       'erreur_taille_min' => 'El valor debe tener como mínimo @min@ caracteres (actualmente @nb@).',
+       'erreur_telephone' => 'El número no es válido.',
+       'erreur_url' => 'La dirección <em>@url@</em> no es válida.',
+       'erreur_url_protocole' => 'La dirección ingresada <em>(@url@)</em> debe comenzar por @protocole@',
+       'erreur_url_protocole_exact' => 'La dirección ingresada <em>(@url@)</em> no comienza por un protocolo válido (http:// por ejemplo)',
+
+       // N
+       'normaliser_option_date' => '¿Normalizar la fecha?',
+       'normaliser_option_date_aucune' => 'No',
+       'normaliser_option_date_en_datetime' => 'En formato «Datetime» (para SQL)',
+
+       // O
+       'option_couleur_normaliser_label' => '¿Normalizar el código color?',
+       'option_couleur_type_hexa' => 'Código color en formato hexadecimal',
+       'option_couleur_type_label' => 'Tipo de verificación a efectuar',
+       'option_decimal_nb_decimales_label' => 'Número de decimales tras la coma',
+       'option_email_disponible_label' => 'Dirección disponible',
+       'option_email_disponible_label_case' => 'Verifique que la dirección no sea usada por otra persona.',
+       'option_email_mode_5322' => 'La verificación más conforme a los estándares existentes',
+       'option_email_mode_label' => 'Modo de comprobación de las direcciones de correo electrónico',
+       'option_email_mode_normal' => 'Comprobación normal de SPIP',
+       'option_email_mode_strict' => 'Comprobación no tan permisiva',
+       'option_entier_max_label' => 'Valor máximo',
+       'option_entier_min_label' => 'Valor mínimo',
+       'option_regex_modele_label' => 'El valor debe corresponder al patrón siguiente',
+       'option_siren_siret_mode_label' => '¿Qué quiere comprobar?',
+       'option_siren_siret_mode_siren' => 'el SIREN',
+       'option_siren_siret_mode_siret' => 'el SIRET',
+       'option_taille_max_label' => 'Tamaño máximo',
+       'option_taille_min_label' => 'Tamaño mínimo',
+       'option_url_mode_complet' => 'Verificación completa de la url',
+       'option_url_mode_label' => 'Modo de verificación de las urls',
+       'option_url_mode_php_filter' => 'Verificación completa de la url a través del filtro FILTER_VALIDATE_URL de php',
+       'option_url_mode_protocole_seul' => 'Verificación únicamente de la presencia de un protocolo',
+       'option_url_protocole_label' => 'Nombre del protocolo a verificar',
+       'option_url_type_protocole_exact' => 'Ingresar un protocolo a continuación:',
+       'option_url_type_protocole_ftp' => 'Protocolos ftp: ftp o sftp',
+       'option_url_type_protocole_label' => 'Tipo de protocolo a verificar',
+       'option_url_type_protocole_mail' => 'Protocolos mail: imap, pop3 o smtp',
+       'option_url_type_protocole_tous' => 'Todos los protocolos aceptados',
+       'option_url_type_protocole_web' => 'Protocolos web: http o https',
+
+       // T
+       'type_couleur' => 'Color',
+       'type_couleur_description' => 'Verifica que el valor es un código color.',
+       'type_date' => 'Fecha',
+       'type_date_description' => 'Comprueba que el valor es una fecha con el formato DD/MM/AAAA. El separador no importa (".", "/", etc).',
+       'type_decimal' => 'Número decimal',
+       'type_decimal_description' => 'Verifica que el valor es un número decimal, con la posibilidad de restringir entre diez valores y de precisar el número de decimales tras la coma.',
+       'type_email' => 'Dirección de correo electrónico',
+       'type_email_description' => 'Comprueba que la dirección de correo electrónico tiene el formato correcto.',
+       'type_email_disponible' => 'Disponibilidad de una dirección de correo electrónico',
+       'type_email_disponible_description' => 'Comprueba que la dirección de correo electrónico no está usada por otro usuario del sistema.',
+       'type_entier' => 'Número entero',
+       'type_entier_description' => 'Comprueba que el valor es un número entero, con la posibilidad de restringir entre dos valores.',
+       'type_regex' => 'Expresión regular',
+       'type_regex_description' => 'Comprueba que el valor corresponda al patrón indicado. Para el uso de los patrones, refiérase a <a href="http://php.net/manual/es/reference.pcre.pattern.syntax.php">la documentación en línea de PHP</a>.',
+       'type_siren_siret' => 'SIREN o SIRET',
+       'type_siren_siret_description' => 'Comprueba que el valor es un número valido del <a href="http://fr.wikipedia.org/wiki/SIREN">Sistema de Identificación del Repertorio de las Empresas</a> francés.',
+       'type_taille' => 'Tamaño',
+       'type_taille_description' => 'Comprueba que el tamaño del valor corresponde al mínimo y/o al máximo indicado.',
+       'type_telephone' => 'Número de teléfono',
+       'type_telephone_description' => 'Comprueba que el número de teléfono corresponde a un patrón reconocido.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Verifica que la url corresponde a un patrón conocido.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_fa.php b/www/plugins/verifier/lang/verifier_fa.php
new file mode 100644 (file)
index 0000000..a95b78c
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'اين كد پستي درست نيست.',
+       'erreur_comparaison_egal' => 'اين مقدار بايد با ميدان"@nom_champ@"  مساوي باشد',
+       'erreur_comparaison_egal_type' => 'اين مقدار بايد با نوع مقدار ميدان  "@nom_champ@" مساوي و يكي باشد',
+       'erreur_comparaison_grand' => 'اين مقدار بايد از ميدان"@nom_champ@" بالاتر باشد',
+       'erreur_comparaison_grand_egal' => 'اين مقدار بايد از مقدار ميدانِ "@nom_champ@"بالاتر يا مساوي باشد',
+       'erreur_comparaison_petit' => 'اين مقدار بايد از مقدار ميدان"@nom_champ@"  پائين‌تر باشد',
+       'erreur_comparaison_petit_egal' => 'اين مقدار بايد از مقدار ميدان "@nom_champ@"پائين‌تر يا با آن مساوي باشد',
+       'erreur_couleur' => 'كد رنگ معتبر نيست.',
+       'erreur_date' => 'تاريخ معتبر نيست.',
+       'erreur_date_format' => 'فرمت تاريخ قبول نيست.',
+       'erreur_decimal' => 'مقدار بايد يك عدد اعشاري باشد.',
+       'erreur_decimal_nb_decimales' => 'رقم نمي‌تواند بيش از @nb_decimales@ اعشار داشته باشد.',
+       'erreur_email' => 'نشاني ايميل <em>@email@</em> درست فرمت‌ بندي نشده. ',
+       'erreur_email_nondispo' => 'نشاني ايميل <em>@email@</em> پيشتر استفاده شده.',
+       'erreur_entier' => 'مقدار بايد يك عدد صحيح باشد.',
+       'erreur_entier_entre' => 'مقدار بايد بين @min@ و @max@.',
+       'erreur_entier_max' => 'مقدار بايد كم‌تر از @max@ باشد.',
+       'erreur_entier_min' => 'مقدار بايد بيشتر از @min@ باشد.',
+       'erreur_heure' => 'L’horaire indiquée n’existe pas.', # NEW
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.', # NEW
+       'erreur_id_document' => 'اين شناسه‌ي سند معتبر نيست.',
+       'erreur_inconnue_generique' => 'فرمت صحيح نيست',
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)', # NEW
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # NEW
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # NEW
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).', # NEW
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).', # NEW
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.', # NEW
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.', # NEW
+       'erreur_numerique' => 'فرمت عدد معتبر نيست.',
+       'erreur_regex' => 'فرمت رشته معتبر نيست.',
+       'erreur_siren' => 'فرمت SIREN معتبر نيست.',
+       'erreur_siret' => 'شماره SIRET معتبر نيست. ',
+       'erreur_taille_egal' => 'مقدار بايد دقيقاً كاراكتر‌هاي @egal@ داشته باشد.', # MODIF
+       'erreur_taille_entre' => 'مقدار بايد بين @min@ و @max@ كاراكتر داشته باشد. ', # MODIF
+       'erreur_taille_max' => 'مقدار نبايد بيش از @max@ كاراكتر داشته باشد.', # MODIF
+       'erreur_taille_min' => 'اين مقدار نبايد كم‌تر از @min@ كارآكتر داشته باشد.', # MODIF
+       'erreur_telephone' => 'اين شماره معتبر نيست.',
+       'erreur_url' => 'نشاني <em>@url@</em> معتبر نيست',
+       'erreur_url_protocole' => 'نشاني وارد شده <em>(@url@)</em> doit بايد با @protocole@ آغاز شود. ',
+       'erreur_url_protocole_exact' => 'نشاني وارد شده <em>(@url@)</em> با يك پروتكل معتبر (http:// مانند)شروع نمي‌شود',
+
+       // N
+       'normaliser_option_date' => 'عادي‌سازي داده‌؟',
+       'normaliser_option_date_aucune' => 'خير',
+       'normaliser_option_date_en_datetime' => 'با فرمت «تاريخ‌زمان» (براي اس‌كيو‌ال)',
+
+       // O
+       'option_couleur_normaliser_label' => 'عادي سازي كد رنگ؟',
+       'option_couleur_type_hexa' => 'كد رنگ با فرمت هگزادسيمال',
+       'option_couleur_type_label' => 'نوع تأييد براي اجرا',
+       'option_decimal_nb_decimales_label' => 'تعداد اعشارها بعد از مميز',
+       'option_email_disponible_label' => 'نشاني در دسترس',
+       'option_email_disponible_label_case' => 'چك كنيد كه كاربر ديگر اين نشاني را استفاده نكرده باشد',
+       'option_email_mode_5322' => 'چك كنيد كه معتبرترين استانداردها در دسترس باشد',
+       'option_email_mode_label' => 'حالت چك كردن ايميل‌ها',
+       'option_email_mode_normal' => 'چك كردن معمولي اسپيپ ',
+       'option_email_mode_strict' => 'چك كردن آسان‌گيرانه‌تر',
+       'option_entier_max_label' => 'بيشترين مقدار',
+       'option_entier_min_label' => 'كمر‌ترين مقدار ',
+       'option_regex_modele_label' => 'مقدار بايد با عبارت بعدي جور باشد',
+       'option_siren_siret_mode_label' => 'مي‌خواهيد تأييد كنيد؟ ',
+       'option_siren_siret_mode_siren' => 'شماره «نظام ملي اطلاعات فهرست بنگاه‌ها» (به فرانسه SIREN)',
+       'option_siren_siret_mode_siret' => 'شماره «نظام ملي فهرست بنگاه‌ها و مؤسسات» (سرواژه‌ي فرانسه آن: SIRET)',
+       'option_taille_max_label' => 'بيشترين اندازه',
+       'option_taille_min_label' => 'كم‌ترين اندازه',
+       'option_url_mode_complet' => 'چك كامل يو.آر.ال',
+       'option_url_mode_label' => 'حالت چك كردن يو.آر.ال ها',
+       'option_url_mode_php_filter' => 'چك كامل يو.آر.ال از طريق فيلتر FILTER_VALIDATE_URL  پي.اچ.پي',
+       'option_url_mode_protocole_seul' => 'چك كردن انحصاري وجود يك پروتكل ',
+       'option_url_protocole_label' => 'نام پروتكل براي چك كردن',
+       'option_url_type_protocole_exact' => 'يك پروتكل در زير وارد كنيد:',
+       'option_url_type_protocole_ftp' => 'پروتكل‌هاي انتقال پرونده: ftp  يا sftp ',
+       'option_url_type_protocole_label' => 'نوع پروتكل براي چك كردن',
+       'option_url_type_protocole_mail' => 'پروتكل‌هاي نامه‌ الكترونيكي: imap, pop3  يا smtp',
+       'option_url_type_protocole_tous' => 'تمام پروتكل‌هاي مورد قبول ',
+       'option_url_type_protocole_web' => 'پروتكل‌هاي وب: http يا https',
+
+       // T
+       'type_couleur' => 'رنگ',
+       'type_couleur_description' => 'تأييد مقداري كه يك كد رنگ است ',
+       'type_date' => 'تاريخ',
+       'type_date_description' => 'چك كنيد كه فرمت تاريخ اين باشد: س‌س‌س‌س/م‌م/رر. مميز آزاد است («.»، «/»، و غيره).',
+       'type_decimal' => 'شماره‌ي اعشاري',
+       'type_decimal_description' => 'چك كنيد كه مقدار يك رغم اعشاري باشد، با امكان محدود كردن دو مقدار و تعيين اعشار بعد از مميز.',
+       'type_email' => 'نشاني ايميل ',
+       'type_email_description' => 'چك كنيد كه نشاني ايميل فرمت درست داشته باشد.',
+       'type_email_disponible' => 'دسترس‌‌بودگي نشاني ايميل',
+       'type_email_disponible_description' => 'چك كنيد كه نشاني ايميل از سوي كاربر ديگر سامانه استفاده نشده باشد.',
+       'type_entier' => 'عدد صحيح',
+       'type_entier_description' => 'چك كنيد كه مقدار يك عدد صحيح باشد،‌ با گزينه‌ي محدوديت بين دو مقدار.',
+       'type_regex' => 'عبارت عادي',
+       'type_regex_description' => '<چك كنيد كه مقدار با عبارت خواسته شد جور باشد. براي اطلاعات بيشتر در مورد استفاده از عبارت درخواست شده به اينجا رجوع كنيد: <a href="http://fr2.php.net/manual/fr/reference.pcre.pattern.syntax.php">l\'aide en ligne de PHP</a>.',
+       'type_siren_siret' => 'شماره‌ي نظام ملي اطلاعات فهرست بنگاه‌ها يا شماره‌ي ملي فهرست بنگاه‌ها و تأسيسات (سرواژه به فرانسه:SIREN ياSIRET)',
+       'type_siren_siret_description' => 'چك كنيد كه مقدار يك شماره‌ي معتبر است <a href="http://fr.wikipedia.org/wiki/SIREN">نظامل اطلاعات بنگاه‌ها به فرانسه s</a> .',
+       'type_taille' => 'اندازه',
+       'type_taille_description' => 'چك كنيد كه اندازه‌ي مقدار با بيشترين و/يا كم‌ترين مقدار درخواستي جور باشد.',
+       'type_telephone' => 'شماره تلفن',
+       'type_telephone_description' => 'چك كنيد كه شماره‌ي تلفن با فرمت شماره‌ي تلفن جور باشد.',
+       'type_url' => 'يو.آر.ال ',
+       'type_url_description' => 'چك كنيد كه يو.آر.ال با يك فرمت شناخته شده جور باشد. '
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_fr.php b/www/plugins/verifier/lang/verifier_fr.php
new file mode 100644 (file)
index 0000000..accb401
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/verifier/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Ce code postal est incorrect.',
+       'erreur_comparaison_egal' => 'La valeur doit être égale au champ "@nom_champ@"',
+       'erreur_comparaison_egal_type' => 'La valeur doit être égale et de même type que le champ "@nom_champ@"',
+       'erreur_comparaison_grand' => 'La valeur doit être supérieure au champ "@nom_champ@"',
+       'erreur_comparaison_grand_egal' => 'La valeur doit être supérieure ou égale au champ "@nom_champ@"',
+       'erreur_comparaison_petit' => 'La valeur doit être inférieure au champ "@nom_champ@"',
+       'erreur_comparaison_petit_egal' => 'La valeur doit être inférieure ou égale au champ "@nom_champ@"',
+       'erreur_couleur' => 'Le code couleur n\'est pas valide.',
+       'erreur_date' => 'La date n\'est pas valide.',
+       'erreur_date_format' => 'Le format de la date n\'est pas accepté.',
+       'erreur_decimal' => 'La valeur doit être un nombre décimal.',
+       'erreur_decimal_nb_decimales' => 'Le nombre ne doit pas avoir plus de @nb_decimales@ chiffres après la virgule.',
+       'erreur_email' => 'L\'adresse de courriel <em>@email@</em> n\'a pas un format valide.',
+       'erreur_email_nondispo' => 'L\'adresse de courriel <em>@email@</em> est déjà utilisée.',
+       'erreur_entier' => 'La valeur doit être un entier.',
+       'erreur_entier_entre' => 'La valeur doit être comprise entre @min@ et @max@.',
+       'erreur_entier_max' => 'La valeur doit être inférieure à @max@.',
+       'erreur_entier_min' => 'La valeur doit être supérieure à @min@.',
+       'erreur_heure' => 'L’horaire indiqué n’existe pas.',
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.',
+       'erreur_id_document' => 'Cet identifiant de document n\'est pas valide.',
+       'erreur_inconnue_generique' => 'Le format n\'est pas correct.',
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)',
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.',
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.',
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).',
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).',
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.',
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.',
+       'erreur_numerique' => 'Le format du nombre n\'est pas valide.',
+       'erreur_regex' => 'Le format de la chaîne n\'est pas valide.',
+       'erreur_siren' => 'Le numéro de SIREN n\'est pas valide.',
+       'erreur_siret' => 'Le numéro de SIRET n\'est pas valide.',
+       'erreur_taille_egal' => 'La valeur doit comprendre exactement @egal@ caractères (actuellement @nb@).',
+       'erreur_taille_entre' => 'La valeur doit comprendre entre @min@ et @max@ caractères (actuellement @nb@).',
+       'erreur_taille_max' => 'La valeur doit comprendre au maximum @max@ caractères (actuellement @nb@).',
+       'erreur_taille_min' => 'La valeur doit comprendre au minimum @min@ caractères (actuellement @nb@).',
+       'erreur_telephone' => 'Le numéro n\'est pas valide.',
+       'erreur_url' => 'L\'adresse <em>@url@</em> n\'est pas valide.',
+       'erreur_url_protocole' => 'L\'adresse saisie <em>(@url@)</em> doit commencer par @protocole@',
+       'erreur_url_protocole_exact' => 'L\'adresse saisie <em>(@url@)</em> ne commence pas par un protocole valide (http:// par exemple)',
+
+       // N
+       'normaliser_option_date' => 'Normaliser la date ?',
+       'normaliser_option_date_aucune' => 'Non',
+       'normaliser_option_date_en_datetime' => 'Au format «Datetime» (pour SQL)',
+
+       // O
+       'option_couleur_normaliser_label' => 'Normaliser le code couleur ?',
+       'option_couleur_type_hexa' => 'Code couleur au format héxadécimal',
+       'option_couleur_type_label' => 'Type de vérification à effectuer',
+       'option_decimal_nb_decimales_label' => 'Nombre de décimales après la virgule',
+       'option_email_disponible_label' => 'Adresse disponible',
+       'option_email_disponible_label_case' => 'Vérifier que l\'adresse n\'est pas déjà utilisée par un utilisateur',
+       'option_email_mode_5322' => 'Vérification la plus conforme aux standards disponibles',
+       'option_email_mode_label' => 'Mode de vérification des courriels',
+       'option_email_mode_normal' => 'Vérification normale de SPIP',
+       'option_email_mode_strict' => 'Vérification moins permissive',
+       'option_entier_max_label' => 'Valeur maximum',
+       'option_entier_min_label' => 'Valeur minimum',
+       'option_regex_modele_label' => 'La valeur doit correspondre au masque suivant',
+       'option_siren_siret_mode_label' => 'Que voulez-vous vérifier ?',
+       'option_siren_siret_mode_siren' => 'le SIREN',
+       'option_siren_siret_mode_siret' => 'le SIRET',
+       'option_taille_max_label' => 'Taille maximum',
+       'option_taille_min_label' => 'Taille minimum',
+       'option_url_mode_complet' => 'Vérification complète de l\'url',
+       'option_url_mode_label' => 'Mode de vérification des urls',
+       'option_url_mode_php_filter' => 'Vérification complète de l\'url via le filtre FILTER_VALIDATE_URL de php',
+       'option_url_mode_protocole_seul' => 'Vérification uniquement de la présence d\'un protocole',
+       'option_url_protocole_label' => 'Nom du protocole à vérifier',
+       'option_url_type_protocole_exact' => 'Saisir un protocole ci-dessous :',
+       'option_url_type_protocole_ftp' => 'Protocoles ftp : ftp ou sftp',
+       'option_url_type_protocole_label' => 'Type de protocole à vérifier',
+       'option_url_type_protocole_mail' => 'Protocoles mail : imap, pop3 ou smtp',
+       'option_url_type_protocole_tous' => 'Tous protocoles acceptés',
+       'option_url_type_protocole_web' => 'Protocoles web : http ou https',
+
+       // T
+       'type_couleur' => 'Couleur',
+       'type_couleur_description' => 'Vérifie que la valeur est un code couleur.',
+       'type_date' => 'Date',
+       'type_date_description' => 'Vérifie que la valeur est une date au format JJ/MM/AAAA. Le séparateur est libre (&quot;.&quot;, &quot;/&quot;, etc).',
+       'type_decimal' => 'Nombre décimal',
+       'type_decimal_description' => 'Vérifie que la valeur est un nombre décimal, avec la possibilité de restreindre entre deux valeurs et de préciser le nombre de décimales après la virgule.',
+       'type_email' => 'Adresse de courriel',
+       'type_email_description' => 'Vérifie que l\'adresse de courriel a un format correct.',
+       'type_email_disponible' => 'Disponibilité d\'une adresse de courriel',
+       'type_email_disponible_description' => 'Vérifie que l\'adresse de courriel n\'est pas déjà utilisé par un autre utilisateur du système.',
+       'type_entier' => 'Nombre entier',
+       'type_entier_description' => 'Vérifie que la valeur est un entier, avec la possibilité de restreindre entre deux valeurs.',
+       'type_regex' => 'Expression régulière',
+       'type_regex_description' => 'Vérifie que la valeur correspond au masque demandé. Pour l\'utilisation des masques, reportez-vous à <a href="http://fr2.php.net/manual/fr/reference.pcre.pattern.syntax.php">l\'aide en ligne de PHP</a>.',
+       'type_siren_siret' => 'SIREN ou SIRET',
+       'type_siren_siret_description' => 'Vérifie que la valeur est un numéro valide du <a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des ENtreprises</a> français.',
+       'type_taille' => 'Taille',
+       'type_taille_description' => 'Vérifie que la taille de la valeur correspond au minimum et/ou au maximum demandé.',
+       'type_telephone' => 'Numéro de téléphone',
+       'type_telephone_description' => 'Vérifie que le numéro de téléphone correspond à un schéma reconnu.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Vérifie que l\'url correspond à un schéma reconnu.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_fr_tu.php b/www/plugins/verifier/lang/verifier_fr_tu.php
new file mode 100644 (file)
index 0000000..3b02bc9
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=fr_tu
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Ce code postal est incorrect.',
+       'erreur_comparaison_egal' => 'La valeur doit être égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_egal_type' => 'La valeur doit être égale et de même type que le champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand' => 'La valeur doit être supérieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand_egal' => 'La valeur doit être supérieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit' => 'La valeur doit être inférieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit_egal' => 'La valeur doit être inférieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_couleur' => 'Le code couleur n\'est pas valide.', # NEW
+       'erreur_date' => 'La date n\'est pas valide.',
+       'erreur_date_format' => 'Le format de la date n\'est pas accepté.',
+       'erreur_decimal' => 'La valeur doit être un nombre décimal.',
+       'erreur_decimal_nb_decimales' => 'Le nombre ne doit pas avoir plus de @nb_decimales@ chiffres après la virgule.',
+       'erreur_email' => '@email@</em> n\'a pas un format valide.',
+       'erreur_email_nondispo' => 'L\'adresse de courriel <em>@email@</em> est déjà utilisée.',
+       'erreur_entier' => 'La valeur doit être un entier.',
+       'erreur_entier_entre' => 'La valeur doit être comprise entre @min@ et @max@.',
+       'erreur_entier_max' => 'La valeur doit être inférieure à @max@.',
+       'erreur_entier_min' => 'La valeur doit être supérieure à @min@.',
+       'erreur_heure' => 'L’horaire indiquée n’existe pas.', # NEW
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.', # NEW
+       'erreur_id_document' => 'Cet identifiant de document n\'est pas valide.',
+       'erreur_inconnue_generique' => 'Le format n\'est pas correct.', # NEW
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)', # NEW
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # NEW
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # NEW
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).', # NEW
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).', # NEW
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.', # NEW
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.', # NEW
+       'erreur_numerique' => 'Le format du nombre n\'est pas valide.',
+       'erreur_regex' => 'Le format de la chaîne n\'est pas valide.',
+       'erreur_siren' => 'Le numéro de SIREN n\'est pas valide.',
+       'erreur_siret' => 'Le numéro de SIRET n\'est pas valide.',
+       'erreur_taille_egal' => 'La valeur doit comprendre exactement @egal@ caractères.', # MODIF
+       'erreur_taille_entre' => 'La valeur doit comprendre entre @min@ et @max@ caractères.', # MODIF
+       'erreur_taille_max' => 'La valeur doit comprendre au maximum @max@ caractères.', # MODIF
+       'erreur_taille_min' => 'La valeur doit comprendre au minimum @min@ caractères.', # MODIF
+       'erreur_telephone' => 'Le numéro n\'est pas valide.', # MODIF
+       'erreur_url' => 'L\'adresse <em>@url@</em> n\'est pas valide.',
+       'erreur_url_protocole' => 'L\'adresse saisie <em>(@url@)</em> doit commencer par @protocole@',
+       'erreur_url_protocole_exact' => 'L\'adresse saisie <em>(@url@)</em> ne commence pas par un protocole valide (http:// par exemple)',
+
+       // N
+       'normaliser_option_date' => 'Normaliser la date ?', # NEW
+       'normaliser_option_date_aucune' => 'Non', # NEW
+       'normaliser_option_date_en_datetime' => 'Au format «Datetime» (pour SQL)', # NEW
+
+       // O
+       'option_couleur_normaliser_label' => 'Normaliser le code couleur ?', # NEW
+       'option_couleur_type_hexa' => 'Code couleur au format héxadécimal', # NEW
+       'option_couleur_type_label' => 'Type de vérification à effectuer', # NEW
+       'option_decimal_nb_decimales_label' => 'Nombre de décimales après la virgule',
+       'option_email_disponible_label' => 'Adresse disponible',
+       'option_email_disponible_label_case' => 'Vérifier que l\'adresse n\'est pas déjà utilisée par un utilisateur',
+       'option_email_mode_5322' => 'Vérification la plus conforme aux standards disponibles',
+       'option_email_mode_label' => 'Mode de vérification des courriels',
+       'option_email_mode_normal' => 'Vérification normale de SPIP',
+       'option_email_mode_strict' => 'Vérification moins permissive',
+       'option_entier_max_label' => 'Valeur maximum',
+       'option_entier_min_label' => 'Valeur minimum',
+       'option_regex_modele_label' => 'La valeur doit correspondre au masque suivant',
+       'option_siren_siret_mode_label' => 'Que veux-tu vérifier ?', # MODIF
+       'option_siren_siret_mode_siren' => 'le SIREN',
+       'option_siren_siret_mode_siret' => 'le SIRET',
+       'option_taille_max_label' => 'Taille maximum',
+       'option_taille_min_label' => 'Taille minimum',
+       'option_url_mode_complet' => 'Vérification complète de l\'url',
+       'option_url_mode_label' => 'Mode de vérification des urls',
+       'option_url_mode_php_filter' => 'Vérification complète de l\'url via le filtre FILTER_VALIDATE_URL de php',
+       'option_url_mode_protocole_seul' => 'Vérification uniquement de la présence d\'un protocole', # MODIF
+       'option_url_protocole_label' => 'Nom du protocole à vérifier',
+       'option_url_type_protocole_exact' => 'Saisir un protocole ci-dessous :',
+       'option_url_type_protocole_ftp' => 'Protocoles ftp : ftp ou sftp',
+       'option_url_type_protocole_label' => 'Type de protocole à vérifier',
+       'option_url_type_protocole_mail' => 'Protocoles mail : imap, pop3 ou smtp',
+       'option_url_type_protocole_tous' => 'Tous protocoles acceptés',
+       'option_url_type_protocole_web' => 'Protocoles web : http ou https',
+
+       // T
+       'type_couleur' => 'Couleur', # NEW
+       'type_couleur_description' => 'Vérifie que la valeur est un code couleur.', # NEW
+       'type_date' => 'Date',
+       'type_date_description' => 'Vérifie que la valeur est une date au format JJ/MM/AAAA. Le séparateur est libre (".", "/", etc).',
+       'type_decimal' => 'Nombre décimal',
+       'type_decimal_description' => 'Vérifie que la valeur est un nombre décimal, avec la possibilité de restreindre entre deux valeurs et de préciser le nombre de décimales après la virgule.',
+       'type_email' => 'Adresse de courriel',
+       'type_email_description' => 'Vérifie que l\'adresse de courriel a un format correct.',
+       'type_email_disponible' => 'Disponibilité d\'une adresse de courriel',
+       'type_email_disponible_description' => 'Vérifie que l\'adresse de courriel n\'est pas déjà utilisé par un autre utilisateur du système.',
+       'type_entier' => 'Nombre entier',
+       'type_entier_description' => 'Vérifie que la valeur est un entier, avec la possibilité de restreindre entre deux valeurs.',
+       'type_regex' => 'Expression régulière',
+       'type_regex_description' => 'Vérifie que la valeur correspond au masque demandé. Pour l\'utilisation des masques, reporte-toi à <a href="http://fr2.php.net/manual/fr/reference.pcre.pattern.syntax.php">l\'aide en ligne de PHP</a>.', # MODIF
+       'type_siren_siret' => 'SIREN ou SIRET',
+       'type_siren_siret_description' => 'Vérifie que la valeur est un numéro valide du <a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des ENtreprises</a> français.',
+       'type_taille' => 'Taille',
+       'type_taille_description' => 'Vérifie que la taille de la valeur correspond au minimum et/ou au maximum demandé.',
+       'type_telephone' => 'Numéro de téléphone',
+       'type_telephone_description' => 'Vérifie que le numéro de téléphone correspond à un schéma reconnu.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Vérifie que l\'url correspond à un schéma reconnu.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_it.php b/www/plugins/verifier/lang/verifier_it.php
new file mode 100644 (file)
index 0000000..18cdd0c
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=it
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Il CAP non è corretto.',
+       'erreur_comparaison_egal' => 'La valeur doit être égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_egal_type' => 'La valeur doit être égale et de même type que le champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand' => 'La valeur doit être supérieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand_egal' => 'La valeur doit être supérieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit' => 'La valeur doit être inférieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit_egal' => 'La valeur doit être inférieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_couleur' => 'Le code couleur n\'est pas valide.', # NEW
+       'erreur_date' => 'La data non è valida.',
+       'erreur_date_format' => 'Il formato della data non è corretto.',
+       'erreur_decimal' => 'Il valore deve essere un numero decimale.',
+       'erreur_decimal_nb_decimales' => 'Il numero non deve avere più di @nb_decimales@ cifre dopo la virgola.',
+       'erreur_email' => 'L\'indirizzo di posta <em>@email@</em> non ha un formato valido.',
+       'erreur_email_nondispo' => 'L\'indirizzo di posta <em>@email@</em> è già utilizzato.',
+       'erreur_entier' => 'Il valore deve essere un numero intero.',
+       'erreur_entier_entre' => 'Il valore deve essere compreso tra @min@ e @max@.',
+       'erreur_entier_max' => 'Il valore deve essere minore di @max@.',
+       'erreur_entier_min' => 'Il valore deve essere maggiore di @min@.',
+       'erreur_heure' => 'L’horaire indiquée n’existe pas.', # NEW
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.', # NEW
+       'erreur_id_document' => 'L\'id del documento non è valido.',
+       'erreur_inconnue_generique' => 'Le format n\'est pas correct.', # NEW
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)', # NEW
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # NEW
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # NEW
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).', # NEW
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).', # NEW
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.', # NEW
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.', # NEW
+       'erreur_numerique' => 'Il formato del numero non è valido.',
+       'erreur_regex' => 'Il formato non è valido.',
+       'erreur_siren' => 'Il numero di SIREN non è valido.',
+       'erreur_siret' => 'Il numero di SIRET non è valido.',
+       'erreur_taille_egal' => 'Il valore deve avere esattamente @egal@ caratteri.', # MODIF
+       'erreur_taille_entre' => 'Il valore deve avere da @min@ a @max@ caratteri.', # MODIF
+       'erreur_taille_max' => 'Il valore deve avere al massimo @max@ caratteri.', # MODIF
+       'erreur_taille_min' => 'Il valore deve avere minimo @min@ caratteri.', # MODIF
+       'erreur_telephone' => 'Il numero non è valido.',
+       'erreur_url' => 'L\'indirizzo <em>@url@</em> non è valido.',
+       'erreur_url_protocole' => 'L\'indirizzo inserito <em>(@url@)</em> deve cominciare con @protocole@',
+       'erreur_url_protocole_exact' => 'L\'indirizzo inserito <em>(@url@)</em> non comincia con un protocollo valido (http:// ad esempio)',
+
+       // N
+       'normaliser_option_date' => 'Normaliser la date ?', # NEW
+       'normaliser_option_date_aucune' => 'Non', # NEW
+       'normaliser_option_date_en_datetime' => 'Au format «Datetime» (pour SQL)', # NEW
+
+       // O
+       'option_couleur_normaliser_label' => 'Normaliser le code couleur ?', # NEW
+       'option_couleur_type_hexa' => 'Code couleur au format héxadécimal', # NEW
+       'option_couleur_type_label' => 'Type de vérification à effectuer', # NEW
+       'option_decimal_nb_decimales_label' => 'Numero di decimali dopo la virgola',
+       'option_email_disponible_label' => 'Indirizzo disponibile',
+       'option_email_disponible_label_case' => 'Verifica che l\'indirizzo non sia già stato utilizzato da un utente',
+       'option_email_mode_5322' => 'Verifica rispetto agli standard disponibili',
+       'option_email_mode_label' => 'Modalità di verifica delle email',
+       'option_email_mode_normal' => 'Verifica normale di SPIP',
+       'option_email_mode_strict' => 'Verifica meno permissiva',
+       'option_entier_max_label' => 'Valore massimo',
+       'option_entier_min_label' => 'Valore minimo',
+       'option_regex_modele_label' => 'Il valore deve corrispondere alla seguente maschera',
+       'option_siren_siret_mode_label' => 'Cosa vuoi verificare?',
+       'option_siren_siret_mode_siren' => 'il SIREN',
+       'option_siren_siret_mode_siret' => 'il SIRET',
+       'option_taille_max_label' => 'Dimensione massima',
+       'option_taille_min_label' => 'Dimensione minima',
+       'option_url_mode_complet' => 'Verifica completa dell\'url',
+       'option_url_mode_label' => 'Modalità di verifica dell\'url',
+       'option_url_mode_php_filter' => 'Verifica completa dell\'url grazie al filtro FILTER_VALIDATE_URL di php',
+       'option_url_mode_protocole_seul' => 'Verifica solo la presenza di un protocollo',
+       'option_url_protocole_label' => 'Nome del protocollo da verificare',
+       'option_url_type_protocole_exact' => 'Inserisci un protocollo qui sotto:',
+       'option_url_type_protocole_ftp' => 'Protocolli ftp : ftp o sftp',
+       'option_url_type_protocole_label' => 'Tipo di protocollo da verificare',
+       'option_url_type_protocole_mail' => 'Protocolli mail: imap, pop3 o smtp',
+       'option_url_type_protocole_tous' => 'Tutti i protocolli accettati',
+       'option_url_type_protocole_web' => 'Protocolli web: http o https',
+
+       // T
+       'type_couleur' => 'Couleur', # NEW
+       'type_couleur_description' => 'Vérifie que la valeur est un code couleur.', # NEW
+       'type_date' => 'Data',
+       'type_date_description' => 'Verifica che il valore sia una data nel formato GG/MM/AAAA. Il separatore è libero (";", "/", ecc).',
+       'type_decimal' => 'Numero decimale',
+       'type_decimal_description' => 'Verifica che il valore sia un numero decimale, con la possibilità di restringerlo ad un intervallo tra due valori e di specificare il numero di cifre decimali dopo la virgola.',
+       'type_email' => 'Indirizzo di posta elettronica',
+       'type_email_description' => 'Verifica che l\'indirizzo di posta abbia un formato corretto.',
+       'type_email_disponible' => 'Disponibilità di un indirizzo di posta elettronica',
+       'type_email_disponible_description' => 'Verifica che l\'indirizzo di posta elettronica non sia già utilizzato da un altro utente del sistema.',
+       'type_entier' => 'Numero intero',
+       'type_entier_description' => 'Verifica che il valore sia un numero intero, con la possibilità di restringerlo ad un intervallo tra due valori.',
+       'type_regex' => 'Espressione regolare',
+       'type_regex_description' => 'Verifica che il valore corrisponda alla maschera richiesta. Per l\'utilizzo delle maschere, riferisciti all\'<a href="http://it.php.net/manual/en/reference.pcre.pattern.syntax.php">aiuto in linea di PHP</a>.',
+       'type_siren_siret' => 'SIREN o SIRET',
+       'type_siren_siret_description' => 'Verifica che il valore sia un numero valido di <a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des ENtreprises</a> francese.',
+       'type_taille' => 'Dimensione',
+       'type_taille_description' => 'Verifica che la dimensione del valore corrisponda ad un minimo e/o ad un massimo richiesto.',
+       'type_telephone' => 'Numero telefonico',
+       'type_telephone_description' => 'Verifica che il numero telefonico corrisponda ad uno schema riconosciuto.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Verifica che l\'url corrisponda ad uno schema riconosciuto.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_pt_br.php b/www/plugins/verifier/lang/verifier_pt_br.php
new file mode 100644 (file)
index 0000000..d081291
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=pt_br
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Este Cep está incorreto.',
+       'erreur_comparaison_egal' => 'La valeur doit être égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_egal_type' => 'La valeur doit être égale et de même type que le champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand' => 'La valeur doit être supérieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_grand_egal' => 'La valeur doit être supérieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit' => 'La valeur doit être inférieure au champ "@nom_champ@"', # NEW
+       'erreur_comparaison_petit_egal' => 'La valeur doit être inférieure ou égale au champ "@nom_champ@"', # NEW
+       'erreur_couleur' => 'Le code couleur n\'est pas valide.', # NEW
+       'erreur_date' => 'A data não é válida.',
+       'erreur_date_format' => 'O formato da data não é aceitável.',
+       'erreur_decimal' => 'O valor deve ser um número decimal.',
+       'erreur_decimal_nb_decimales' => 'O número não deve ter mais de @nb_decimales@ algarismos depois da vírgula.',
+       'erreur_email' => 'O endereço de e-mail <em>@email@</em> não está num formato válido.',
+       'erreur_email_nondispo' => 'O endereço de e-mail <em>@email@</em> já está sendo usado.',
+       'erreur_entier' => 'O valor deve ser um número inteiro.',
+       'erreur_entier_entre' => 'O valor dever ser entre @min@ e @max@.',
+       'erreur_entier_max' => 'O valor deve ser inferior a @max@.',
+       'erreur_entier_min' => 'O valor deve ser superior a @min@.',
+       'erreur_heure' => 'L’horaire indiquée n’existe pas.', # NEW
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.', # NEW
+       'erreur_id_document' => 'Esta extensão de documento não é válida.',
+       'erreur_inconnue_generique' => 'Le format n\'est pas correct.', # NEW
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)', # NEW
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # NEW
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # NEW
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).', # NEW
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).', # NEW
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.', # NEW
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.', # NEW
+       'erreur_numerique' => 'O formato do número não é válido.',
+       'erreur_regex' => 'O formato da expressão não é válido.',
+       'erreur_siren' => 'O número SIREN não é válido.',
+       'erreur_siret' => 'O número SIRET não é válido.',
+       'erreur_taille_egal' => 'O valor deve ter exatamente @egal@ caracteres.', # MODIF
+       'erreur_taille_entre' => 'O valor deve ter entre @min@ e @max@ caracteres.', # MODIF
+       'erreur_taille_max' => 'O valor deve ter no máximo @max@ caracteres.', # MODIF
+       'erreur_taille_min' => 'O valor deve ter no mínimo @min@ caracteres.', # MODIF
+       'erreur_telephone' => 'O número não é válido.',
+       'erreur_url' => 'O endereço <em>@url@</em> não é válido.',
+       'erreur_url_protocole' => 'O endereço informado <em>(@url@)</em> deve começar com @protocole@',
+       'erreur_url_protocole_exact' => 'O endereço informado <em>(@url@)</em> não começa com um protocolo válido (http:// por exemplo)',
+
+       // N
+       'normaliser_option_date' => 'Normaliser la date ?', # NEW
+       'normaliser_option_date_aucune' => 'Non', # NEW
+       'normaliser_option_date_en_datetime' => 'Au format «Datetime» (pour SQL)', # NEW
+
+       // O
+       'option_couleur_normaliser_label' => 'Normaliser le code couleur ?', # NEW
+       'option_couleur_type_hexa' => 'Code couleur au format héxadécimal', # NEW
+       'option_couleur_type_label' => 'Type de vérification à effectuer', # NEW
+       'option_decimal_nb_decimales_label' => 'Número de décimais depois da vírgula',
+       'option_email_disponible_label' => 'Endereço disponível',
+       'option_email_disponible_label_case' => 'Verificar se o endereço já não está sendo utilizado por um usuário',
+       'option_email_mode_5322' => 'A verificação mais de acordo com os padrões disponíveis',
+       'option_email_mode_label' => 'Modo de verificação de e-mails',
+       'option_email_mode_normal' => 'Verificação normal do SPIP',
+       'option_email_mode_strict' => 'Verificação menos permissiva',
+       'option_entier_max_label' => 'Valor máximo',
+       'option_entier_min_label' => 'Valor mínimo',
+       'option_regex_modele_label' => 'O valor deve correspponder à máscara a seguir',
+       'option_siren_siret_mode_label' => 'O que você quer verificar?',
+       'option_siren_siret_mode_siren' => 'O número SIREN',
+       'option_siren_siret_mode_siret' => 'O número SIRET',
+       'option_taille_max_label' => 'Tamanho máximo',
+       'option_taille_min_label' => 'Tamanho mínimo',
+       'option_url_mode_complet' => 'Verificação completa de url',
+       'option_url_mode_label' => 'Modo de verificação de urls',
+       'option_url_mode_php_filter' => 'Verificação completa de url através do filtro FILTER_VALIDATE_URL do php',
+       'option_url_mode_protocole_seul' => 'Verificação apenas da presença de um protocolo',
+       'option_url_protocole_label' => 'Nome do protocolo a ser verificado',
+       'option_url_type_protocole_exact' => 'Informar um protocolo abaixo:',
+       'option_url_type_protocole_ftp' => 'Protocolos ftp: ftp ou sftp',
+       'option_url_type_protocole_label' => 'Tipo de protocolo a ser verificado',
+       'option_url_type_protocole_mail' => 'Protocolos de e-mail: imap, pop3 ou smtp',
+       'option_url_type_protocole_tous' => 'Todos os protocolos aceitos',
+       'option_url_type_protocole_web' => 'Protocolos web: http ou https',
+
+       // T
+       'type_couleur' => 'Couleur', # NEW
+       'type_couleur_description' => 'Vérifie que la valeur est un code couleur.', # NEW
+       'type_date' => 'Data',
+       'type_date_description' => 'Verifica se o valor é uma data no formato DD/MM/AAAA. O separador é livre (".", "/" etc).',
+       'type_decimal' => 'Número decimal',
+       'type_decimal_description' => 'Verifica se o valor é um número decimal, com a possibilidade de restringir entre dois valores e de especificar o número de decimais após a vírgula.',
+       'type_email' => 'Endereço de e-mail',
+       'type_email_description' => 'Verifica se o endereço de e-mail está num formato correto.',
+       'type_email_disponible' => 'Disponibilidade de um endereço de e-mail',
+       'type_email_disponible_description' => 'Verifica se o endereço de e-mail já está sendo utilizado por um outro usuário do sistema.',
+       'type_entier' => 'Número inteiro',
+       'type_entier_description' => 'Verifica se o valor é um número inteiro, com a possibilidade de restringir entre dois valores.',
+       'type_regex' => 'Expressão regular',
+       'type_regex_description' => 'Verifica se o valor corresponde à máscara solicitada. Para a utilização de máscaras, consulte <a href="http://fr2.php.net/manual/fr/reference.pcre.pattern.syntax.php">ajuda online do PHP</a>.',
+       'type_siren_siret' => 'SIREN ou SIRET',
+       'type_siren_siret_description' => 'Verifica se o valor é um número válido de <a href="http://fr.wikipedia.org/wiki/SIREN">sistema de identificação do cadastro de empresas (Système d’Identification du Répertoire des ENtreprises)</a> francês.',
+       'type_taille' => 'Tamanho',
+       'type_taille_description' => 'Verifica se o tamanho do valor corresponde ao mínimo e/ou ao máximo solicitado.',
+       'type_telephone' => 'Número de telefone',
+       'type_telephone_description' => 'Verifica se o número de telefone corresponde a um esquema reconhecido.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Verifica se o url corresponde a um esquema reconhecido.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_ru.php b/www/plugins/verifier/lang/verifier_ru.php
new file mode 100644 (file)
index 0000000..7f620a7
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Неправильный индекс',
+       'erreur_comparaison_egal' => 'Значение должно соответствовать полю "@nom_champ@"',
+       'erreur_comparaison_egal_type' => 'Значение должно соответствовать и быть такого же типа как поле "@nom_champ@"',
+       'erreur_comparaison_grand' => 'Значение должно быть больше чем поле "@nom_champ@"',
+       'erreur_comparaison_grand_egal' => 'Значение должно быть больше или соответствовать полю "@nom_champ@"',
+       'erreur_comparaison_petit' => 'Значаение должно быть меньше чем поле "@nom_champ@"',
+       'erreur_comparaison_petit_egal' => 'Значение должно быть меньшим или равным полю "@nom_champ@"',
+       'erreur_couleur' => 'Ошибка в коде цвета',
+       'erreur_date' => 'Неправильный формат даты.',
+       'erreur_date_format' => 'Неправильный формат даты.',
+       'erreur_decimal' => 'Число должно быть десятичным.',
+       'erreur_decimal_nb_decimales' => 'После запятой должно быть больше чем @nb_decimales@ значений',
+       'erreur_email' => 'Неправильный формат <em>@email@</em>.',
+       'erreur_email_nondispo' => '<em>@email@</em> уже используется.',
+       'erreur_entier' => 'Значение должно быть целым числом.',
+       'erreur_entier_entre' => 'Значение должно быть между @min@ и @max@.',
+       'erreur_entier_max' => 'Значение должно быть меньше @max@.',
+       'erreur_entier_min' => 'Значение должно быть больше чем @min@.',
+       'erreur_heure' => 'L’horaire indiquée n’existe pas.', # NEW
+       'erreur_heure_format' => 'Le format de l’heure n’est pas accepté.', # NEW
+       'erreur_id_document' => 'Ошибочный идентификатор документа.',
+       'erreur_inconnue_generique' => 'Неправильный формат.',
+       'erreur_isbn' => 'Le numéro ISBN n\'est pas valide (ex: 978-2-1234-5680-3 ou 2-1234-5680-X)', # NEW
+       'erreur_isbn_13_X' => 'Un numéro ISBN-13 ne peut pas se terminer par X.', # NEW
+       'erreur_isbn_G' => 'Le premier segment doit être égal à 978 ou 979.', # NEW
+       'erreur_isbn_nb_caracteres' => 'Le numéro ISBN doit comprendre 10 ou 13 caractères, sans compter les tirets (actuellement @nb@).', # NEW
+       'erreur_isbn_nb_segments' => 'Le numéro ISBN doit comprendre 4 ou 5 segments (actuellement @nb@).', # NEW
+       'erreur_isbn_segment' => 'Le segment "@segment@" comprend @nb@ chiffre(s) en trop.', # NEW
+       'erreur_isbn_segment_lettre' => 'Le segment "@segment@" ne doit pas contenir de lettre.', # NEW
+       'erreur_numerique' => 'Неправильный формат числа.',
+       'erreur_regex' => 'Неправильно сформированный regexp.',
+       'erreur_siren' => 'Значение SIREN ошибочно.',
+       'erreur_siret' => 'Значение SIRET ошибочно.',
+       'erreur_taille_egal' => 'Значение должно состоять строго из  @egal@ знаков.',
+       'erreur_taille_entre' => 'Значение должно иметь от @min@ до @max@ знаков.',
+       'erreur_taille_max' => 'Значение должно иметь не больше чем @max@ знаков.',
+       'erreur_taille_min' => 'Значение должно иметь не меньше чем @min@ знаков.',
+       'erreur_telephone' => 'Неверный номер телефона.',
+       'erreur_url' => 'Неверный URL адрес <em>@url@</em>',
+       'erreur_url_protocole' => 'Адрес <em>(@url@)</em> должен начинаться с @protocole@',
+       'erreur_url_protocole_exact' => 'Адрес <em>(@url@)</em> должен начинаться с протокола  (например http:// )',
+
+       // N
+       'normaliser_option_date' => 'Упорядочить дату?',
+       'normaliser_option_date_aucune' => 'Нет',
+       'normaliser_option_date_en_datetime' => 'Формат даты и времени (для SQL)',
+
+       // O
+       'option_couleur_normaliser_label' => 'Упорядочить цвет?',
+       'option_couleur_type_hexa' => 'Код цвета в шестнадцатеричном формате ',
+       'option_couleur_type_label' => 'Тип проверки',
+       'option_decimal_nb_decimales_label' => 'Количество символов после запятой.',
+       'option_email_disponible_label' => 'Доступный адрес',
+       'option_email_disponible_label_case' => 'Проверить использовался ли адрес другим пользователем.',
+       'option_email_mode_5322' => 'Проверить по строгим стандартам.',
+       'option_email_mode_label' => 'Режим проверки электронной почты.',
+       'option_email_mode_normal' => 'Стандартная проверка SPIP',
+       'option_email_mode_strict' => 'Не строгая проверка.',
+       'option_entier_max_label' => 'Максимальное значение',
+       'option_entier_min_label' => 'Минимальное значение',
+       'option_regex_modele_label' => 'Значение должно соответствовать следующему выражению',
+       'option_siren_siret_mode_label' => 'Что вы будете проверять?',
+       'option_siren_siret_mode_siren' => 'SIREN номер',
+       'option_siren_siret_mode_siret' => 'SIRET номер',
+       'option_taille_max_label' => 'Максимальный размер ',
+       'option_taille_min_label' => 'Минимальный размер',
+       'option_url_mode_complet' => 'Полная проверка URL',
+       'option_url_mode_label' => 'Режим проверки URL',
+       'option_url_mode_php_filter' => 'Полная проверка валидации URL  с помощью PHP фильтра FILTER_VALIDATE_URL',
+       'option_url_mode_protocole_seul' => 'Проверка на существование протокола',
+       'option_url_protocole_label' => 'Название протокола, который нужно проверить',
+       'option_url_type_protocole_exact' => 'Введите названия протокола:',
+       'option_url_type_protocole_ftp' => 'Протоколы передачи файлов: FTP or SFTP',
+       'option_url_type_protocole_label' => 'Тип протокола для проверки',
+       'option_url_type_protocole_mail' => 'Почтовые протоколы : imap, pop3 ou smtp',
+       'option_url_type_protocole_tous' => 'Все доступные протоколы',
+       'option_url_type_protocole_web' => 'Интернет протоколы : http или https',
+
+       // T
+       'type_couleur' => 'Цвет',
+       'type_couleur_description' => 'Проверить является ли информация цветовым кодом',
+       'type_date' => 'Дата',
+       'type_date_description' => 'Проверить является ли формат даты ДД/ММ/ГГГГ. Разделитель может быть произвольным (".", "/", и т.д.).',
+       'type_decimal' => 'Десятичное число',
+       'type_decimal_description' => 'Проверить является ли значение десятичным числом, с целью определить количество знаков после запятой.',
+       'type_email' => 'Электронная почта',
+       'type_email_description' => 'Проверить корректность формата электронной почты.',
+       'type_email_disponible' => 'Доступность электронной почты',
+       'type_email_disponible_description' => 'Проверить не использовалась ли электронная почта другим пользователем.',
+       'type_entier' => 'Целое число',
+       'type_entier_description' => 'Проверить является ли число целым.',
+       'type_regex' => 'Регулярное выражение',
+       'type_regex_description' => 'Проверить совместимость значения и выражения. Для подробной информации о  регулярных выражениях обратитесь по адресу <a href="http://fr2.php.net/manual/en/reference.pcre.pattern.syntax.php">the online PHP help</a>.',
+       'type_siren_siret' => 'SIREN или SIRET',
+       'type_siren_siret_description' => 'Проверить валидность с французского языка <a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des ENtreprises</a> (Company Registry ID System).',
+       'type_taille' => 'Размер',
+       'type_taille_description' => 'Проверить лежит ли значение параметра в диапазоне минимального и максимального значения.',
+       'type_telephone' => 'Номер телефона',
+       'type_telephone_description' => 'Проверить соответствует ли номер телефона формату ввода.',
+       'type_url' => 'URL',
+       'type_url_description' => 'Проверить соответствие ли URL  формат ввода.'
+);
+
+?>
diff --git a/www/plugins/verifier/lang/verifier_sk.php b/www/plugins/verifier/lang/verifier_sk.php
new file mode 100644 (file)
index 0000000..6b8ce9f
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/verifier?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // E
+       'erreur_code_postal' => 'Toto PSČ je neplatné.',
+       'erreur_comparaison_egal' => 'Hodnota sa musí zhodovať s poľom "@nom_champ@"',
+       'erreur_comparaison_egal_type' => 'Hodnota musí sa musí zhodovať s poľom "@nom_champ@" a musí byť rovnakého typu',
+       'erreur_comparaison_grand' => 'Hodnota musí byť väčšia ako pole "@nom_champ@"',
+       'erreur_comparaison_grand_egal' => 'Hodnota musí byť väčšia alebo rovná poľu "@nom_champ@"',
+       'erreur_comparaison_petit' => 'Hodnota musí byť menšia ako pole "@nom_champ@"',
+       'erreur_comparaison_petit_egal' => 'Hodnota musí byť menšia alebo rovná ako "@nom_champ@"',
+       'erreur_couleur' => 'Kód farby nie je platný.',
+       'erreur_date' => 'Tento dátum je neplatný.',
+       'erreur_date_format' => 'Formát dátumu je neplatný.',
+       'erreur_decimal' => 'Hodnota musí byť desatinné číslo.',
+       'erreur_decimal_nb_decimales' => 'Číslo musí mať po desatinnej čiarke viac ako @nb_decimales@ miest.',
+       'erreur_email' => 'E-mailová adresa <em>@email@</em> nemá  správny formát.',
+       'erreur_email_nondispo' => 'E-mailová adresa <em>@email@</em> sa už používa.',
+       'erreur_entier' => 'Hodnota musí byť celé číslo.',
+       'erreur_entier_entre' => 'Hodnota musí byť medzi @min@ a @max@.',
+       'erreur_entier_max' => 'Hodnota musí byť menšia ako @max@.',
+       'erreur_entier_min' => 'Hodnota musí byť väčšia ako @min@.',
+       'erreur_heure' => 'Zadaný čas neexistuje.',
+       'erreur_heure_format' => 'Formát času, ktorý ste zadali, nie je akceptovaný.',
+       'erreur_id_document' => 'Tento identifikátor dokumentu nie je platný.',
+       'erreur_inconnue_generique' => 'Formát nie je správny.',
+       'erreur_isbn' => 'Číslo ISBN nie je platné (napr. 978-2-1234-5680-3 alebo 2-1234-5680-X)',
+       'erreur_isbn_13_X' => 'Číslo ISBN-13 sa nemôže končiť písmenom X.',
+       'erreur_isbn_G' => 'Musí sa začínať číslami 978 alebo 979.',
+       'erreur_isbn_nb_caracteres' => 'Číslo ISBN musí mať 10 alebo 13 znakov okrem spojovníkov (teraz má @nb@).',
+       'erreur_isbn_nb_segments' => 'Číslo ISBN musí mať 4 alebo 5 skupín číslic (teraz má @nb@).',
+       'erreur_isbn_segment' => 'V skupine "@segment@" je naviac @nb@ číslo/čísel.',
+       'erreur_isbn_segment_lettre' => 'V skupine "@segment@" nesmie byť žiadne písmeno.',
+       'erreur_numerique' => 'Formát čísla je neplatný.',
+       'erreur_regex' => 'Reťazec pravidelného výrazu má nesprávny formát.',
+       'erreur_siren' => 'IČO je neplatné.',
+       'erreur_siret' => 'Obchodné meno s IČOm je neplatné.',
+       'erreur_taille_egal' => 'Údaj musí mať presne @egal@ znakov (teraz má @nb@).',
+       'erreur_taille_entre' => 'Údaj musí mať medzi @min@ a @max@ znakov (teraz má @nb@). ',
+       'erreur_taille_max' => 'Údaj nesmie mať menej ako @max@ znakov (teraz má @nb@).',
+       'erreur_taille_min' => 'Údaj nesmie mať menej ako @min@ znakov (teraz má @nb@).',
+       'erreur_telephone' => 'Telefónne číslo je neplatné.',
+       'erreur_url' => 'Internetová adresa <em>@url@</em> je neplatná.',
+       'erreur_url_protocole' => 'Zadaná adresa <em>(@url@)</em> sa musí začínať s @protocole@',
+       'erreur_url_protocole_exact' => 'Zadaná adresa <em>(@url@)</em> sa nezačína s platným protokolom (napr. http://)',
+
+       // N
+       'normaliser_option_date' => 'Štandardizovať dátum?',
+       'normaliser_option_date_aucune' => 'Nie',
+       'normaliser_option_date_en_datetime' => 'Vo formáte "Dátum a čas" (pre SQL)',
+
+       // O
+       'option_couleur_normaliser_label' => 'Štandardizovať kód farby?',
+       'option_couleur_type_hexa' => 'Kód farby v hexadecimálnom (šetnástkovom) formáte',
+       'option_couleur_type_label' => 'Typ overenia, ktorý sa má použiť',
+       'option_decimal_nb_decimales_label' => 'Počet desatinných miest',
+       'option_email_disponible_label' => 'Dostupná adresa',
+       'option_email_disponible_label_case' => 'Skontrolujte, či túto adresu už nepoužíva iný používateľ',
+       'option_email_mode_5322' => 'Skontrolovať podľa najprísnejších dostupných štandardov',
+       'option_email_mode_label' => 'Režim kontroly e-mailov',
+       'option_email_mode_normal' => 'Normálna kontrola SPIPu',
+       'option_email_mode_strict' => 'Prísnejšia kontrola',
+       'option_entier_max_label' => 'Maximálna hodnota',
+       'option_entier_min_label' => 'Minimálna hodnota',
+       'option_regex_modele_label' => 'Hodnota sa musí zhodovať s týmto výrazom',
+       'option_siren_siret_mode_label' => 'Určite to chcete potvrdiť?',
+       'option_siren_siret_mode_siren' => 'IČO',
+       'option_siren_siret_mode_siret' => 'IČO a obchodné meno',
+       'option_taille_max_label' => 'Maximálna veľkosť',
+       'option_taille_min_label' => 'Minimálna veľkosť',
+       'option_url_mode_complet' => 'Úplné overenie internetovej adresy',
+       'option_url_mode_label' => 'Režim overenia internetovej adresy',
+       'option_url_mode_php_filter' => 'Úplné overenie internetovej adresy pomocou PHP filtra FILTER_VALIDATE_URL',
+       'option_url_mode_protocole_seul' => 'Iba overenie existencie protokolu',
+       'option_url_protocole_label' => 'Názov protokolu, ktorý treba overiť',
+       'option_url_type_protocole_exact' => 'Zadajte protokol:',
+       'option_url_type_protocole_ftp' => 'Protokoly na prenos súborov: FTP alebo SFTP',
+       'option_url_type_protocole_label' => 'Typ protokolu, ktorý treba overiť',
+       'option_url_type_protocole_mail' => 'E-mailové protokoly: IMAP, POP3 alebo SMTP',
+       'option_url_type_protocole_tous' => 'Všetky akceptované protokoly',
+       'option_url_type_protocole_web' => 'Internetové protokoly: HTTP alebo HTTPS',
+
+       // T
+       'type_couleur' => 'Farba',
+       'type_couleur_description' => 'Skontroluje, či je hodnota zadaný kód farby.',
+       'type_date' => 'Dátum',
+       'type_date_description' => 'Skontrolujte, či je dátum vo formáte DD/MM/RRRR. Oddeľovacím znakom môže byť čokoľvek (napr. ".", "/").',
+       'type_decimal' => 'Desatinné číslo',
+       'type_decimal_description' => 'Skontroluje, či je zadané desatinné číslo s možnosťou obmedziť jeho hodnotu určitým rozsahom a určiť počet desatinných miest.',
+       'type_email' => 'E-mailová adresa',
+       'type_email_description' => 'Skontrolujte, či má e-mailová adresa správnu podobu.',
+       'type_email_disponible' => 'Dostupnosť e-mailovej adresy',
+       'type_email_disponible_description' => 'Skontrolujte, či e-mailovú adresu už nepoužíva iný používateľ systému.',
+       'type_entier' => 'Celé číslo',
+       'type_entier_description' => 'Skontroluje, či je hodnotou celé číslo s možnosťou obmedziť ju dvoma hraničnými hodnotami.',
+       'type_regex' => 'Pravidelný výraz',
+       'type_regex_description' => 'Skontrolujte, že hodnota sa zhoduje so zadaným výrazom. Viac informácií o používaní pravidelných výrazov nájdete v <a href="http://fr2.php.net/manual/en/reference.pcre.pattern.syntax.php">internetovompomocníkovi k PHP.</a>',
+       'type_siren_siret' => 'IČO alebo IČO a obchodné meno',
+       'type_siren_siret_description' => 'Skontroluje, že hodnota je platné číslo z Fracúzskeho<a href="http://fr.wikipedia.org/wiki/SIREN">Système d’Identification du Répertoire des ENtreprises</a> (Obchodný register).',
+       'type_taille' => 'Veľkosť',
+       'type_taille_description' => 'Skontroluje, že veľkosť hodnoty zodpovedá určenej minimálnej a/lebo maximálnej hodnote.',
+       'type_telephone' => 'Telefónne číslo',
+       'type_telephone_description' => 'Skontroluje, či sa telefónne číslo zhoduje s rozoznávaným formátom telefónnych čísel.',
+       'type_url' => 'Internetová adresa',
+       'type_url_description' => 'Overí, či sa internetová adresa zhoduje s rozoznávaným formátom.'
+);
+
+?>
diff --git a/www/plugins/verifier/paquet.xml b/www/plugins/verifier/paquet.xml
new file mode 100644 (file)
index 0000000..e035ddc
--- /dev/null
@@ -0,0 +1,23 @@
+<paquet\r
+       prefix="verifier"\r
+       categorie="outil"\r
+       version="1.0.3"\r
+       etat="test"\r
+       compatibilite="[2.0.10;3.0.*]"\r
+       logo="images/verifier-128.png"\r
+       documentation="http://www.spip-contrib.net/Verifier,1505"\r
+>\r
+\r
+       <nom>API de v&#233;rification</nom>\r
+       <!-- Une API générique pour vérifier une valeur -->\r
+\r
+       <auteur lien="http://www.ldd.fr">Les Développements Durables</auteur>\r
+\r
+       <licence lien="http://www.gnu.org/licenses/gpl-3.0.html">GPL 3</licence>\r
+\r
+       <traduire module="verifier" reference="fr" gestionnaire="salvatore" />\r
+\r
+       <pipeline nom="verifier" action="" />\r
+\r
+       <utilise nom="yaml" />\r
+</paquet>\r
diff --git a/www/plugins/verifier/plugin.xml b/www/plugins/verifier/plugin.xml
new file mode 100644 (file)
index 0000000..f6c9ee4
--- /dev/null
@@ -0,0 +1,31 @@
+<plugin>\r
+       <nom>\r
+               <multi>\r
+                       [fr]API de v&#233;rification\r
+                       [en]Control API\r
+               </multi>\r
+       </nom>\r
+       <slogan>Une API g&#233;n&#233;rique pour v&#233;rifier une valeur</slogan>\r
+       <auteur>[Les Développements Durables->http://www.ldd.fr]</auteur>\r
+       <icon>images/verifier-128.png</icon>\r
+       <licence>GPL v3</licence>\r
+       <version>1.0.3</version>\r
+       <etat>test</etat>\r
+       <description>\r
+               <multi>\r
+                       [fr]Fournit une fonction unique <code>verifier($valeur, $type, $options, &$valeur_normalisee)</code> permettant de tester la validit&#233; d'une valeur.\r
+                       [en]Provides a unique function <code>verifier($value, $type, $options, &$valeur_normalisee)</code> to test the validity of a value.\r
+               </multi>\r
+       </description>\r
+       <prefix>verifier</prefix>\r
+       <lien>http://www.spip-contrib.net/Verifier,1505</lien>\r
+       <pipeline>\r
+               <nom>verifier</nom>\r
+               <action></action>\r
+       </pipeline>\r
+       <necessite id="SPIP" version="[2.0.10;3.0.99]" />\r
+       <utilise id="yaml" />   \r
+       <categorie>outil</categorie>\r
+       <traduire gestionnaire="salvatore" module="verifier" reference="fr" />\r
+</plugin>\r
+\r
diff --git a/www/plugins/verifier/svn.revision b/www/plugins/verifier/svn.revision
new file mode 100644 (file)
index 0000000..3c5491d
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/verifier
+Revision: 73345
+Dernier commit: 2013-06-07 12:42:13 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/verifier</origine>
+<revision>73345</revision>
+<commit>2013-06-07 12:42:13 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/verifier/test/verifier.html b/www/plugins/verifier/test/verifier.html
new file mode 100644 (file)
index 0000000..663ba96
--- /dev/null
@@ -0,0 +1,260 @@
+<html>\r
+<body>\r
+<h1>Test de vérification de valeurs</h1>\r
+\r
+<h2>Vérifions qu'un mot est un mot :</h2>\r
+<pre>\r
+<?php\r
+\r
+$verifier = charger_fonction('verifier','inc');\r
+\r
+$un_mot = "poli4_EFSdq89";\r
+$un_autre_mot = "aqe  edioj o^";\r
+$modele = "/^[\w]+$/";\r
+\r
+echo "Modèle => $modele\n\n";\r
+echo "'$un_mot' ?";\r
+var_dump($verifier($un_mot, 'regex', array('modele'=>$modele)));\r
+echo "'$un_autre_mot' ?";\r
+var_dump($verifier($un_autre_mot, 'regex', array('modele'=>$modele)));\r
+\r
+?>\r
+</pre>\r
+\r
+<h2>Vérifions des entiers :</h2>\r
+<pre>\r
+<?php\r
+\r
+$un_entier = 568;\r
+$un_autre_entier = "-89";\r
+\r
+echo "$un_entier entre 0 et 1000 ?";\r
+var_dump($verifier($un_entier, 'entier', array('min'=>0, 'max'=>1000)));\r
+echo "$un_entier < 100 ?";\r
+var_dump($verifier($un_entier, 'entier', array('max'=>100)));\r
+echo "$un_autre_entier est positif ?";\r
+var_dump($verifier($un_autre_entier, 'entier', array('min'=>0)));\r
+echo "$un_autre_entier entre -100 et -50 ?";\r
+var_dump($verifier($un_autre_entier, 'entier', array('min'=>-100, 'max'=>-50)));\r
+\r
+?>\r
+</pre>\r
+\r
+<h2>V&eacute;rifions une taille d'une cha&icirc;ne :</h2>\r
+<pre>\r
+<?php\r
+\r
+$une_chaine = "123456";\r
+$un_autre_chaine = "abc";\r
+\r
+echo "$une_chaine de 1 à 3 caractères ?";\r
+var_dump($verifier($une_chaine, 'taille', array('min'=>1, 'max'=>3)));\r
+echo "$une_chaine 5 caractères max ?";\r
+var_dump($verifier($une_chaine, 'taille', array('max'=>5)));\r
+echo "$une_chaine 4 caractères mini ?";\r
+var_dump($verifier($une_chaine, 'taille', array('min'=>4)));\r
+echo "$un_autre_chaine de 1 à 3 caractères ?";\r
+var_dump($verifier($un_autre_chaine, 'taille', array('min'=>1, 'max'=>3)));\r
+echo "$un_autre_chaine 5 caractères max ?";\r
+var_dump($verifier($un_autre_chaine, 'taille', array('max'=>5)));\r
+echo "$un_autre_chaine 4 caractères mini ?";\r
+var_dump($verifier($un_autre_chaine, 'taille', array('min'=>4)));\r
+echo "$une_chaine de 3 caractères ?";\r
+var_dump($verifier($une_chaine, 'taille', array('egal'=>3)));\r
+echo "$un_autre_chaine de 3 caractères ?";\r
+var_dump($verifier($un_autre_chaine, 'taille', array('egal'=>3)));\r
+\r
+?>\r
+</pre>\r
+\r
+\r
+<h2>Vérifions des emails :</h2>\r
+<pre>\r
+<?php\r
+\r
+$email = "test@test.fr";\r
+$email2 = "test@b";\r
+$email3 = "test";\r
+\r
+echo "Valide SPIP : $email ?";\r
+var_dump($verifier($email, 'email'));\r
+echo "Valide SPIP : $email2 ?";\r
+var_dump($verifier($email2, 'email'));\r
+echo "Valide SPIP : $email3 ?";\r
+var_dump($verifier($email3, 'email'));\r
+\r
+echo "Valide Strict : $email ?";\r
+var_dump($verifier($email, 'email',array('mode'=>'strict')));\r
+echo "Valide Strict : $email2 ?";\r
+var_dump($verifier($email2, 'email',array('mode'=>'strict')));\r
+echo "Valide Strict : $email3 ?";\r
+var_dump($verifier($email3, 'email',array('mode'=>'strict')));\r
+\r
+\r
+?>\r
+</pre>\r
+\r
+<h2>Vérifions des téléphones :</h2>\r
+<pre>\r
+<?php\r
+\r
+$telephone = "01.01/01-02 03";\r
+$telephone2 = "090909";\r
+$telephone3 = "10 01 01 01 01";\r
+\r
+echo "Téléphone : $telephone ?";\r
+var_dump($verifier($telephone, 'telephone_fr'));\r
+echo "Téléphone : $telephone2 ?";\r
+var_dump($verifier($telephone2, 'telephone_fr'));\r
+echo "Téléphone : $telephone3 ?";\r
+var_dump($verifier($telephone3, 'telephone_fr'));\r
+\r
+\r
+?>\r
+</pre>\r
+\r
+\r
+<h2>Vérifions des SIREN/SIRET :</h2>\r
+<pre>\r
+<?php\r
+\r
+$siren_valide = "321227852";\r
+$siren_non_valide = "321227822";\r
+$siret_valide = "32122785200019";\r
+$siret_non_valide = "32122785200033";\r
+\r
+echo "SIREN : $siren_valide ?";\r
+var_dump($verifier($siren_valide, 'siren_siret'));\r
+echo "SIREN : $siren_non_valide ?";\r
+var_dump($verifier($siren_non_valide, 'siren_siret'));\r
+\r
+echo "SIRET : $siret_valide ?";\r
+var_dump($verifier($siret_valide, 'siren_siret',array('mode'=>'siret')));\r
+echo "SIRET : $siret_non_valide ?";\r
+var_dump($verifier($siret_non_valide, 'siren_siret',array('mode'=>'siret')));\r
+?>\r
+</pre>\r
+\r
+<h2>Vérifions des DATES :</h2>\r
+<pre>\r
+<?php\r
+$date_valide = "30-01-2009";\r
+$date_non_valide = "321227822";\r
+$date_non_valide2 = "29-02-2011";\r
+$date_valide2 = "29-02-2012";\r
+\r
+echo "Date JJ/MM/AAAA (avec séparateur /.-) : $date_valide ?";\r
+var_dump($verifier($date_valide, 'date'));\r
+echo "Date JJ/MM/AAAA : $date_non_valide ?";\r
+var_dump($verifier($date_non_valide, 'date'));\r
+echo "Date JJ/MM/AAAA : $date_non_valide2 ?";\r
+var_dump($verifier($date_non_valide2, 'date'));\r
+echo "Date JJ/MM/AAAA : $date_valide2 ?";\r
+var_dump($verifier($date_valide2, 'date'));\r
+?>\r
+</pre>\r
+\r
+<h2>Vérifions des URL :</h2>\r
+<pre>\r
+<?php\r
+\r
+// Bon c'est pas terrible tout ce code... Faut revoir ca avec le plugin test builder\r
+$url_web_valide1 = "Http://www.domaine.tld";\r
+$url_web_valide2 = "https://www.Domaine.tld";\r
+$url_ftp_valide = "sftp://www.domaine.tld";\r
+$url_mail_valide = "pop3://www.domaine.tld";\r
+$url_exact_valide = "ssh://www.domaine.tld";\r
+$url_tous_valide = "rtsp://www.domaine.tld";\r
+\r
+echo "protocole_seul : url_web_valide1 : $url_web_valide1 ?";\r
+var_dump($verifier($url_web_valide1, 'url', array('mode'=>'protocole_seul','type_protocole'=>'web')));\r
+echo "protocole_seul : url_web_valide2 : $url_web_valide2 ?";\r
+var_dump($verifier($url_web_valide2, 'url', array('mode'=>'protocole_seul','type_protocole'=>'web')));\r
+echo "protocole_seul : url_ftp_valide : $url_ftp_valide ?";\r
+var_dump($verifier($url_ftp_valide, 'url', array('mode'=>'protocole_seul','type_protocole'=>'ftp')));\r
+echo "protocole_seul : url_mail_valide : $url_mail_valide ?";\r
+var_dump($verifier($url_mail_valide, 'url', array('mode'=>'protocole_seul','type_protocole'=>'mail')));\r
+echo "protocole_seul : url_exact_valide : $url_exact_valide ?";\r
+var_dump($verifier($url_exact_valide, 'url', array('mode'=>'protocole_seul','type_protocole'=>'exact','protocole'=>'ssh')));\r
+echo "protocole_seul : url_tous_valide : $url_tous_valide ?";\r
+var_dump($verifier($url_tous_valide, 'url', array('mode'=>'protocole_seul','type_protocole'=>'tous')));\r
+\r
+$url_web_invalide1 = "htpp://www.domaine.tld";\r
+$url_web_invalide2 = "http:/www.domaine.tld";\r
+$url_web_invalide3 = "ftp://www.domaine.tld";\r
+\r
+echo "protocole_seul : url_web_invalide1 : $url_web_invalide1 ?";\r
+var_dump($verifier($url_web_invalide1, 'url', array('mode'=>'protocole_seul','type_protocole'=>'web')));\r
+echo "protocole_seul : url_web_invalide2 : $url_web_invalide2 ?";\r
+var_dump($verifier($url_web_invalide2, 'url', array('mode'=>'protocole_seul','type_protocole'=>'web')));\r
+echo "protocole_seul : url_web_invalide3 : $url_web_invalide3 ?";\r
+var_dump($verifier($url_web_invalide3, 'url', array('mode'=>'protocole_seul','type_protocole'=>'web')));\r
+\r
+$url_web_valide1 = "http://www.domaine.co.tld";\r
+$url_web_valide2 = "http://www.domaine.tld/repertoire";\r
+$url_web_valide3 = "http://www.DOMAINE.tld/repertoire";\r
+$url_web_valide4 = "http://www.domaine.tld/fichier%20.html";\r
+$url_web_valide5 = "http://www.domaine.tld/fichier.html#ancre";\r
+$url_web_valide6 = "http://www.domaine.tld/spip.php?page=test/verifier&toto=1";\r
+$url_web_valide7 = "http://www.domaine.tld/Presentation,432.html";\r
+$url_web_valide8 = "http://toto:t8_&$!@192.168.0.1:8000";\r
+$url_web_invalide1 = "http://www.domaïne.tld";\r
+$url_web_invalide2 = "http://www.domaine.tld\toto";\r
+$url_web_invalide3 = "http://www.domaine.tld/toto titi";\r
+\r
+\r
+echo "complet : url_web_valide1 : $url_web_valide1 ?";\r
+var_dump($verifier($url_web_valide1, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_valide2 : $url_web_valide2 ?";\r
+var_dump($verifier($url_web_valide2, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_valide3 : $url_web_valide3 ?";\r
+var_dump($verifier($url_web_valide3, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_valide4 : $url_web_valide4 ?";\r
+var_dump($verifier($url_web_valide4, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_valide5 : $url_web_valide5 ?";\r
+var_dump($verifier($url_web_valide5, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_valide6 : $url_web_valide6 ?";\r
+var_dump($verifier($url_web_valide6, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_valide7 : $url_web_valide7 ?";\r
+var_dump($verifier($url_web_valide7, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_valide8 : $url_web_valide8 ?";\r
+var_dump($verifier($url_web_valide8, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+\r
+echo "complet : url_web_invalide1 : $url_web_invalide1 ?";\r
+var_dump($verifier($url_web_invalide1, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_invalide2 : $url_web_invalide2 ?";\r
+var_dump($verifier($url_web_invalide2, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+echo "complet : url_web_invalide3 : $url_web_invalide3 ?";\r
+var_dump($verifier($url_web_invalide3, 'url', array('mode'=>'complet','type_protocole'=>'web')));\r
+\r
+\r
+echo "php_filter : url_web_valide1 : $url_web_valide1 ?";\r
+var_dump($verifier($url_web_valide1, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_valide2 : $url_web_valide2 ?";\r
+var_dump($verifier($url_web_valide2, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_valide3 : $url_web_valide3 ?";\r
+var_dump($verifier($url_web_valide3, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_valide4 : $url_web_valide4 ?";\r
+var_dump($verifier($url_web_valide4, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_valide5 : $url_web_valide5 ?";\r
+var_dump($verifier($url_web_valide5, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_valide6 : $url_web_valide6 ?";\r
+var_dump($verifier($url_web_valide6, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_valide7 : $url_web_valide7 ?";\r
+var_dump($verifier($url_web_valide7, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_valide8 : $url_web_valide8 ?";\r
+var_dump($verifier($url_web_valide8, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+\r
+echo "php_filter : url_web_invalide1 : $url_web_invalide1 ?";\r
+var_dump($verifier($url_web_invalide1, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_invalide2 : $url_web_invalide2 ?";\r
+var_dump($verifier($url_web_invalide2, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+echo "php_filter : url_web_invalide3 : $url_web_invalide3 ?";\r
+var_dump($verifier($url_web_invalide3, 'url', array('mode'=>'php_filter','type_protocole'=>'web')));\r
+\r
+?>\r
+</pre>\r
+\r
+\r
+</body>\r
+</html>\r
diff --git a/www/plugins/verifier/verifier/code_postal.php b/www/plugins/verifier/verifier/code_postal.php
new file mode 100644 (file)
index 0000000..90705cf
--- /dev/null
@@ -0,0 +1,63 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Un code postal francais est compose de 5 chiffres
+ * http://fr.wikipedia.org/wiki/Code_postal_en_France
+ * a completer pour d'autre pays
+ * 
+ * cf : http://fr.wikipedia.org/wiki/Codes_postaux
+ * 
+ * La regexp par défaut doit valider toutes les possibilités
+ * -* combinaisons de chiffres et de lettres et aussi tiret
+ * -* notations internationales cf : http://en.wikipedia.org/wiki/List_of_postal_codes#On_the_use_of_country_codes
+ * 
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   pays => code pays
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_code_postal_dist($valeur, $options=array()){
+       $erreur = _T('verifier:erreur_code_postal');
+       if (!is_string($valeur))
+               return $erreur;
+
+       $ok = '';
+       switch ($options['pays']){
+               case 'FR':
+                       if (!preg_match(",^((0[1-9])|([1-8][0-9])|(9[0-8]))[0-9]{3}$,", $valeur))
+                               return $erreur;
+                       break;
+               case 'DZ':// Algérie
+               case 'DE':// Allemagne
+               case 'BY':// Bielorussie
+               case 'BA':// Bosnie Herzégovine
+               case 'HR':// Croatie
+               case 'ES':// Espagne
+               case 'FI':// Finlande
+               case 'GT':// Guatemala
+               case 'IT':// Italie
+               case 'LT':// Lituanie
+               case 'MY':// Malaisie
+               case 'MA':// Maroc
+               case 'MX':// Mexique
+               case 'ME':// Montenegro
+               case 'LK':// Sri lanka
+               case 'MX':// Mexique
+               case 'UA':// Ukraine
+                       // 5 chiffres
+                       if (!preg_match(",^[0-9]{5}$,", $valeur))
+                               return $erreur;
+                       break;
+               default:
+                       if (!preg_match('/^[A-Z]{1,2}[-|\s][0-9]{3,6}$|^[0-9]{3,6}$|^[0-9|A-Z]{2,5}[-|\s][0-9|A-Z]{2,4}$|^[A-Z]{1,2} [0-9|A-Z]{2,5}[-|\s][0-9|A-Z]{2,4}/i',$valeur))
+                               return $erreur;
+                       break;
+       }
+
+       return $ok;
+}
diff --git a/www/plugins/verifier/verifier/comparaison_champ.php b/www/plugins/verifier/verifier/comparaison_champ.php
new file mode 100644 (file)
index 0000000..d04e34a
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Compare la valeur avec un autre champ du _request().
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   Un éventuel tableau d'options.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_comparaison_champ_dist($valeur, $options=array()){
+       include_spip('inc/filtres');
+       
+       // On vérifie qu'on a bien un champ à comparer
+       if (!$champ = $options['champ'] or !is_scalar($champ)) return true;
+       else $valeur_champ = _request($champ);
+       
+       // On cherche le nom du champ
+       $nom_champ = $options['nom_champ'] ? $options['nom_champ'] : $champ;
+       
+       switch ($options['comparaison']){
+               case 'petit':
+                       return $valeur < $valeur_champ ? '' : _T('verifier:erreur_comparaison_petit', array('nom_champ'=>$nom_champ));
+                       break;
+               case 'petit_egal':
+                       return $valeur <= $valeur_champ ? '' : _T('verifier:erreur_comparaison_petit_egal', array('nom_champ'=>$nom_champ));
+                       break;
+               case 'grand':
+                       return $valeur > $valeur_champ ? '' : _T('verifier:erreur_comparaison_grand', array('nom_champ'=>$nom_champ));
+                       break;
+               case 'grand_egal':
+                       return $valeur >= $valeur_champ ? '' : _T('verifier:erreur_comparaison_grand_egal', array('nom_champ'=>$nom_champ));
+                       break;
+               case 'egal_type':
+                       return $valeur === $valeur_champ ? '' : _T('verifier:erreur_comparaison_egal_type', array('nom_champ'=>$nom_champ));
+                       break;
+               default:
+                       return $valeur == $valeur_champ ? '' : _T('verifier:erreur_comparaison_egal', array('nom_champ'=>$nom_champ));
+                       break;
+       }
+}
+
diff --git a/www/plugins/verifier/verifier/couleur.php b/www/plugins/verifier/verifier/couleur.php
new file mode 100644 (file)
index 0000000..2445392
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifie la validité d'un code couleur
+ * 
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   type => hexa,...
+ *   normaliser => oui ou rien
+ * @param null $valeur_normalisee
+ *   Si normalisation a faire, la variable sera rempli par la couleur normalisee.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_couleur_dist($valeur, $options=array(), &$valeur_normalisee=null){
+       $erreur = _T('verifier:erreur_couleur');
+       if (!is_string($valeur))
+               return $erreur;
+
+       $ok = '';
+       switch ($options['type']){
+               case 'hexa':
+               default:
+                       if (!preg_match(",^#[a-f0-9]{6}$,i", $valeur))
+                               if (isset($options['normaliser']) and preg_match(",^[a-f0-9]{6}$,i", $valeur))
+                                       $valeur_normalisee = "#".$valeur ;
+                               else
+                                       return $erreur;
+                       break;
+       }
+
+       return $ok;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/verifier/verifier/couleur.yaml b/www/plugins/verifier/verifier/couleur.yaml
new file mode 100644 (file)
index 0000000..f20e507
--- /dev/null
@@ -0,0 +1,18 @@
+\r
+titre: '<:verifier:type_couleur:>'\r
+description: '<:verifier:type_couleur_description:>'\r
+options:\r
+  -\r
+    saisie: 'radio'\r
+    options:\r
+      nom: 'type'\r
+      label: '<:verifier:option_couleur_type_label:>'\r
+      datas:\r
+        hexa: '<:verifier:option_couleur_type_hexa:>'\r
+      defaut: 'hexa'\r
+  -\r
+    saisie: 'oui_non'\r
+    options:\r
+      nom: 'normaliser'\r
+      label: '<:verifier:option_couleur_normaliser_label:>'\r
+      defaut: ''\r
diff --git a/www/plugins/verifier/verifier/date.php b/www/plugins/verifier/verifier/date.php
new file mode 100644 (file)
index 0000000..d4d081d
--- /dev/null
@@ -0,0 +1,142 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Une date au format JJ/MM/AAAA (avec séparateurs souples : espace / - .)
+ * Options :
+ * - format : permet de préciser le format de la date  jma pour jour/mois/année (par défaut), mja (pour mois / jour / année), amj (année/mois/jour)
+ * TODO : compléter les formats 
+ * On pourrait faire mieux, genre vérifier les jours en fonction du mois
+ * Mais c'est pas très important, on reste simple
+ *
+ * @param string|array $valeur
+ *   La valeur à vérifier, en chaîne pour une date seule, en tableau contenant deux entrées "date" et "heure" si on veut aussi l'heure
+ * @param array $options
+ *   tableau d'options.
+ * @param null $valeur_normalisee
+ *   Si normalisation a faire, la variable sera rempli par la date normalisee.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_date_dist($valeur, $options=array(), &$valeur_normalisee=null){
+       $erreur = _T('verifier:erreur_date_format');
+       $horaire = false; // par défaut on ne teste qu'une date
+       
+       // Si ce n'est ni une chaîne ni un tableau : pas le bon format
+       if (!is_string($valeur) and !is_array($valeur))
+               return $erreur;
+       
+       // Si c'est un tableau
+       if (is_array($valeur)) {
+               // S'il y a les bonnes infos on les garde aux bons endroits
+               if (
+                       isset($valeur['date']) and is_string($valeur['date'])
+                       and isset($valeur['heure']) and is_string($valeur['heure'])
+               ) {
+                       $options['heure'] = $valeur['heure']; // l'heure pour la fonction de normalisation
+                       $valeur = $valeur['date']; // valeur principale pour la date
+                       $horaire = true; // on détecte une vérif avec horaire uniquement dans ce cas
+               }
+               // Sinon : pas le bon format
+               else {
+                       return $erreur;
+               }
+       }
+       
+       $ok = '';
+       
+       // On tolère différents séparateurs
+       $valeur = preg_replace("#\.|/| #i",'-',$valeur);
+       
+       // On vérifie la validité du format
+       $format = isset($options['format']) ? $options['format'] : 'jma'; 
+       
+       if ($format=='mja') {
+               if(!preg_match('#^[0-9]{1,2}-[0-9]{1,2}-[0-9]{4}$#',$valeur)) return $erreur;
+               list($mois,$jour,$annee) = explode('-',$valeur);
+       } elseif ($format=='amj') {
+               if(!preg_match('#^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$#',$valeur)) return $erreur;
+               list($annee,$mois,$jour) = explode('-',$valeur);
+       } else {
+       // Format jma par défaut
+               if(!preg_match('#^[0-9]{1,2}-[0-9]{1,2}-[0-9]{4}$#',$valeur)) return $erreur;
+               list($jour,$mois,$annee) = explode('-',$valeur);
+       }
+
+               // Validité de la date
+               $erreur = _T('verifier:erreur_date');
+               if (!checkdate($mois, $jour, $annee)) return $erreur;
+       
+       if($horaire) {
+               // Format de l'heure
+               $options['heure'] = str_replace(array('h','m','min'), array(':','',''), $options['heure']);
+               if (!preg_match('#^([0-9]{1,2}):([0-9]{1,2})$#', $options['heure'], $hetm)) {
+                       return _T('verifier:erreur_heure_format');
+               }
+               // Si c'est le bon format, on teste si les nombres donnés peuvent exister
+               else {
+                       $heures = intval($hetm[1]);
+                       $minutes = intval($hetm[2]);
+                       if ($heures < 0 or $heures > 23 or $minutes < 0 or $minutes > 59){
+                               return _T('verifier:erreur_heure');
+                       }
+                       // Si tout est bon pour l'heure, on recompose en ajoutant des 0 si besoin
+                       else {
+                               $options['heure'] = sprintf('%02d:%02d', $heures, $minutes);
+                       }
+               }
+       }
+       // normaliser si demandé
+       if ($options['normaliser'] and $options['normaliser'] == 'datetime') {
+               $valeur_normalisee = normaliser_date_datetime_dist($valeur, $options, $ok);
+       }
+
+       return $ok;
+}
+
+
+
+
+/**
+ * Convertir une date en datetime 
+ *
+**/
+function normaliser_date_datetime_dist($valeur, $options, &$erreur) {
+       $defaut = '0000-00-00 00:00:00';
+
+       if (!$valeur) {
+               return $defaut;
+       }
+
+       $date = str_replace('-', '/', $valeur); // formater en jj/mm/aaaa
+
+       if (isset($options['heure'])) {
+               $date .= (' ' . $options['heure'] . ':00');
+       } else {
+               $date .= ' 00:00:00';
+       }
+
+       include_spip('inc/filtres');
+       if (!$date = recup_date($date)) {
+               $erreur = "Impossible d'extraire la date de $date";
+               return false;
+       }
+
+       if (!($date = mktime($date[3], $date[4], 0, (int)$date[1], (int)$date[2], (int)$date[0]))) {
+               // mauvais format de date
+               $erreur = "Impossible de normaliser la date...";
+               return false;
+       }
+
+       $date = date("Y-m-d H:i:s", $date);
+       $date = vider_date($date); // enlever les valeurs considerees comme nulles (1 1 1970, etc...)
+
+       if (!$date) {
+               $date = $defaut;
+       }
+
+       return $date;
+}
+
diff --git a/www/plugins/verifier/verifier/date.yaml b/www/plugins/verifier/verifier/date.yaml
new file mode 100644 (file)
index 0000000..aef4408
--- /dev/null
@@ -0,0 +1,13 @@
+
+titre: '<:verifier:type_date:>'
+description: '<:verifier:type_date_description:>'
+options:
+  -
+    saisie: 'radio'
+    options:
+      nom: 'normaliser'
+      label: '<:verifier:normaliser_option_date:>'
+      datas:
+        aucune: '<:verifier:normaliser_option_date_aucune:>'
+        datetime: '<:verifier:normaliser_option_date_en_datetime:>'
+      defaut: 'datetime'
diff --git a/www/plugins/verifier/verifier/decimal.php b/www/plugins/verifier/verifier/decimal.php
new file mode 100644 (file)
index 0000000..b144ead
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifie qu'un entier cohérent peut être extrait de la valeur
+ * Options :
+ * - min : valeur minimale acceptée
+ * - max : valeur maximale acceptée
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   Si ce tableau associatif contient une valeur pour 'min' ou 'max', un contrôle supplémentaire sera effectué.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_decimal_dist($valeur, $options=array()){
+       $erreur = _T('verifier:erreur_decimal');
+       
+       // Pas de tableau ni d'objet
+       if (is_numeric($valeur) and $valeur == floatval($valeur)){
+               // Si c'est une chaine on convertit en flottant
+               $valeur = floatval($valeur);
+               $ok = true;
+               $erreur = '';
+               
+               if (isset($options['min']))
+                       $ok = ($ok and ($valeur >= $options['min']));
+               
+               if (isset($options['max'])){
+                       $ok = ($ok and ($valeur <= $options['max']));
+               }
+               
+               if (!$ok){
+                       if (isset($options['min']) and isset($options['max']))
+                               $erreur = _T('verifier:erreur_entier_entre', $options);
+                       elseif (isset($options['max']))
+                               $erreur = _T('verifier:erreur_entier_max', $options);
+                       else
+                               $erreur = _T('verifier:erreur_entier_min', $options);
+               }
+       }
+       
+       // On vérifie le nombre de décimales après la virgule
+       if ($nb_decimales = $options['nb_decimales'] and round($valeur, $nb_decimales) != $valeur){
+               $erreur = _T('verifier:erreur_decimal_nb_decimales', array('nb_decimales' => $nb_decimales));
+       }
+       
+       return $erreur;
+}
+
+?>
diff --git a/www/plugins/verifier/verifier/decimal.yaml b/www/plugins/verifier/verifier/decimal.yaml
new file mode 100644 (file)
index 0000000..dff9ac4
--- /dev/null
@@ -0,0 +1,26 @@
+
+titre: '<:verifier:type_decimal:>'
+description: '<:verifier:type_decimal_description:>'
+options:
+  -
+    saisie: 'input'
+    options:
+      nom: 'min'
+      label: '<:verifier:option_entier_min_label:>'
+    verifier:
+      type: 'decimal'
+  -
+    saisie: 'input'
+    options:
+      nom: 'max'
+      label: '<:verifier:option_entier_max_label:>'
+    verifier:
+      type: 'decimal'
+  -
+    saisie: 'input'
+    options:
+      nom: 'nb_decimales'
+      label: '<:verifier:option_decimal_nb_decimales_label:>'
+    verifier:
+      type: 'entier'
+      min: 0
diff --git a/www/plugins/verifier/verifier/email.php b/www/plugins/verifier/verifier/email.php
new file mode 100644 (file)
index 0000000..b525c31
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifie la validité d'une adresse de courriel.
+ * 
+ * Les contraintes du mail sont déterminées par le mode de validation
+ * En option, on contrôle aussi la disponibilité du mail dans la table des auteurs
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   Un éventuel tableau d'options.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_email_dist($valeur, $options=array()){
+       include_spip('inc/filtres');
+       if (!is_string($valeur))
+               return $erreur;
+
+       // Disponibilite des courriels en base AUTEURS
+       // Si l'adresse n'est pas disponible, on stoppe tout sinon on continue
+       if ($options['disponible'] and !verifier_disponibilite_email($valeur,isset($options['id_auteur'])?$options['id_auteur']:null)){
+               return _T('verifier:erreur_email_nondispo', array('email' => echapper_tags($valeur)));
+       }
+       
+       // Choix du mode de verification de la syntaxe des courriels
+       if (!$options['mode'] or !in_array($options['mode'], array('normal','rfc5322','strict'))){
+               $mode = 'normal';
+       }
+       else{
+               $mode = $options['mode'];
+       }
+               
+       $fonctions_disponibles = array('normal' => 'email_valide', 'rfc5322' => 'verifier_email_rfc5322', 'strict' => 'verifier_email_de_maniere_stricte');
+       $fonction_verif = $fonctions_disponibles[$mode];
+       
+       if (!$fonction_verif($valeur))
+               return _T('verifier:erreur_email', array('email' => echapper_tags($valeur)));
+       else
+               return '';
+}
+
+/**
+ * Changement de la RegExp d'origine
+ *
+ * Respect de la RFC5322 
+ *
+ * @link (phraseur détaillé ici : http://www.dominicsayers.com/isemail/)
+ * @param string $valeur La valeur à vérifier
+ * @return boolean Retourne true uniquement lorsque le mail est valide
+ */
+function verifier_email_rfc5322($valeur){
+       // Si c'est un spammeur autant arreter tout de suite
+       if (preg_match(",[\n\r].*(MIME|multipart|Content-),i", $valeur)) {
+               spip_log("Tentative d'injection de mail : $valeur");
+               return false;
+       }
+       include_spip('inc/is_email');
+       foreach (explode(',', $valeur) as $adresse) {
+               if (!is_email(trim($adresse)))
+                       return false;
+       }
+       return true;
+}
+
+/**
+ * Version basique du contrôle des mails
+ *
+ * Cette version impose des restrictions supplémentaires
+ * qui sont souvent utilisées pour des raison de simplification des adresses
+ * (ex. comptes utilisateurs lisibles, etc..)
+ *
+ * @param string $valeur La valeur à vérifier
+ * @return boolean Retourne true uniquement lorsque le mail est valide
+ */
+function verifier_email_de_maniere_stricte($valeur){
+       // Si c'est un spammeur autant arreter tout de suite
+       if (preg_match(",[\n\r].*(MIME|multipart|Content-),i", $valeur)) {
+               spip_log("Tentative d'injection de mail : $valeur");
+               return false;
+       }
+       foreach (explode(',', $valeur) as $adresse) {
+               // nettoyer certains formats
+               // "Marie Toto <Marie@toto.com>"
+               $adresse = trim(preg_replace(",^[^<>\"]*<([^<>\"]+)>$,i", "\\1", $adresse));
+               if (!preg_match('/^([A-Za-z0-9]){1}([A-Za-z0-9]|-|_|\.)*@[A-Za-z0-9]([A-Za-z0-9]|-|\.){1,}\.[A-Za-z]{2,4}$/', $adresse))
+                       return false;
+       }
+       return true; 
+}
+
+/**
+ * Vérifier que le courriel à tester n'est pas
+ * déjà utilisé dans la table spip_auteurs
+ *
+ * @param string $valeur La valeur à vérifier
+ * @return boolean Retourne false lorsque le mail est déjà utilisé
+ */
+function verifier_disponibilite_email($valeur,$exclure_id_auteur=null){
+       include_spip('base/abstract_sql');
+
+       if(sql_getfetsel('id_auteur', 'spip_auteurs', 'email='.sql_quote($valeur).(!is_null($exclure_id_auteur)?"AND statut<>'5poubelle' AND id_auteur<>".intval($exclure_id_auteur):'')))
+               return false;
+       else
+               return true;
+}
diff --git a/www/plugins/verifier/verifier/email.yaml b/www/plugins/verifier/verifier/email.yaml
new file mode 100644 (file)
index 0000000..bbd904f
--- /dev/null
@@ -0,0 +1,20 @@
+
+titre: '<:verifier:type_email:>'
+description: '<:verifier:type_email_description:>'
+options:
+  -
+    saisie: 'radio'
+    options:
+      nom: 'mode'
+      label: '<:verifier:option_email_mode_label:>'
+      datas:
+        normal: '<:verifier:option_email_mode_normal:>'
+        strict: '<:verifier:option_email_mode_strict:>'
+        rfc5322: '<:verifier:option_email_mode_5322:>'
+      defaut: 'normal'
+  -
+    saisie: 'case'
+    options:
+      nom: 'disponible'
+      label: '<:verifier:option_email_disponible_label:>'
+      label_case: '<:verifier:option_email_disponible_label_case:>'
diff --git a/www/plugins/verifier/verifier/entier.php b/www/plugins/verifier/verifier/entier.php
new file mode 100644 (file)
index 0000000..2a82b73
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifie qu'un entier cohérent peut être extrait de la valeur
+ * Options :
+ * - min : valeur minimale acceptée
+ * - max : valeur maximale acceptée
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   Si ce tableau associatif contient une valeur pour 'min' ou 'max', un contrôle supplémentaire sera effectué.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_entier_dist($valeur, $options=array()){
+       $erreur = _T('verifier:erreur_entier');
+
+       // Pas de tableau ni d'objet
+       if (is_numeric($valeur) and $valeur == intval($valeur)){
+               // Si c'est une chaine on convertit en entier
+               $valeur = intval($valeur);
+               $ok = true;
+               $erreur = '';
+               
+               if (isset($options['min']))
+                       $ok = ($ok and ($valeur >= $options['min']));
+               
+               if (isset($options['max'])){
+                       $ok = ($ok and ($valeur <= $options['max']));
+               }
+               
+               if (!$ok){
+                       if (isset($options['min']) and isset($options['max']))
+                               $erreur = _T('verifier:erreur_entier_entre', $options);
+                       elseif (isset($options['max']))
+                               $erreur = _T('verifier:erreur_entier_max', $options);
+                       else
+                               $erreur = _T('verifier:erreur_entier_min', $options);
+               }
+       }
+       
+       return $erreur;
+}
+
+?>
diff --git a/www/plugins/verifier/verifier/entier.yaml b/www/plugins/verifier/verifier/entier.yaml
new file mode 100644 (file)
index 0000000..43021a0
--- /dev/null
@@ -0,0 +1,18 @@
+
+titre: '<:verifier:type_entier:>'
+description: '<:verifier:type_entier_description:>'
+options:
+  -
+    saisie: 'input'
+    options:
+      nom: 'min'
+      label: '<:verifier:option_entier_min_label:>'
+    verifier:
+      type: 'entier'
+  -
+    saisie: 'input'
+    options:
+      nom: 'max'
+      label: '<:verifier:option_entier_max_label:>'
+    verifier:
+      type: 'entier'
diff --git a/www/plugins/verifier/verifier/id_document.php b/www/plugins/verifier/verifier/id_document.php
new file mode 100644 (file)
index 0000000..e0909db
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifie que la valeur correspond à un id_dcoument valide
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_id_document_dist($valeur, $options=array()){
+       $erreur = '';
+       
+       if ($valeur !== '') {
+               // On vérifie déjà qu'il s'agit d'un nombre
+               if(!is_numeric($valeur))
+                       $erreur = _T('verifier:erreur_id_document');
+               // Puis qu'il y a au moins un document avec cet id
+               elseif (!sql_countsel('spip_documents',"id_document=$valeur"))
+                       $erreur = _T('verifier:erreur_id_document');
+       }
+       
+       return $erreur;
+}
+
+?>
diff --git a/www/plugins/verifier/verifier/isbn.php b/www/plugins/verifier/verifier/isbn.php
new file mode 100644 (file)
index 0000000..ba0a2ce
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Validation d'un numero ISBN 
+ *
+ * d apres https://fr.wikipedia.org/wiki/Numéro_ISBN
+ * ISBN-13 : longeur totale 13 caracteres divises en 5 segments de la forme G - A - B - C - K
+ *           G:  3 caracteres (978 ou 979)
+ *           A:  de 1 a 5 caracteres (code de la zone geographique)
+ *           B:  de 1 a 7 caracteres (code de l editeur)
+ *           C:  de 1 a 6 caracteres, completes eventuellement par des 0 afin que le total-G soit egal a 10 caracteres (code du livre)
+ *           K:  1 caractere entre 0 et 9 (cle de controle calculee d apres les autres chiffres)
+ *           ex: 978-2-1234-5680-3
+ * ISBN-10 : longeur totale 10 caracteres divises en 4 segments de la forme A -B -C -K
+ *           A, B, C : idem ISBN-13
+ *           K:  1 caractere entre 0 et 9, ou X (cle de controle calculee d apres les autres chiffres)
+ *           ex: 2-1234-5680-X
+ * 
+ * Avec un numero ISBN comportant des tirets, on pourrait utiliser une regex
+ * pour verifier que chaque segment comporte le nombre adequat de caracteres.
+ * Cependant ca ne permet pas d indiquer precisement la nature de l erreur.
+ * La regex au cas ou : "/^(97[89][- ]){0,1}[0-9]{1,5}[- ][0-9]{1,7}[- ][0-9]{1,6}[- ][0-9X]$/"
+ * 
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_isbn_dist($valeur, $options=array()){
+
+       // dans tous les cas, on doit avoir 10 ou 13 caracteres (en enlevant les tirets)
+       $val['nb'] = $nb = strlen(preg_replace('/-/', '', $valeur));
+       if (!preg_match("/10|13/", $nb)) {
+               return _T('verifier:erreur_isbn_nb_caracteres', $val);
+       }
+
+       // un numero ISBN-13 ne peut pas se terminer par X
+       else if (preg_match("/^97[89].*X$/", $valeur)) {
+               return _T('verifier:erreur_isbn_13_X'); 
+       }
+
+       // s il y a le bon nombre de caracteres, on verifie qu il soient bien agences
+       else {
+
+               // si le numero ISBN est decompose en segments par des tirets, verifier chaque segment
+               if (preg_match("/-/", $valeur)){
+
+                       // d'abord on recupere les valeurs de chaque segment
+                       $segments = explode("-", $valeur);
+                       $val['nb'] = count($segments);
+                       // ISBN-13
+                       if ($val['nb'] == 5) {
+                               $isbn = 13;
+                               $G = $segments[0];
+                               $A = $segments[1];
+                               $B = $segments[2];
+                               $C = $segments[3];
+                               $K = $segments[4];
+                       }
+                       // ISBN-10
+                       else if ($val['nb'] == 4) {
+                               $isbn = 10;
+                               $A = $segments[0];
+                               $B = $segments[1];
+                               $C = $segments[2];
+                               $K = $segments[3];
+                       }
+                       // nombre de segments incorrect (on ne sait jamais)
+                       else {
+                               return _T('verifier:erreur_isbn_nb_segments', $val);
+                       }
+
+                       // puis ensuite, on verifie leur conformite
+                       // G : 978 ou 979
+                       if ($G AND !preg_match("/97[89]/", $G)) {
+                               return _T('verifier:erreur_isbn_G');
+                       }
+                       // A, B et C doivent contenir des chiffres
+                       foreach (array($A,$B,$C) as $segment){
+                               $val['segment'] = $segment;
+                               if (!is_numeric($segment))
+                                       return _T('verifier:erreur_isbn_segment_lettre', $val);
+                       }
+                       // A (code zone geographique) : 5 caracteres max
+                       if ($nbA = strlen($A) AND $nbA > 5) {
+                               $val['nb'] = $nbA - 5;
+                               $val['segment'] = $A;
+                               return _T('verifier:erreur_isbn_segment', $val);
+                       }
+                       // B (code editeur) : 7 caracteres max
+                       if ($nbB = strlen($B) AND $nbB > 7) {
+                               $val['nb'] = $nbB - 7;
+                               $val['segment'] = $B;
+                               return _T('verifier:erreur_isbn_segment', $val);
+                       }
+                       // C (code livre) : 6 caracteres max
+                       if ($nbC = strlen($C) AND $nbC > 6) {
+                               $val['nb'] = $nbC - 6;
+                               $val['segment'] = $C;
+                               return _T('verifier:erreur_isbn_segment', $val);
+                       }
+                       // K (cle de controle) : 1 caractere max
+                       if ($nbK = strlen($K) AND $nbK > 1) {
+                               $val['nb'] = $nbK - 1;
+                               $val['segment'] = $K;
+                               return _T('verifier:erreur_isbn_segment', $val);
+                       }
+               }
+
+               // si le numero ISBN n a pas de tiret, on verifie au moyen d une regex
+               else {
+                       // verification generique [978 ou 979] [9 chiffres] [1 chiffre ou lettre X]
+                       if (!preg_match("/^(97[89]){0,1}[0-9]{1,9}[0-9X]$/", $valeur))
+                               return _T('verifier:erreur_isbn');
+               }
+       }
+
+       return '';
+}
diff --git a/www/plugins/verifier/verifier/regex.php b/www/plugins/verifier/verifier/regex.php
new file mode 100644 (file)
index 0000000..8ba8605
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifié une valeur suivant une expression régulière.
+ * Options :
+ * - modele : chaine représentant l'expression
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   Contient une chaine représentant l'expression.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_regex_dist($valeur, $options=array()){
+       $erreur = _T('verifier:erreur_regex');
+       if (!is_string($valeur))
+               return $erreur;
+
+       if (preg_match($options['modele'], $valeur))
+               return '';
+
+       return $erreur;
+}
+
+?>
diff --git a/www/plugins/verifier/verifier/regex.yaml b/www/plugins/verifier/verifier/regex.yaml
new file mode 100644 (file)
index 0000000..590aaf4
--- /dev/null
@@ -0,0 +1,9 @@
+
+titre: '<:verifier:type_regex:>'
+description: '<:verifier:type_regex_description:>'
+options:
+  -
+    saisie: 'input'
+    options:
+      nom: 'modele'
+      label: '<:verifier:option_regex_modele_label:>'
diff --git a/www/plugins/verifier/verifier/siren_siret.php b/www/plugins/verifier/verifier/siren_siret.php
new file mode 100644 (file)
index 0000000..04f0f71
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Validation d'un SIREN ou d'un SIRET 
+ *
+ * 1/ Un SIREN comporte STRICTEMENT 9 caractères
+ * 1b/ Un SIRET comporte strictement 14 caractères
+ * 2/ Un siren/siret utilise une clef de controle "1-2"
+ *    Un siren/siret est donc valide si la somme des chiffres pairs
+ *    + la somme du double de tous les chiffres impairs (16 = 1+6 = 7) est un multiple de 10
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   Indique s'il faut tester le SIREN ou le SIRET.
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_siren_siret_dist($valeur, $options=array()){
+       if (!$options['mode'] or !in_array($options['mode'], array('siren', 'siret'))){
+               $mode = 'siren';
+       }
+       else{
+               $mode = $options['mode'];
+       }
+
+       // on supprime les espaces avant d'effectuer les tests
+       $valeur = preg_replace('/\s/', '', $valeur);
+
+       // Test de SIREN
+       if ($mode == 'siren'){
+               $erreur = _T('verifier:erreur_siren');
+               if (!is_string($valeur))
+                       return $erreur;
+
+               // Si pas 9 caractère, c'est déjà foiré !
+               if(!preg_match('/^[0-9]{9}$/',$valeur)) return $erreur;
+       
+               // On vérifie la clef de controle "1-2"
+               $somme = 0;
+               $i = 0; // Les impaires
+               while($i < 9){ $somme += $valeur[$i]; $i+=2; }
+               $i = 1; // Les paires !
+               while($i < 9){ if((2*$valeur[$i])>9) $somme += (2*$valeur[$i])-9; else $somme += 2*$valeur[$i]; $i+=2; }
+       
+               if ($somme % 10) return $erreur;
+       }
+       // Test de SIRET
+       else{
+               $erreur = _T('verifier:erreur_siret');
+               if (!is_string($valeur))
+                       return $erreur;
+
+               // Si pas 14 caractère, c'est déjà foiré !
+               if(!preg_match('/^[0-9]{14}$/',$valeur)) return $erreur;
+               if(preg_match('/[0]{8}/',$valeur)) return $erreur;
+
+               // Pour le SIRET on vérifie la clef de controle "1-2" avec les impaires *2
+               // (vs pairs*2 pour SIREN, parce qu'on part de la fin)
+               $somme = 0;
+               $i = 1; // Les paires
+               while($i < 14){ $somme += $valeur[$i]; $i+=2; }
+               $i = 0; // Les impaires !
+               while($i < 14){ if((2*$valeur[$i])>9) $somme += (2*$valeur[$i])-9; else $somme += 2*$valeur[$i]; $i+=2; }
+       
+               if($somme % 10) return $erreur;
+       }
+       
+       return '';
+}
diff --git a/www/plugins/verifier/verifier/siren_siret.yaml b/www/plugins/verifier/verifier/siren_siret.yaml
new file mode 100644 (file)
index 0000000..c9d8b30
--- /dev/null
@@ -0,0 +1,12 @@
+
+titre: '<:verifier:type_siren_siret:>'
+description: '<:verifier:type_siren_siret_description:>'
+options:
+  -
+    saisie: 'radio'
+    options:
+      nom: 'mode'
+      label: '<:verifier:option_siren_siret_mode_label:>'
+      datas:
+        siren: '<:verifier:option_siren_siret_mode_siren:>'
+        siret: '<:verifier:option_siren_siret_mode_siret:>'
diff --git a/www/plugins/verifier/verifier/taille.php b/www/plugins/verifier/verifier/taille.php
new file mode 100644 (file)
index 0000000..b55ad1f
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifier une taille minimale/maximale, pour un mot de passe par exemple
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   Les éléments à vérifier (min, max, egal).
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+
+function verifier_taille_dist($valeur, $options=array()){
+       $ok = true;
+       if (!is_string($valeur))
+               return _T('erreur_inconnue_generique');
+       
+       include_spip('inc/charsets');
+       $erreur = '';
+       $taille = spip_strlen($valeur);
+       
+       if (isset($options['min']))
+               $ok = ($ok and ($taille >= $options['min']));
+       
+       if (isset($options['max'])){
+               $ok = ($ok and ($taille <= $options['max']));
+       }
+       if (isset($options['egal'])){
+               $ok = ($ok and ($taille == $options['egal']));
+       }
+       
+       if (!$ok){
+               // On ajoute la taille actuelle aux valeurs de remplacement
+               $options['nb'] = $taille;
+               if (isset($options['min']) and isset($options['max']))
+                       $erreur = _T('verifier:erreur_taille_entre', $options);
+               elseif (isset($options['max']))
+                       $erreur = _T('verifier:erreur_taille_max', $options);
+               elseif (isset($options['egal']))
+                       $erreur = _T('verifier:erreur_taille_egal', $options);
+               else
+                       $erreur = _T('verifier:erreur_taille_min', $options);
+       }
+       
+       return $erreur;
+}
diff --git a/www/plugins/verifier/verifier/taille.yaml b/www/plugins/verifier/verifier/taille.yaml
new file mode 100644 (file)
index 0000000..3b9283c
--- /dev/null
@@ -0,0 +1,22 @@
+
+titre: '<:verifier:type_taille:>'
+description: '<:verifier:type_taille_description:>'
+options:
+  -
+    saisie: 'input'
+    options:
+      nom: 'min'
+      label: '<:verifier:option_taille_min_label:>'
+    verifier:
+      type: 'entier'
+      options:
+        min: 0
+  -
+    saisie: 'input'
+    options:
+      nom: 'max'
+      label: '<:verifier:option_taille_max_label:>'
+    verifier:
+      type: 'entier'
+      options:
+        min: 0
diff --git a/www/plugins/verifier/verifier/telephone.php b/www/plugins/verifier/verifier/telephone.php
new file mode 100644 (file)
index 0000000..5261bb2
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérifie un numéro de téléphone. Pour l'instant seulement avec le schéma français.
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *   [INUTILISE].
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_telephone_dist($valeur, $options=array()){
+       $erreur = _T('verifier:erreur_telephone');
+       if (!is_string($valeur))
+               return $erreur;
+       $ok = '';
+
+       // On accepte differentes notations, les points, les tirets, les espaces, les slashes
+       $tel = preg_replace("#\.|/|-| #i",'',$valeur);
+       
+       if (preg_match("/^\+33/", $tel)) {
+               $options['pays'] = 'FR';
+               $tel = preg_replace('/^\+33/','0',$valeur);
+       }
+       if (preg_match("/^\+34/", $tel)) {
+               $options['pays'] = 'ES';
+               $tel = preg_replace('/^\+34/','',$valeur);
+       }
+       if (preg_match("/^\+41/", $tel)) {
+               $options['pays'] = 'CH';
+               $tel = preg_replace('/^\+41/','0',$valeur);
+       }
+
+       switch($options['pays']){
+               case 'CH':
+                       if (!preg_match("/^0[1-9]{9}$/",$tel)) return $erreur;
+                       break;
+               case 'ES':
+                       if (!preg_match("/^[69][0-9]{8}$/",$tel)) return $erreur;
+                       break;
+               case 'FR':
+                       if (!preg_match("/^0[1-9][0-9]{8}$/",$tel)) return $erreur;
+               default:
+                       // On interdit les 000 etc. mais je pense qu'on peut faire plus malin
+                       // TODO finaliser les numéros à la con
+                       if($tel == '0000000000') return $erreur;
+                       break;
+       }
+       
+       return $ok;
+}
diff --git a/www/plugins/verifier/verifier/telephone.yaml b/www/plugins/verifier/verifier/telephone.yaml
new file mode 100644 (file)
index 0000000..dacf99a
--- /dev/null
@@ -0,0 +1,3 @@
+
+titre: '<:verifier:type_telephone:>'
+description: '<:verifier:type_telephone_description:>'
diff --git a/www/plugins/verifier/verifier/url.php b/www/plugins/verifier/verifier/url.php
new file mode 100644 (file)
index 0000000..ce5120f
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+/**
+ * Vérification d'une URL
+ * 
+ * Si auncune option n'est définie, vérifie uniquement si un protocole de type web est défini
+ *
+ * @param string $valeur
+ *   La valeur à vérifier.
+ * @param array $options
+ *      mode : protocole_seul, php_filter, complet
+ *              type_protocole : tous, web (http ou https), mail (imap, pop3, smtp), ftp (ftp ou sftp), exact
+ *     protocole : nom du protocole (si type_protocole=exact)
+ * @return string
+ *   Retourne une chaine vide si c'est valide, sinon une chaine expliquant l'erreur.
+ */
+function verifier_url_dist($valeur, $options=array()){
+       if (!is_string($valeur))
+               return _T('erreur_inconnue_generique');
+
+       // Choix du mode de verification de la syntaxe des url
+       if (!$options['mode'] or !in_array($options['mode'], array('protocole_seul','php_filter','complet'))){
+               $mode = 'protocole_seul';
+       }
+       else{
+               $mode = $options['mode'];
+       }
+               
+       // Choix du type de protocole à vérifier
+       if (!$options['type_protocole'] or !in_array($options['type_protocole'], array('tous','web','mail','ftp','exact'))){
+               $type_protocole = 'web';
+       }
+       else{
+               $type_protocole = $options['type_protocole'];
+               $protocole = '' ;
+               if ($type_protocole=='exact' && $options['protocole']){
+                       $protocole = $options['protocole'];
+               }
+       }
+               
+       $fonctions_disponibles = array('protocole_seul' => 'verifier_url_protocole', 'php_filter' => 'verifier_php_filter', 'complet' => 'verifier_url_complet');
+       $fonction_verif = $fonctions_disponibles[$mode];
+       
+       return $fonction_verif($valeur,$type_protocole,$protocole) ;
+
+}
+
+/**
+ * Vérifier uniquement la présence d'un protocole
+ *
+ * @param string $valeur La valeur à vérifier
+ * @param string $type_protocole : tous, web (http ou https), mail (imap, pop3, smtp), ftp (ftp ou sftp), exact
+ * @param string $protocole : nom du protocole (si type_protocole=exact)
+ * @return boolean Retourne true uniquement lorsque l'url est valide
+ */
+function verifier_url_protocole($url,$type_protocole,$protocole){
+
+       $urlregex = array('tous' => "#^([a-z0-9]*)\:\/\/.*$# i",
+                                                'web' => "#^(https?)\:\/\/.*$# i",
+                                                'ftp' => "#^(s?ftp)\:\/\/.*$# i",
+                                                'mail' => "#^(pop3|smtp|imap)\:\/\/.*$# i",
+                                                'exact' => "#^(".$protocole.")\:\/\/.*$# i");
+       
+       $msg_erreur = array('tous' => "",
+                                                        'web' => "http://, https://",
+                                                        'ftp' => "^ftp://, sftp://",
+                                                        'mail' => "pop3://, smtp://, imap://",
+                                                        'exact' => $protocole."://" );
+       
+
+       if (!preg_match($urlregex[$type_protocole], $url)) {
+               if($type_protocole=="tous") {
+                       return _T('verifier:erreur_url_protocole_exact', array('url' => echapper_tags($url)));
+               } else {
+                       return _T('verifier:erreur_url_protocole', array('url' => echapper_tags($url),'protocole' => $msg_erreur[$type_protocole]));
+               }
+       }
+       return '';
+}
+
+/**
+ * Vérifier uniquement la présence d'un protocole
+ *
+ * @param string $valeur La valeur à vérifier
+ * @param string $type_protocole : tous, web (http ou https), mail (imap, pop3, smtp), ftp (ftp ou sftp), exact
+ * @param string $protocole : nom du protocole (si type_protocole=exact)
+ * @return boolean Retourne true uniquement lorsque l'url est valide
+ */
+function verifier_php_filter($url,$type_protocole,$protocole){
+
+       if (!filter_var($url, FILTER_VALIDATE_URL))
+               return _T('verifier:erreur_url', array('url' => echapper_tags($valeur)));
+       return '';
+}
+
+/**
+ * Vérifier la présence d'un protocole et de la bonne syntaxe du reste de l'url
+ *
+ * http://phpcentral.com/208-url-validation-in-php.html
+ * <http[s]|ftp> :// [user[:pass]@] hostname [port] [/path] [?getquery] [anchor]
+ *
+ * @param string $valeur La valeur à vérifier
+ * @param string $type_protocole : web (http ou https), mail (imap, pop3, smtp), ftp (ftp ou sftp), exact
+ * @param string $protocole : nom du protocole (si type_protocole=exact)
+ * @return boolean Retourne true uniquement lorsque l'url est valide
+ */
+function verifier_url_complet($url,$type_protocole,$protocole){
+       
+       if($msg=verifier_url_protocole($url,$type_protocole,$protocole)!=''){
+               return $msg;
+       }
+       // SCHEME
+       $urlregex = "#^(.*)\:\/\/";
+       
+       // USER AND PASS (optional)
+       $urlregex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?";
+       
+       // HOSTNAME OR IP
+       $urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*"; // http://x = allowed (ex. http://localhost, http://routerlogin)
+       //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)+"; // http://x.x = minimum
+       //$urlregex .= "([a-z0-9+\$_-]+\.)*[a-z0-9+\$_-]{2,3}"; // http://x.xx(x) = minimum
+       //use only one of the above
+       
+       // PORT (optional)
+       $urlregex .= "(\:[0-9]{2,5})?";
+       // PATH (optional)
+       $urlregex .= "(\/([a-z0-9+\$_%,-]\.?)+)*\/?";
+       // GET Query (optional)
+       $urlregex .= "(\?[a-z+&\$_.-][a-z0-9;:@/&%=+\$_.-]*)?";
+       // ANCHOR (optional)
+       $urlregex .= "(\#[a-z_.-][a-z0-9+\$_.-]*)?\$# i";
+       
+       if (!preg_match($urlregex, $url))
+               return _T('verifier:erreur_url', array('url' => echapper_tags($valeur)));
+       return '';
+}
\ No newline at end of file
diff --git a/www/plugins/verifier/verifier/url.yaml b/www/plugins/verifier/verifier/url.yaml
new file mode 100644 (file)
index 0000000..7864f56
--- /dev/null
@@ -0,0 +1,33 @@
+\r
+titre: '<:verifier:type_url:>'\r
+description: '<:verifier:type_url_description:>'\r
+options:\r
+  -\r
+    saisie: 'radio'\r
+    options:\r
+      nom: 'mode'\r
+      label: '<:verifier:option_url_mode_label:>'\r
+      datas:\r
+        protocole_seul: '<:verifier:option_url_mode_protocole_seul:>'\r
+        php_filter: '<:verifier:option_url_mode_php_filter:>'\r
+        complet: '<:verifier:option_url_mode_complet:>'\r
+      defaut: 'protocole_seul'\r
+  -\r
+    saisie: 'radio'\r
+    options:\r
+      nom: 'type_protocole'\r
+      label: '<:verifier:option_url_type_protocole_label:>'\r
+      datas:\r
+        tous: '<:verifier:option_url_type_protocole_tous:>'\r
+        web: '<:verifier:option_url_type_protocole_web:>'\r
+        mail: '<:verifier:option_url_type_protocole_mail:>'\r
+        ftp: '<:verifier:option_url_type_protocole_ftp:>'\r
+        exact: '<:verifier:option_url_type_protocole_exact:>'\r
+      defaut: 'web'\r
+  -\r
+    saisie: 'input'\r
+    options:\r
+      nom: 'protocole'\r
+      label: '<:verifier:option_url_protocole_label:>'\r
+\r
+\r
diff --git a/www/plugins/yaml/demo/iter_data_yaml.html b/www/plugins/yaml/demo/iter_data_yaml.html
new file mode 100644 (file)
index 0000000..9b52dce
--- /dev/null
@@ -0,0 +1,17 @@
+#CACHE{0}
+
+<h2>(DATA) YAML</h2>
+
+<dl>
+
+<B_r1>
+#PAGINATION
+<br />#TOTAL_BOUCLE/#GRAND_TOTAL
+<BOUCLE_r1(DATA)
+       {datasource http://per.sonn.es/Marcimat.yaml, yaml}
+       {pagination 5}>
+<dt>#CLE</dt>
+<dd> [(#VALEUR|print)] </dd>
+</BOUCLE_r1>
+
+</dl>
diff --git a/www/plugins/yaml/experimental/README b/www/plugins/yaml/experimental/README
new file mode 100644 (file)
index 0000000..e7e8012
--- /dev/null
@@ -0,0 +1,9 @@
+Installer ces deux fichiers dans les squelettes
+
+Puis appeler spip.php?page=yaml&id_article=X
+
+ou alors dans .htaccess ajouter :
+RewriteRule ^article([0-9]+)[\.,]yaml$ spip.php?page=yaml&id_article=$1 [QSA,L]
+
+puis appeler articleXXX,yaml
+
diff --git a/www/plugins/yaml/experimental/yaml.html b/www/plugins/yaml/experimental/yaml.html
new file mode 100644 (file)
index 0000000..38f5ce7
--- /dev/null
@@ -0,0 +1,5 @@
+#HTTP_HEADER{Content-Type: text/plain; charset=#CHARSET}
+<BOUCLE_a(ARTICLES){id_article}>
+# Article #ID_ARTICLE du site #URL_SITE_SPIP*
+[(#ID_ARTICLE|yaml_article)]
+</BOUCLE_a>
diff --git a/www/plugins/yaml/experimental/yaml_fonctions.php b/www/plugins/yaml/experimental/yaml_fonctions.php
new file mode 100644 (file)
index 0000000..a9f27e5
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function yaml_article($id_article) {
+       include_spip('inc/yaml');
+       $a = array_filter(sql_fetsel('*', 'spip_articles', 'id_article='.$id_article));
+       $a['rubrique'] = array_filter(sql_fetsel('*', 'spip_rubriques', 'id_rubrique='.$a['id_rubrique']));
+
+       foreach(sql_allfetsel('*', 'spip_mots AS m LEFT JOIN spip_mots_articles AS c ON m.id_mot=c.id_mot', 'c.id_article='.$id_article) as $m)
+               $a['mots'][] = array_filter($m);
+
+       return yaml_encode(
+               array_filter($a)
+               );
+}
\ No newline at end of file
diff --git a/www/plugins/yaml/inc/yaml.php b/www/plugins/yaml/inc/yaml.php
new file mode 100644 (file)
index 0000000..0e12ea0
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+# textwheel fournit yaml_decode() aussi...
+# include_spip('inc/yaml-mini');
+
+# wrapper de la class sfYAML pour SPIP
+#
+# fournit deux fonctions pour YAML,
+# analogues a json_encode() et json_decode
+#
+# Regle de dev: ne pas se rendre dependant de la lib sous-jacente
+
+// Si on est en PHP4
+ if (version_compare(PHP_VERSION, '5.0.0', '<'))
+       define('_LIB_YAML','spyc-php4'); 
+ else {
+       // temporaire le temps de tester spyc
+       define('_LIB_YAML','sfyaml'); 
+       #define('_LIB_YAML','spyc'); 
+}
+/*
+ * Encode n'importe quelle structure en yaml
+ * @param $struct
+ * @return string
+ */
+function yaml_encode($struct, $opt = array()) {
+       // Si PHP4
+       if (_LIB_YAML == 'spyc-php4') {
+               require_once _DIR_PLUGIN_YAML.'spyc/spyc-php4.php';
+               return Spyc::YAMLDump($struct);
+       }
+       // test temporaire
+       if (_LIB_YAML == 'spyc') {
+               require_once _DIR_PLUGIN_YAML.'spyc/spyc.php';
+               return Spyc::YAMLDump($struct);
+       }
+
+       require_once _DIR_PLUGIN_YAML.'inc/yaml_sfyaml.php';
+       return yaml_sfyaml_encode($struct, $opt);
+}
+
+/*
+ * Decode un texte yaml, renvoie la structure
+ * @param string $input
+ *        boolean $show_error  true: arrete le parsing et retourne erreur en cas d'echec  - false: retourne un simple false en cas d'erreur de parsing
+ */
+if (!function_exists('yaml_decode')) {
+function yaml_decode($input,$show_error=true) {
+       // Si PHP4
+       if (_LIB_YAML == 'spyc-php4') {
+               require_once _DIR_PLUGIN_YAML.'spyc/spyc-php4.php';
+               return Spyc::YAMLLoad($input);
+       }
+       // test temporaire
+       if (_LIB_YAML == 'spyc') {
+               require_once _DIR_PLUGIN_YAML.'spyc/spyc.php';
+               return Spyc::YAMLLoad($input);
+       }
+
+       require_once _DIR_PLUGIN_YAML.'inc/yaml_sfyaml.php';
+       return yaml_sfyaml_decode($input,$show_error);
+}
+}
+
+/*
+ * Decode un fichier en utilisant yaml_decode
+ * @param string $fichier 
+ */
+function yaml_decode_file($fichier){
+       $yaml = '';
+       $retour = false;
+       
+       lire_fichier($fichier, $yaml);
+       // Si on recupere bien quelque chose
+       if ($yaml){
+               $retour = yaml_decode($yaml);
+       }
+       
+       return $retour;
+}
+
+/*
+ * Charge les inclusions de YAML dans un tableau
+ * Les inclusions sont indiquees dans le tableau via la valeur 'inclure:rep/fichier.yaml' ou rep indique le chemin relatif.
+ * On passe donc par find_in_path() pour trouver le fichier
+ * @param array $tableau
+ */
+
+function yaml_charger_inclusions($tableau){
+       if (is_array($tableau)){
+               $retour = array();
+               foreach($tableau as $cle => $valeur) {
+                       if (is_string($valeur) && substr($valeur,0,8)=='inclure:' && substr($valeur,-5)=='.yaml')
+                               $retour = array_merge($retour,yaml_charger_inclusions(yaml_decode_file(find_in_path(substr($valeur,8)))));
+                       elseif (is_array($valeur))
+                               $retour = array_merge($retour,array($cle => yaml_charger_inclusions($valeur)));
+                       else
+                               $retour = array_merge($retour,array($cle => $valeur));
+               }
+               return $retour;
+       }
+       elseif (is_string($tableau) && substr($tableau,0,8)=='inclure:' && substr($tableau,-5)=='.yaml')
+               return yaml_charger_inclusions(yaml_decode_file(find_in_path(substr($tableau,8))));
+       else
+               return $tableau;
+}
+
+?>
diff --git a/www/plugins/yaml/inc/yaml_sfyaml.php b/www/plugins/yaml/inc/yaml_sfyaml.php
new file mode 100644 (file)
index 0000000..1d94844
--- /dev/null
@@ -0,0 +1,36 @@
+<?php\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+function yaml_sfyaml_encode($struct, $opt = array()) {\r
+       require_once _DIR_PLUGIN_YAML.'sfyaml/sfYaml.php';\r
+       require_once _DIR_PLUGIN_YAML.'sfyaml/sfYamlDumper.php';\r
+       $opt = array_merge(\r
+               array(\r
+                       'inline' => 2\r
+               ), $opt);\r
+       $yaml = new sfYamlDumper();\r
+       return $yaml->dump($struct, $opt['inline']);\r
+}\r
+\r
+function yaml_sfyaml_decode($input,$show_error=true) {\r
+       require_once _DIR_PLUGIN_YAML.'sfyaml/sfYaml.php';\r
+       require_once _DIR_PLUGIN_YAML.'sfyaml/sfYamlParser.php';\r
+\r
+       $yaml = new sfYamlParser();\r
+\r
+       try\r
+       {\r
+         $ret = $yaml->parse($input);\r
+       }\r
+       catch (Exception $e)\r
+       {\r
+               if ($show_error) \r
+              throw new InvalidArgumentException(sprintf('Unable to parse string: %s', $e->getMessage()));\r
+          else\r
+              return false;       \r
+       }\r
+\r
+       return $ret;\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/yaml/inc/yaml_to_array.php b/www/plugins/yaml/inc/yaml_to_array.php
new file mode 100644 (file)
index 0000000..75969ef
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+function inc_yaml_to_array_dist($u) {
+       include_spip('inc/yaml');
+       if (is_array($yaml = yaml_decode($u)))
+               $tableau = $yaml;
+       else if (is_object($yaml))
+               $tableau = (array) $yaml;
+
+       return $tableau;
+}
+
+?>
diff --git a/www/plugins/yaml/lang/paquet-yaml.xml b/www/plugins/yaml/lang/paquet-yaml.xml
new file mode 100644 (file)
index 0000000..a22b3e2
--- /dev/null
@@ -0,0 +1,19 @@
+<traduction module="paquet-yaml" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/yaml/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=ru">
+               <traducteur nom="nazar" lien="http://trad.spip.net/auteur/nazar" />
+               <traducteur nom="Serge Markitanenko" lien="http://trad.spip.net/auteur/serge-markitanenko" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/yaml/lang/paquet-yaml_en.php b/www/plugins/yaml/lang/paquet-yaml_en.php
new file mode 100644 (file)
index 0000000..7bae352
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Y
+       'yaml_description' => 'This plugin provides the functions for reading/writing YAML format:
+<code>yaml_decode()</code> and <code>yaml_encode()</code>. It also provides the yaml format for the (DATA) loop.',
+       'yaml_slogan' => 'A simple file format for editing lists of data'
+);
+
+?>
diff --git a/www/plugins/yaml/lang/paquet-yaml_es.php b/www/plugins/yaml/lang/paquet-yaml_es.php
new file mode 100644 (file)
index 0000000..90af6eb
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Y
+       'yaml_description' => 'Este plugin proporciona las funciones de lectura/escritura del formato YAML: <code>yaml_decode()</code> y <code>yaml_encode()</code>. También proporciona el formato yaml para el bucle (DATA).',
+       'yaml_slogan' => 'Un formato de archivo simple para editar listas de datos'
+);
+
+?>
diff --git a/www/plugins/yaml/lang/paquet-yaml_fa.php b/www/plugins/yaml/lang/paquet-yaml_fa.php
new file mode 100644 (file)
index 0000000..9d298e7
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Y
+       'yaml_description' => 'اين پلاگين كاركردهاي خواندن/نوشتن فرمت يا.اي.ام.ال را فراهم مي‌آورد: <code>yaml_decode()</code> و<code>yaml_encode()</code>. همچنين فرمت يا.اي.ام.ال را براي حلقه‌ي (DATA) فراهم مي‌سازد.',
+       'yaml_slogan' => 'فرمتي براي پروند‌ه ساده براي ويرايش فهرست‌هاي داده‌ها'
+);
+
+?>
diff --git a/www/plugins/yaml/lang/paquet-yaml_fr.php b/www/plugins/yaml/lang/paquet-yaml_fr.php
new file mode 100644 (file)
index 0000000..b3735f8
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/yaml/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Y
+       'yaml_description' => 'Ce plugin fournit les fonctions de lecture/écriture du format YAML:
+       <code>yaml_decode()</code> et <code>yaml_encode()</code>. Il fournit aussi le format yaml pour la boucle (DATA).',
+       'yaml_slogan' => 'Un format de fichier simple pour éditer des listes de données'
+);
+
+?>
diff --git a/www/plugins/yaml/lang/paquet-yaml_ru.php b/www/plugins/yaml/lang/paquet-yaml_ru.php
new file mode 100644 (file)
index 0000000..8691623
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Y
+       'yaml_description' => 'Плагин позволяет использовать функции чтения/записи в формате YAML:
+       <code>yaml_decode()</code> и <code>yaml_encode()</code>. И позволяет использовать YAML в запросе BOUCLE(DATA).',
+       'yaml_slogan' => 'Позволяет работать с YAML форматом'
+);
+
+?>
diff --git a/www/plugins/yaml/lang/paquet-yaml_sk.php b/www/plugins/yaml/lang/paquet-yaml_sk.php
new file mode 100644 (file)
index 0000000..4b44dfb
--- /dev/null
@@ -0,0 +1,16 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-yaml?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Y
+       'yaml_description' => 'Tento zásuvný modul ponúka funkcie čítanie/zápisu formátu YAML:
+       <code>yaml_decode()</code> a <code>yaml_encode()</code>. Poskytuje formát yaml aj pre cyklus (DATA).',
+       'yaml_slogan' => 'Jednoduchý formát súborov na upravovanie zoznamov dát'
+);
+
+?>
diff --git a/www/plugins/yaml/paquet.xml b/www/plugins/yaml/paquet.xml
new file mode 100644 (file)
index 0000000..c64dc93
--- /dev/null
@@ -0,0 +1,19 @@
+<paquet
+       prefix="yaml"
+       categorie="outil"
+       version="1.5.0"
+       etat="stable"
+       compatibilite="[2.1.0;3.0.*]"
+       logo="yaml.png"
+       documentation="http://www.spip-contrib.net/Le-plugin-YAML"
+>
+
+       <nom>YAML</nom>
+       <!-- Un format de fichier simple pour éditer des listes de données -->
+
+       <credit lien="http://yaml.org/">yaml.org</credit>
+       <credit lien="http://code.google.com/p/spyc/">Spyc</credit>
+       <credit lien="http://components.symfony-project.org/yaml/">Symfony YAML - Fabien Potencier</credit>
+
+       <licence lien="http://opensource.org/licenses/mit-license.php">MIT</licence>
+</paquet>
diff --git a/www/plugins/yaml/plugin.xml b/www/plugins/yaml/plugin.xml
new file mode 100644 (file)
index 0000000..8384e20
--- /dev/null
@@ -0,0 +1,19 @@
+<plugin>
+       <nom>YAML</nom>
+       <slogan>Un format de fichier simple pour &#233;diter des listes de donn&#233;es.</slogan>
+       <auteur>format d&#233;fini par yaml.org, librairie php d&#233;velopp&#233;e par Fabien Potencier pour Symfony</auteur>
+       <licence>MIT</licence>
+       <version>1.5.0</version>
+       <etat>stable</etat>
+       <description>
+       Ce plugin fournit les fonctions de lecture/&#233;criture du format YAML.
+       <code>yaml_decode()</code> et <code>yaml_encode()</code>. Il fournit aussi le format yaml pour la boucle (DATA).
+       </description>
+       <prefix>YAML</prefix>
+       <lien>http://www.spip-contrib.net/Le-plugin-YAML</lien>
+       <icon>yaml.png</icon>
+       <fonctions>yaml_fonctions.php</fonctions>
+       <necessite id="SPIP" version="[2.0.10;3.0.99]" />
+       <categorie>outil</categorie>
+       <chemin dir='' />
+</plugin>
diff --git a/www/plugins/yaml/sfyaml/sfYaml.php b/www/plugins/yaml/sfyaml/sfYaml.php
new file mode 100755 (executable)
index 0000000..5a2be2e
--- /dev/null
@@ -0,0 +1,145 @@
+<?php
+
+/*
+ * This file is part of the symfony package.
+ * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * sfYaml offers convenience methods to load and dump YAML.
+ *
+ * @package    symfony
+ * @subpackage yaml
+ * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version    SVN: $Id: sfYaml.class.php 8988 2008-05-15 20:24:26Z fabien $
+ */
+class sfYaml
+{
+  static protected
+    $spec = '1.2';
+
+  /**
+   * Sets the YAML specification version to use.
+   *
+   * @param string $version The YAML specification version
+   */
+  static public function setSpecVersion($version)
+  {
+    if (!in_array($version, array('1.1', '1.2')))
+    {
+      throw new InvalidArgumentException(sprintf('Version %s of the YAML specifications is not supported', $version));
+    }
+
+    self::$spec = $version;
+  }
+
+  /**
+   * Gets the YAML specification version to use.
+   *
+   * @return string The YAML specification version
+   */
+  static public function getSpecVersion()
+  {
+    return self::$spec;
+  }
+
+  /**
+   * Loads YAML into a PHP array.
+   *
+   * The load method, when supplied with a YAML stream (string or file),
+   * will do its best to convert YAML in a file into a PHP array.
+   *
+   *  Usage:
+   *  <code>
+   *   $array = sfYaml::load('config.yml');
+   *   print_r($array);
+   *  </code>
+   *
+   * @param string $input Path of YAML file or string containing YAML
+   *
+   * @return array The YAML converted to a PHP array
+   *
+   * @throws InvalidArgumentException If the YAML is not valid
+   */
+  public static function load($input)
+  {
+    $file = '';
+
+    // if input is a file, load it
+    if (strpos($input, "\n") === false && is_file($input))
+    {
+      $file = $input;
+
+      $content = $yaml = file_get_contents($input);
+
+      // if the file contains valid PHP, process it
+      if (strpos($content, '<'.'?') !== false
+      AND !(defined('_YAML_EVAL_PHP') AND !_YAML_EVAL_PHP))
+      {
+        ob_start();
+        $retval = eval('?'.'>'.$yaml);
+        $content = ob_get_clean();
+        // syntax error?
+        if ($retval === FALSE)
+          $content = $yaml;
+      }
+
+      // if an array is returned by the config file assume it's in plain php form else in YAML
+      $input = is_array($retval) ? $retval : $content;
+    }
+
+    // if an array is returned by the config file assume it's in plain php form else in YAML
+    if (is_array($input))
+    {
+      return $input;
+    }
+
+    require_once dirname(__FILE__).'/sfYamlParser.php';
+
+    $yaml = new sfYamlParser();
+
+    try
+    {
+      $ret = $yaml->parse($input);
+    }
+    catch (Exception $e)
+    {
+      throw new InvalidArgumentException(sprintf('Unable to parse %s: %s', $file ? sprintf('file "%s"', $file) : 'string', $e->getMessage()));
+    }
+
+    return $ret;
+  }
+
+  /**
+   * Dumps a PHP array to a YAML string.
+   *
+   * The dump method, when supplied with an array, will do its best
+   * to convert the array into friendly YAML.
+   *
+   * @param array   $array PHP array
+   * @param integer $inline The level where you switch to inline YAML
+   *
+   * @return string A YAML string representing the original PHP array
+   */
+  public static function dump($array, $inline = 2)
+  {
+    require_once dirname(__FILE__).'/sfYamlDumper.php';
+
+    $yaml = new sfYamlDumper();
+
+    return $yaml->dump($array, $inline);
+  }
+}
+
+/**
+ * Wraps echo to automatically provide a newline.
+ *
+ * @param string $string The string to echo with new line
+ */
+function echoln($string)
+{
+  echo $string."\n";
+}
diff --git a/www/plugins/yaml/sfyaml/sfYamlDumper.php b/www/plugins/yaml/sfyaml/sfYamlDumper.php
new file mode 100755 (executable)
index 0000000..0ada2b3
--- /dev/null
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * This file is part of the symfony package.
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once(dirname(__FILE__).'/sfYamlInline.php');
+
+/**
+ * sfYamlDumper dumps PHP variables to YAML strings.
+ *
+ * @package    symfony
+ * @subpackage yaml
+ * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version    SVN: $Id: sfYamlDumper.class.php 10575 2008-08-01 13:08:42Z nicolas $
+ */
+class sfYamlDumper
+{
+  /**
+   * Dumps a PHP value to YAML.
+   *
+   * @param  mixed   $input  The PHP value
+   * @param  integer $inline The level where you switch to inline YAML
+   * @param  integer $indent The level o indentation indentation (used internally)
+   *
+   * @return string  The YAML representation of the PHP value
+   */
+  public function dump($input, $inline = 0, $indent = 0)
+  {
+    $output = '';
+    $prefix = $indent ? str_repeat(' ', $indent) : '';
+
+    if ($inline <= 0 || !is_array($input) || empty($input))
+    {
+      $output .= $prefix.sfYamlInline::dump($input);
+    }
+    else
+    {
+      $isAHash = array_keys($input) !== range(0, count($input) - 1);
+
+      foreach ($input as $key => $value)
+      {
+        $willBeInlined = $inline - 1 <= 0 || !is_array($value) || empty($value);
+
+        $output .= sprintf('%s%s%s%s',
+          $prefix,
+          $isAHash ? sfYamlInline::dump($key).':' : '-',
+          $willBeInlined ? ' ' : "\n",
+          $this->dump($value, $inline - 1, $willBeInlined ? 0 : $indent + 2)
+        ).($willBeInlined ? "\n" : '');
+      }
+    }
+
+    return $output;
+  }
+}
diff --git a/www/plugins/yaml/sfyaml/sfYamlInline.php b/www/plugins/yaml/sfyaml/sfYamlInline.php
new file mode 100755 (executable)
index 0000000..f2e74bd
--- /dev/null
@@ -0,0 +1,424 @@
+<?php
+
+/*
+ * This file is part of the symfony package.
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * sfYamlInline implements a YAML parser/dumper for the YAML inline syntax.
+ *
+ * @package    symfony
+ * @subpackage yaml
+ * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version    SVN: $Id: sfYamlInline.class.php 16177 2009-03-11 08:32:48Z fabien $
+ */
+class sfYamlInline
+{
+  /**
+   * Convert a YAML string to a PHP array.
+   *
+   * @param string $value A YAML string
+   *
+   * @return array A PHP array representing the YAML string
+   */
+  static public function load($value)
+  {
+    $value = trim($value);
+
+    if (0 == strlen($value))
+    {
+      return '';
+    }
+
+    switch ($value[0])
+    {
+      case '[':
+        return self::parseSequence($value);
+      case '{':
+        return self::parseMapping($value);
+      default:
+        return self::parseScalar($value);
+    }
+  }
+
+  /**
+   * Dumps a given PHP variable to a YAML string.
+   *
+   * @param mixed $value The PHP variable to convert
+   *
+   * @return string The YAML string representing the PHP array
+   */
+  static public function dump($value)
+  {
+    $trueValues = '1.1' == sfYaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true');
+    $falseValues = '1.1' == sfYaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false');
+
+    switch (true)
+    {
+      case is_resource($value):
+        throw new InvalidArgumentException('Unable to dump PHP resources in a YAML file.');
+      case is_object($value):
+        return '!!php/object:'.serialize($value);
+      case is_array($value):
+        return self::dumpArray($value);
+      case null === $value:
+        return 'null';
+      case true === $value:
+        return 'true';
+      case false === $value:
+        return 'false';
+      case ctype_digit($value):
+        return is_string($value) ? "'$value'" : (int) $value;
+      case is_numeric($value):
+        return is_infinite($value) ? str_ireplace('INF', '.Inf', strval($value)) : (is_string($value) ? "'$value'" : $value);
+      case false !== strpos($value, "\n"):
+        return sprintf('"%s"', str_replace(array('"', "\n", "\r"), array('\\"', '\n', '\r'), $value));
+      case preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \#] | \A[ - ? | < > = ! % @ ]/x', $value):
+        return sprintf("'%s'", str_replace('\'', '\'\'', $value));
+      case '' == $value:
+        return "''";
+      case preg_match(self::getTimestampRegex(), $value):
+        return "'$value'";
+      case in_array(strtolower($value), $trueValues):
+        return "'$value'";
+      case in_array(strtolower($value), $falseValues):
+        return "'$value'";
+      case in_array(strtolower($value), array('null', '~')):
+        return "'$value'";
+      default:
+        return $value;
+    }
+  }
+
+  /**
+   * Dumps a PHP array to a YAML string.
+   *
+   * @param array $value The PHP array to dump
+   *
+   * @return string The YAML string representing the PHP array
+   */
+  static protected function dumpArray($value)
+  {
+    // array
+    $keys = array_keys($value);
+    if (
+      (1 == count($keys) && '0' == $keys[0])
+      ||
+      (count($keys) > 1 && array_reduce($keys, create_function('$v,$w', 'return (integer) $v + $w;'), 0) == count($keys) * (count($keys) - 1) / 2))
+    {
+      $output = array();
+      foreach ($value as $val)
+      {
+        $output[] = self::dump($val);
+      }
+
+      return sprintf('[%s]', implode(', ', $output));
+    }
+
+    // mapping
+    $output = array();
+    foreach ($value as $key => $val)
+    {
+      $output[] = sprintf('%s: %s', self::dump($key), self::dump($val));
+    }
+
+    return sprintf('{ %s }', implode(', ', $output));
+  }
+
+  /**
+   * Parses a scalar to a YAML string.
+   *
+   * @param scalar  $scalar
+   * @param string  $delimiters
+   * @param array   $stringDelimiter
+   * @param integer $i
+   * @param boolean $evaluate
+   *
+   * @return string A YAML string
+   */
+  static public function parseScalar($scalar, $delimiters = null, $stringDelimiters = array('"', "'"), &$i = 0, $evaluate = true)
+  {
+    if (in_array($scalar[$i], $stringDelimiters))
+    {
+      // quoted scalar
+      $output = self::parseQuotedScalar($scalar, $i);
+
+      // skip next delimiter
+      ++$i;
+    }
+    else
+    {
+      // "normal" string
+      if (!$delimiters)
+      {
+        $output = substr($scalar, $i);
+        $i += strlen($output);
+
+        // remove comments
+        if (false !== $strpos = strpos($output, ' #'))
+        {
+          $output = rtrim(substr($output, 0, $strpos));
+        }
+      }
+      else if (preg_match('/^(.+?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match))
+      {
+        $output = $match[1];
+        $i += strlen($output);
+      }
+      else
+      {
+        throw new InvalidArgumentException(sprintf('Malformed inline YAML string (%s).', $scalar));
+      }
+
+      $output = $evaluate ? self::evaluateScalar($output) : $output;
+    }
+
+    return $output;
+  }
+
+  /**
+   * Parses a quoted scalar to YAML.
+   *
+   * @param string  $scalar
+   * @param integer $i
+   *
+   * @return string A YAML string
+   */
+  static protected function parseQuotedScalar($scalar, &$i)
+  {
+    $delimiter = $scalar[$i];
+    ++$i;
+    $buffer = '';
+    $len = strlen($scalar);
+    $escaped = '"' == $delimiter ? '\\"' : "''";
+
+    while ($i < $len)
+    {
+      if (isset($scalar[$i + 1]) && $escaped == $scalar[$i].$scalar[$i + 1])
+      {
+        $buffer .= $delimiter;
+        ++$i;
+      }
+      else if ($delimiter == $scalar[$i])
+      {
+        break;
+      }
+      else
+      {
+        $buffer .= $scalar[$i];
+      }
+
+      ++$i;
+    }
+
+    if ('"' == $delimiter)
+    {
+      // evaluate the string
+      $buffer = str_replace(array('\\n', '\\r'), array("\n", "\r"), $buffer);
+                       if (strpos($buffer,'\\x')!==false){
+                               $buffer = preg_replace_callback(',\\\\x([0-9a-f]+),', create_function('$m', 'return chr(hexdec($m[1]));'), $buffer);
+                       }
+    }
+
+    return $buffer;
+  }
+
+  /**
+   * Parses a sequence to a YAML string.
+   *
+   * @param string  $sequence
+   * @param integer $i
+   *
+   * @return string A YAML string
+   */
+  static protected function parseSequence($sequence, &$i = 0)
+  {
+    $output = array();
+    $len = strlen($sequence);
+    $i += 1;
+
+    // [foo, bar, ...]
+    while ($i < $len)
+    {
+      switch ($sequence[$i])
+      {
+        case '[':
+          // nested sequence
+          $output[] = self::parseSequence($sequence, $i);
+          break;
+        case '{':
+          // nested mapping
+          $output[] = self::parseMapping($sequence, $i);
+          break;
+        case ']':
+          return $output;
+        case ',':
+        case ' ':
+          break;
+        default:
+          $isQuoted = in_array($sequence[$i], array('"', "'"));
+          $value = self::parseScalar($sequence, array(',', ']'), array('"', "'"), $i);
+
+          if (!$isQuoted && false !== strpos($value, ': '))
+          {
+            // embedded mapping?
+            try
+            {
+              $value = self::parseMapping('{'.$value.'}');
+            }
+            catch (InvalidArgumentException $e)
+            {
+              // no, it's not
+            }
+          }
+
+          $output[] = $value;
+
+          --$i;
+      }
+
+      ++$i;
+    }
+
+    throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $sequence));
+  }
+
+  /**
+   * Parses a mapping to a YAML string.
+   *
+   * @param string  $mapping
+   * @param integer $i
+   *
+   * @return string A YAML string
+   */
+  static protected function parseMapping($mapping, &$i = 0)
+  {
+    $output = array();
+    $len = strlen($mapping);
+    $i += 1;
+
+    // {foo: bar, bar:foo, ...}
+    while ($i < $len)
+    {
+      switch ($mapping[$i])
+      {
+        case ' ':
+        case ',':
+          ++$i;
+          continue 2;
+        case '}':
+          return $output;
+      }
+
+      // key
+      $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false);
+
+      // value
+      $done = false;
+      while ($i < $len)
+      {
+        switch ($mapping[$i])
+        {
+          case '[':
+            // nested sequence
+            $output[$key] = self::parseSequence($mapping, $i);
+            $done = true;
+            break;
+          case '{':
+            // nested mapping
+            $output[$key] = self::parseMapping($mapping, $i);
+            $done = true;
+            break;
+          case ':':
+          case ' ':
+            break;
+          default:
+            $output[$key] = self::parseScalar($mapping, array(',', '}'), array('"', "'"), $i);
+            $done = true;
+            --$i;
+        }
+
+        ++$i;
+
+        if ($done)
+        {
+          continue 2;
+        }
+      }
+    }
+
+    throw new InvalidArgumentException(sprintf('Malformed inline YAML string %s', $mapping));
+  }
+
+  /**
+   * Evaluates scalars and replaces magic values.
+   *
+   * @param string $scalar
+   *
+   * @return string A YAML string
+   */
+  static protected function evaluateScalar($scalar)
+  {
+    $scalar = trim($scalar);
+
+    $trueValues = '1.1' == sfYaml::getSpecVersion() ? array('true', 'on', '+', 'yes', 'y') : array('true');
+    $falseValues = '1.1' == sfYaml::getSpecVersion() ? array('false', 'off', '-', 'no', 'n') : array('false');
+
+    switch (true)
+    {
+      case 'null' == strtolower($scalar):
+      case '' == $scalar:
+      case '~' == $scalar:
+        return null;
+      case 0 === strpos($scalar, '!str'):
+        return (string) substr($scalar, 5);
+      case 0 === strpos($scalar, '! '):
+        return intval(self::parseScalar(substr($scalar, 2)));
+      case 0 === strpos($scalar, '!!php/object:'):
+        return unserialize(substr($scalar, 13));
+      case ctype_digit($scalar):
+        $raw = $scalar;
+        $cast = intval($scalar);
+        return '0' == $scalar[0] ? octdec($scalar) : (((string) $raw == (string) $cast) ? $cast : $raw);
+      case in_array(strtolower($scalar), $trueValues):
+        return true;
+      case in_array(strtolower($scalar), $falseValues):
+        return false;
+      case is_numeric($scalar):
+        return '0x' == $scalar[0].$scalar[1] ? hexdec($scalar) : floatval($scalar);
+      case 0 == strcasecmp($scalar, '.inf'):
+      case 0 == strcasecmp($scalar, '.NaN'):
+        return -log(0);
+      case 0 == strcasecmp($scalar, '-.inf'):
+        return log(0);
+      case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
+        return floatval(str_replace(',', '', $scalar));
+      case preg_match(self::getTimestampRegex(), $scalar):
+        return strtotime($scalar);
+      default:
+        return (string) $scalar;
+    }
+  }
+
+  static protected function getTimestampRegex()
+  {
+    return <<<EOF
+    ~^
+    (?P<year>[0-9][0-9][0-9][0-9])
+    -(?P<month>[0-9][0-9]?)
+    -(?P<day>[0-9][0-9]?)
+    (?:(?:[Tt]|[ \t]+)
+    (?P<hour>[0-9][0-9]?)
+    :(?P<minute>[0-9][0-9])
+    :(?P<second>[0-9][0-9])
+    (?:\.(?P<fraction>[0-9]*))?
+    (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
+    (?::(?P<tz_minute>[0-9][0-9]))?))?)?
+    $~x
+EOF;
+  }
+}
diff --git a/www/plugins/yaml/sfyaml/sfYamlParser.php b/www/plugins/yaml/sfyaml/sfYamlParser.php
new file mode 100755 (executable)
index 0000000..baa5f76
--- /dev/null
@@ -0,0 +1,540 @@
+<?php
+
+/*
+ * This file is part of the symfony package.
+ * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+require_once(dirname(__FILE__).'/sfYamlInline.php');
+
+/**
+ * sfYamlParser parses YAML strings to convert them to PHP arrays.
+ *
+ * @package    symfony
+ * @subpackage yaml
+ * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version    SVN: $Id: sfYamlParser.class.php 10832 2008-08-13 07:46:08Z fabien $
+ */
+class sfYamlParser
+{
+  protected
+    $value         = '',
+    $offset        = 0,
+    $lines         = array(),
+    $currentLineNb = -1,
+    $currentLine   = '',
+    $refs          = array();
+
+  /**
+   * Constructor
+   *
+   * @param integer $offset The offset of YAML document (used for line numbers in error messages)
+   */
+  public function __construct($offset = 0)
+  {
+    $this->offset = $offset;
+  }
+
+  /**
+   * Parses a YAML string to a PHP value.
+   *
+   * @param  string $value A YAML string
+   *
+   * @return mixed  A PHP value
+   *
+   * @throws InvalidArgumentException If the YAML is not valid
+   */
+  public function parse($value)
+  {
+    $this->value = $this->cleanup($value);
+    $this->currentLineNb = -1;
+    $this->currentLine = '';
+    $this->lines = explode("\n", $this->value);
+
+    $data = array();
+    while ($this->moveToNextLine())
+    {
+      if ($this->isCurrentLineEmpty())
+      {
+        continue;
+      }
+
+      // tab?
+      if (preg_match('#^\t+#', $this->currentLine))
+      {
+        throw new InvalidArgumentException(sprintf('A YAML file cannot contain tabs as indentation at line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
+      }
+
+      $isRef = $isInPlace = $isProcessed = false;
+      if (preg_match('#^\-(\s+(?P<value>.+?))?\s*$#', $this->currentLine, $values))
+      {
+        if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#', $values['value'], $matches))
+        {
+          $isRef = $matches['ref'];
+          $values['value'] = $matches['value'];
+        }
+
+        // array
+        if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
+        {
+          $c = $this->getRealCurrentLineNb() + 1;
+          $parser = new sfYamlParser($c);
+          $parser->refs =& $this->refs;
+          $data[] = $parser->parse($this->getNextEmbedBlock());
+        }
+        else
+        {
+          if (preg_match('/^([^ ]+)\: +({.*?)$/', $values['value'], $matches))
+          {
+            $data[] = array($matches[1] => sfYamlInline::load($matches[2]));
+          }
+          else
+          {
+            $data[] = $this->parseValue($values['value']);
+          }
+        }
+      }
+      else if (preg_match('#^(?P<key>[^ ].*?) *\:(\s+(?P<value>.+?))?\s*$#', $this->currentLine, $values))
+      {
+        $key = sfYamlInline::parseScalar($values['key']);
+
+        if ('<<' === $key)
+        {
+          if (isset($values['value']) && '*' === substr($values['value'], 0, 1))
+          {
+            $isInPlace = substr($values['value'], 1);
+            if (!array_key_exists($isInPlace, $this->refs))
+            {
+              throw new InvalidArgumentException(sprintf('Reference "%s" does not exist at line %s (%s).', $isInPlace, $this->getRealCurrentLineNb() + 1, $this->currentLine));
+            }
+          }
+          else
+          {
+            if (isset($values['value']) && $values['value'] !== '')
+            {
+              $value = $values['value'];
+            }
+            else
+            {
+              $value = $this->getNextEmbedBlock();
+            }
+            $c = $this->getRealCurrentLineNb() + 1;
+            $parser = new sfYamlParser($c);
+            $parser->refs =& $this->refs;
+            $parsed = $parser->parse($value);
+
+            $merged = array();
+            if (!is_array($parsed))
+            {
+              throw new InvalidArgumentException(sprintf("YAML merge keys used with a scalar value instead of an array at line %s (%s)", $this->getRealCurrentLineNb() + 1, $this->currentLine));
+            }
+            else if (isset($parsed[0]))
+            {
+              // Numeric array, merge individual elements
+              foreach (array_reverse($parsed) as $parsedItem)
+              {
+                if (!is_array($parsedItem))
+                {
+                  throw new InvalidArgumentException(sprintf("Merge items must be arrays at line %s (%s).", $this->getRealCurrentLineNb() + 1, $parsedItem));
+                }
+                $merged = array_merge($parsedItem, $merged);
+              }
+            }
+            else
+            {
+              // Associative array, merge
+              $merged = array_merge($merge, $parsed);
+            }
+
+            $isProcessed = $merged;
+          }
+        }
+        else if (isset($values['value']) && preg_match('#^&(?P<ref>[^ ]+) *(?P<value>.*)#', $values['value'], $matches))
+        {
+          $isRef = $matches['ref'];
+          $values['value'] = $matches['value'];
+        }
+
+        if ($isProcessed)
+        {
+          // Merge keys
+          $data = $isProcessed;
+        }
+        // hash
+        else if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#'))
+        {
+          // if next line is less indented or equal, then it means that the current value is null
+          if ($this->isNextLineIndented())
+          {
+            $data[$key] = null;
+          }
+          else
+          {
+            $c = $this->getRealCurrentLineNb() + 1;
+            $parser = new sfYamlParser($c);
+            $parser->refs =& $this->refs;
+            $data[$key] = $parser->parse($this->getNextEmbedBlock());
+          }
+        }
+        else
+        {
+          if ($isInPlace)
+          {
+            $data = $this->refs[$isInPlace];
+          }
+          else
+          {
+            $data[$key] = $this->parseValue($values['value']);
+          }
+        }
+      }
+      else
+      {
+        // one liner?
+        if (1 == count(explode("\n", rtrim($this->value, "\n"))))
+        {
+          $value = sfYamlInline::load($this->lines[0]);
+          if (is_array($value))
+          {
+            $first = reset($value);
+            if ('*' === substr($first, 0, 1))
+            {
+              $data = array();
+              foreach ($value as $alias)
+              {
+                $data[] = $this->refs[substr($alias, 1)];
+              }
+              $value = $data;
+            }
+          }
+
+          return $value;
+        }
+
+        throw new InvalidArgumentException(sprintf('Unable to parse line %d (%s).', $this->getRealCurrentLineNb() + 1, $this->currentLine));
+      }
+
+      if ($isRef)
+      {
+        $this->refs[$isRef] = end($data);
+      }
+    }
+
+    return empty($data) ? null : $data;
+  }
+
+  /**
+   * Returns the current line number (takes the offset into account).
+   *
+   * @return integer The current line number
+   */
+  protected function getRealCurrentLineNb()
+  {
+    return $this->currentLineNb + $this->offset;
+  }
+
+  /**
+   * Returns the current line indentation.
+   *
+   * @return integer The current line indentation
+   */
+  protected function getCurrentLineIndentation()
+  {
+    return strlen($this->currentLine) - strlen(ltrim($this->currentLine, ' '));
+  }
+
+  /**
+   * Returns the next embed block of YAML.
+   *
+   * @return string A YAML string
+   */
+  protected function getNextEmbedBlock()
+  {
+    $this->moveToNextLine();
+
+    $newIndent = $this->getCurrentLineIndentation();
+
+    if (!$this->isCurrentLineEmpty() && 0 == $newIndent)
+    {
+      throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
+    }
+
+    $data = array(substr($this->currentLine, $newIndent));
+
+    while ($this->moveToNextLine())
+    {
+      if ($this->isCurrentLineEmpty())
+      {
+        if ($this->isCurrentLineBlank())
+        {
+          $data[] = substr($this->currentLine, $newIndent);
+        }
+
+        continue;
+      }
+
+      $indent = $this->getCurrentLineIndentation();
+
+      if (preg_match('#^(?P<text> *)$#', $this->currentLine, $match))
+      {
+        // empty line
+        $data[] = $match['text'];
+      }
+      else if ($indent >= $newIndent)
+      {
+        $data[] = substr($this->currentLine, $newIndent);
+      }
+      else if (0 == $indent)
+      {
+        $this->moveToPreviousLine();
+
+        break;
+      }
+      else
+      {
+        throw new InvalidArgumentException(sprintf('Indentation problem at line %d (%s)', $this->getRealCurrentLineNb() + 1, $this->currentLine));
+      }
+    }
+
+    return implode("\n", $data);
+  }
+
+  /**
+   * Moves the parser to the next line.
+   */
+  protected function moveToNextLine()
+  {
+    if ($this->currentLineNb >= count($this->lines) - 1)
+    {
+      return false;
+    }
+
+    $this->currentLine = $this->lines[++$this->currentLineNb];
+
+    return true;
+  }
+
+  /**
+   * Moves the parser to the previous line.
+   */
+  protected function moveToPreviousLine()
+  {
+    $this->currentLine = $this->lines[--$this->currentLineNb];
+  }
+
+  /**
+   * Parses a YAML value.
+   *
+   * @param  string $value A YAML value
+   *
+   * @return mixed  A PHP value
+   */
+  protected function parseValue($value)
+  {
+    if ('*' === substr($value, 0, 1))
+    {
+      if (false !== $pos = strpos($value, '#'))
+      {
+        $value = substr($value, 1, $pos - 2);
+      }
+      else
+      {
+        $value = substr($value, 1);
+      }
+
+      if (!array_key_exists($value, $this->refs))
+      {
+        throw new InvalidArgumentException(sprintf('Reference "%s" does not exist (%s).', $value, $this->currentLine));
+      }
+      return $this->refs[$value];
+    }
+
+    if (preg_match('/^(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?$/', $value, $matches))
+    {
+      $modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
+
+      return $this->parseFoldedScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), intval(abs($modifiers)));
+    }
+    else
+    {
+      return sfYamlInline::load($value);
+    }
+  }
+
+  /**
+   * Parses a folded scalar.
+   *
+   * @param  string  $separator   The separator that was used to begin this folded scalar (| or >)
+   * @param  string  $indicator   The indicator that was used to begin this folded scalar (+ or -)
+   * @param  integer $indentation The indentation that was used to begin this folded scalar
+   *
+   * @return string  The text value
+   */
+  protected function parseFoldedScalar($separator, $indicator = '', $indentation = 0)
+  {
+    $separator = '|' == $separator ? "\n" : ' ';
+    $text = '';
+
+    $notEOF = $this->moveToNextLine();
+
+    while ($notEOF && $this->isCurrentLineBlank())
+    {
+      $text .= "\n";
+
+      $notEOF = $this->moveToNextLine();
+    }
+
+    if (!$notEOF)
+    {
+      return '';
+    }
+
+    if (!preg_match('#^(?P<indent>'.($indentation ? str_repeat(' ', $indentation) : ' +').')(?P<text>.*)$#', $this->currentLine, $matches))
+    {
+      $this->moveToPreviousLine();
+
+      return '';
+    }
+
+    $textIndent = $matches['indent'];
+    $previousIndent = 0;
+
+    $text .= $matches['text'].$separator;
+    while ($this->currentLineNb + 1 < count($this->lines))
+    {
+      $this->moveToNextLine();
+
+      if (preg_match('#^(?P<indent> {'.strlen($textIndent).',})(?P<text>.+)$#', $this->currentLine, $matches))
+      {
+        if (' ' == $separator && $previousIndent != $matches['indent'])
+        {
+          $text = substr($text, 0, -1)."\n";
+        }
+        $previousIndent = $matches['indent'];
+
+        $text .= str_repeat(' ', $diff = strlen($matches['indent']) - strlen($textIndent)).$matches['text'].($diff ? "\n" : $separator);
+      }
+      else if (preg_match('#^(?P<text> *)$#', $this->currentLine, $matches))
+      {
+        $text .= preg_replace('#^ {1,'.strlen($textIndent).'}#', '', $matches['text'])."\n";
+      }
+      else
+      {
+        $this->moveToPreviousLine();
+
+        break;
+      }
+    }
+
+    if (' ' == $separator)
+    {
+      // replace last separator by a newline
+      $text = preg_replace('/ (\n*)$/', "\n$1", $text);
+    }
+
+    switch ($indicator)
+    {
+      case '':
+        $text = preg_replace('#\n+$#s', "\n", $text);
+        break;
+      case '+':
+        break;
+      case '-':
+        $text = preg_replace('#\n+$#s', '', $text);
+        break;
+    }
+
+    return $text;
+  }
+
+  /**
+   * Returns true if the next line is indented.
+   *
+   * @return Boolean Returns true if the next line is indented, false otherwise
+   */
+  protected function isNextLineIndented()
+  {
+    $currentIndentation = $this->getCurrentLineIndentation();
+    $notEOF = $this->moveToNextLine();
+
+    while ($notEOF && $this->isCurrentLineEmpty())
+    {
+      $notEOF = $this->moveToNextLine();
+    }
+
+    if (false === $notEOF)
+    {
+      return false;
+    }
+
+    $ret = false;
+    if ($this->getCurrentLineIndentation() <= $currentIndentation)
+    {
+      $ret = true;
+    }
+
+    $this->moveToPreviousLine();
+
+    return $ret;
+  }
+
+  /**
+   * Returns true if the current line is blank or if it is a comment line.
+   *
+   * @return Boolean Returns true if the current line is empty or if it is a comment line, false otherwise
+   */
+  protected function isCurrentLineEmpty()
+  {
+    return $this->isCurrentLineBlank() || $this->isCurrentLineComment();
+  }
+
+  /**
+   * Returns true if the current line is blank.
+   *
+   * @return Boolean Returns true if the current line is blank, false otherwise
+   */
+  protected function isCurrentLineBlank()
+  {
+    return '' == trim($this->currentLine, ' ');
+  }
+
+  /**
+   * Returns true if the current line is a comment line.
+   *
+   * @return Boolean Returns true if the current line is a comment line, false otherwise
+   */
+  protected function isCurrentLineComment()
+  {
+    //checking explicitly the first char of the trim is faster than loops or strpos
+    $ltrimmedLine = ltrim($this->currentLine, ' ');
+    return $ltrimmedLine[0] === '#';
+  }
+
+  /**
+   * Cleanups a YAML string to be parsed.
+   *
+   * @param  string $value The input YAML string
+   *
+   * @return string A cleaned up YAML string
+   */
+  protected function cleanup($value)
+  {
+    $value = str_replace(array("\r\n", "\r"), "\n", $value);
+
+    if (!preg_match("#\n$#", $value))
+    {
+      $value .= "\n";
+    }
+
+    // strip YAML header
+    preg_replace('#^\%YAML[: ][\d\.]+.*\n#s', '', $value);
+
+    // remove ---
+    $value = preg_replace('#^\-\-\-.*?\n#s', '', $value);
+
+    return $value;
+  }
+}
diff --git a/www/plugins/yaml/spyc/spyc-php4.php b/www/plugins/yaml/spyc/spyc-php4.php
new file mode 100644 (file)
index 0000000..9329268
--- /dev/null
@@ -0,0 +1,1024 @@
+<?php
+/**
+   * Spyc -- A Simple PHP YAML Class
+   * @version 0.4.5
+   * @author Vlad Andersen <vlad.andersen@gmail.com>
+   * @author Chris Wanstrath <chris@ozmm.org>
+   * @link http://code.google.com/p/spyc/
+   * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2009 Vlad Andersen
+   * @license http://www.opensource.org/licenses/mit-license.php MIT License
+   * @package Spyc
+   */
+
+if (!function_exists('spyc_load')) {
+  /**
+   * Parses YAML to array.
+   * @param string $string YAML string.
+   * @return array
+   */
+  function spyc_load ($string) {
+    return Spyc::YAMLLoadString($string);
+  }
+}
+
+if (!function_exists('spyc_load_file')) {
+  /**
+   * Parses YAML to array.
+   * @param string $file Path to YAML file.
+   * @return array
+   */
+  function spyc_load_file ($file) {
+    return Spyc::YAMLLoad($file);
+  }
+}
+
+/**
+   * The Simple PHP YAML Class.
+   *
+   * This class can be used to read a YAML file and convert its contents
+   * into a PHP array.  It currently supports a very limited subsection of
+   * the YAML spec.
+   *
+   * Usage:
+   * <code>
+   *   $Spyc  = new Spyc;
+   *   $array = $Spyc->load($file);
+   * </code>
+   * or:
+   * <code>
+   *   $array = Spyc::YAMLLoad($file);
+   * </code>
+   * or:
+   * <code>
+   *   $array = spyc_load_file($file);
+   * </code>
+   * @package Spyc
+   */
+class Spyc {
+
+  // SETTINGS
+
+  /**
+   * Setting this to true will force YAMLDump to enclose any string value in
+   * quotes.  False by default.
+   * 
+   * @var bool
+   */
+  var $setting_dump_force_quotes = false;
+
+  /**
+   * Setting this to true will forse YAMLLoad to use syck_load function when
+   * possible. False by default.
+   * @var bool
+   */
+  var $setting_use_syck_is_possible = false;
+
+
+
+  /**#@+
+  * @access private
+  * @var mixed
+  */
+  var $_dumpIndent;
+  var $_dumpWordWrap;
+  var $_containsGroupAnchor = false;
+  var $_containsGroupAlias = false;
+  var $path;
+  var $result;
+  var $LiteralPlaceHolder = '___YAML_Literal_Block___';
+  var $SavedGroups = array();
+  var $indent;
+  /**
+   * Path modifier that should be applied after adding current element.
+   * @var array
+   */
+  var $delayedPath = array();
+
+  /**#@+
+  * @access public
+  * @var mixed
+  */
+  var $_nodeId;
+
+/**
+ * Load a valid YAML string to Spyc.
+ * @param string $input
+ * @return array
+ */
+  function load ($input) {
+    return $this->__loadString($input);
+  }
+
+ /**
+ * Load a valid YAML file to Spyc.
+ * @param string $file
+ * @return array
+ */
+  function loadFile ($file) {
+    return $this->__load($file);
+  }
+
+  /**
+     * Load YAML into a PHP array statically
+     *
+     * The load method, when supplied with a YAML stream (string or file),
+     * will do its best to convert YAML in a file into a PHP array.  Pretty
+     * simple.
+     *  Usage:
+     *  <code>
+     *   $array = Spyc::YAMLLoad('lucky.yaml');
+     *   print_r($array);
+     *  </code>
+     * @access public
+     * @return array
+     * @param string $input Path of YAML file or string containing YAML
+     */
+  function YAMLLoad($input) {
+    $Spyc = new Spyc;
+    return $Spyc->__load($input);
+  }
+
+  /**
+     * Load a string of YAML into a PHP array statically
+     *
+     * The load method, when supplied with a YAML string, will do its best 
+     * to convert YAML in a string into a PHP array.  Pretty simple.
+     *
+     * Note: use this function if you don't want files from the file system
+     * loaded and processed as YAML.  This is of interest to people concerned
+     * about security whose input is from a string.
+     *
+     *  Usage:
+     *  <code>
+     *   $array = Spyc::YAMLLoadString("---\n0: hello world\n");
+     *   print_r($array);
+     *  </code>
+     * @access public
+     * @return array
+     * @param string $input String containing YAML
+     */
+  function YAMLLoadString($input) {
+    $Spyc = new Spyc;
+    return $Spyc->__loadString($input);
+  }
+
+  /**
+     * Dump YAML from PHP array statically
+     *
+     * The dump method, when supplied with an array, will do its best
+     * to convert the array into friendly YAML.  Pretty simple.  Feel free to
+     * save the returned string as nothing.yaml and pass it around.
+     *
+     * Oh, and you can decide how big the indent is and what the wordwrap
+     * for folding is.  Pretty cool -- just pass in 'false' for either if
+     * you want to use the default.
+     *
+     * Indent's default is 2 spaces, wordwrap's default is 40 characters.  And
+     * you can turn off wordwrap by passing in 0.
+     *
+     * @access public
+     * @return string
+     * @param array $array PHP array
+     * @param int $indent Pass in false to use the default, which is 2
+     * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+     */
+  function YAMLDump($array,$indent = false,$wordwrap = false) {
+    $spyc = new Spyc;
+    return $spyc->dump($array,$indent,$wordwrap);
+  }
+
+
+  /**
+     * Dump PHP array to YAML
+     *
+     * The dump method, when supplied with an array, will do its best
+     * to convert the array into friendly YAML.  Pretty simple.  Feel free to
+     * save the returned string as tasteful.yaml and pass it around.
+     *
+     * Oh, and you can decide how big the indent is and what the wordwrap
+     * for folding is.  Pretty cool -- just pass in 'false' for either if
+     * you want to use the default.
+     *
+     * Indent's default is 2 spaces, wordwrap's default is 40 characters.  And
+     * you can turn off wordwrap by passing in 0.
+     *
+     * @access public
+     * @return string
+     * @param array $array PHP array
+     * @param int $indent Pass in false to use the default, which is 2
+     * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+     */
+  function dump($array,$indent = false,$wordwrap = false) {
+    // Dumps to some very clean YAML.  We'll have to add some more features
+    // and options soon.  And better support for folding.
+
+    // New features and options.
+    if ($indent === false or !is_numeric($indent)) {
+      $this->_dumpIndent = 2;
+    } else {
+      $this->_dumpIndent = $indent;
+    }
+
+    if ($wordwrap === false or !is_numeric($wordwrap)) {
+      $this->_dumpWordWrap = 40;
+    } else {
+      $this->_dumpWordWrap = $wordwrap;
+    }
+
+    // New YAML document
+    $string = "---\n";
+
+    // Start at the base of the array and move through it.
+    if ($array) {
+      $array = (array)$array;
+      $first_key = key($array);
+      
+      $previous_key = -1;
+      foreach ($array as $key => $value) {
+        $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key);
+        $previous_key = $key;
+      }
+    }
+    return $string;
+  }
+
+  /**
+     * Attempts to convert a key / value array item to YAML
+     * @access private
+     * @return string
+     * @param $key The name of the key
+     * @param $value The value of the item
+     * @param $indent The indent of the current node
+     */
+  function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0) {
+    if (is_array($value)) {
+      if (empty ($value))
+        return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key);
+      // It has children.  What to do?
+      // Make it the right kind of item
+      $string = $this->_dumpNode($key, NULL, $indent, $previous_key, $first_key);
+      // Add the indent
+      $indent += $this->_dumpIndent;
+      // Yamlize the array
+      $string .= $this->_yamlizeArray($value,$indent);
+    } elseif (!is_array($value)) {
+      // It doesn't have children.  Yip.
+      $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key);
+    }
+    return $string;
+  }
+
+  /**
+     * Attempts to convert an array to YAML
+     * @access private
+     * @return string
+     * @param $array The array you want to convert
+     * @param $indent The indent of the current level
+     */
+  function _yamlizeArray($array,$indent) {
+    if (is_array($array)) {
+      $string = '';
+      $previous_key = -1;
+      $first_key = key($array);
+      foreach ($array as $key => $value) {
+        $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key);
+        $previous_key = $key;
+      }
+      return $string;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+     * Returns YAML from a key and a value
+     * @access private
+     * @return string
+     * @param $key The name of the key
+     * @param $value The value of the item
+     * @param $indent The indent of the current node
+     */
+  function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0) {
+    // do some folding here, for blocks
+    if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
+      strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false ||
+      strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || substr ($value, -1, 1) == ':')) {
+      $value = $this->_doLiteralBlock($value,$indent);
+    } else {
+      $value  = $this->_doFolding($value,$indent);
+      if (is_bool($value)) {
+        $value = ($value) ? "true" : "false";
+      }
+    }
+
+    if ($value === array()) $value = '[ ]';
+
+    $spaces = str_repeat(' ',$indent);
+
+    if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
+      // It's a sequence
+      $string = $spaces.'- '.$value."\n";
+    } else {
+      // Ligne ci-dessous désactivée car non compatible PHP4
+         //if ($first_key===0)  throw new Exception('Keys are all screwy.  The first one was zero, now it\'s "'. $key .'"');
+      // It's mapped
+      if (strpos($key, ":") !== false) { $key = '"' . $key . '"'; }
+      $string = $spaces.$key.': '.$value."\n";
+    }
+    return $string;
+  }
+
+  /**
+     * Creates a literal block for dumping
+     * @access private
+     * @return string
+     * @param $value
+     * @param $indent int The value of the indent
+     */
+  function _doLiteralBlock($value,$indent) {
+    if (strpos($value, "\n") === false && strpos($value, "'") === false) {
+      return sprintf ("'%s'", $value);
+    }
+    if (strpos($value, "\n") === false && strpos($value, '"') === false) {
+      return sprintf ('"%s"', $value);
+    }
+    $exploded = explode("\n",$value);
+    $newValue = '|';
+    $indent  += $this->_dumpIndent;
+    $spaces   = str_repeat(' ',$indent);
+    foreach ($exploded as $line) {
+      $newValue .= "\n" . $spaces . trim($line);
+    }
+    return $newValue;
+  }
+
+  /**
+     * Folds a string of text, if necessary
+     * @access private
+     * @return string
+     * @param $value The string you wish to fold
+     */
+  function _doFolding($value,$indent) {
+    // Don't do anything if wordwrap is set to 0
+
+    if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
+      $indent += $this->_dumpIndent;
+      $indent = str_repeat(' ',$indent);
+      $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
+      $value   = ">\n".$indent.$wrapped;
+    } else {
+      if ($this->setting_dump_force_quotes && is_string ($value))
+        $value = '"' . $value . '"';
+    }
+
+
+    return $value;
+  }
+
+// LOADING FUNCTIONS
+
+  function __load($input) {
+    $Source = $this->loadFromSource($input);
+    return $this->loadWithSource($Source);
+  }
+
+  function __loadString($input) {
+    $Source = $this->loadFromString($input);
+    return $this->loadWithSource($Source);
+  }
+
+  function loadWithSource($Source) {
+    if (empty ($Source)) return array();
+    if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
+      $array = syck_load (implode ('', $Source));
+      return is_array($array) ? $array : array();
+    }
+
+    $this->path = array();
+    $this->result = array();
+
+    $cnt = count($Source);
+    for ($i = 0; $i < $cnt; $i++) {
+      $line = $Source[$i];
+      
+      $this->indent = strlen($line) - strlen(ltrim($line));
+      $tempPath = $this->getParentPathByIndent($this->indent);
+      $line = $this->stripIndent($line, $this->indent);
+      if ($this->isComment($line)) continue;
+      if ($this->isEmpty($line)) continue;
+      $this->path = $tempPath;
+
+      $literalBlockStyle = $this->startsLiteralBlock($line);
+      if ($literalBlockStyle) {
+        $line = rtrim ($line, $literalBlockStyle . " \n");
+        $literalBlock = '';
+        $line .= $this->LiteralPlaceHolder;
+
+        while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
+          $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle);
+        }
+        $i--;
+      }
+
+      while (++$i < $cnt && $this->greedilyNeedNextLine($line)) {
+        $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
+      }
+      $i--;
+
+
+
+      if (strpos ($line, '#')) {
+        if (strpos ($line, '"') === false && strpos ($line, "'") === false)
+          $line = preg_replace('/\s+#(.+)$/','',$line);
+      }
+
+      $lineArray = $this->_parseLine($line);
+
+      if ($literalBlockStyle)
+        $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
+
+      $this->addArray($lineArray, $this->indent);
+
+      foreach ($this->delayedPath as $indent => $delayedPath)
+        $this->path[$indent] = $delayedPath;
+
+      $this->delayedPath = array();
+
+    }
+    return $this->result;
+  }
+
+  function loadFromSource ($input) {
+    if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
+    return file($input);
+
+    return $this->loadFromString($input);
+  }
+
+  function loadFromString ($input) {
+    $lines = explode("\n",$input);
+    foreach ($lines as $k => $_) {
+      $lines[$k] = rtrim ($_, "\r");
+    }
+    return $lines;
+  }
+
+  /**
+     * Parses YAML code and returns an array for a node
+     * @access private
+     * @return array
+     * @param string $line A line from the YAML file
+     */
+  function _parseLine($line) {
+    if (!$line) return array();
+    $line = trim($line);
+
+    if (!$line) return array();
+    $array = array();
+
+    $group = $this->nodeContainsGroup($line);
+    if ($group) {
+      $this->addGroup($line, $group);
+      $line = $this->stripGroup ($line, $group);
+    }
+
+    if ($this->startsMappedSequence($line))
+      return $this->returnMappedSequence($line);
+
+    if ($this->startsMappedValue($line))
+      return $this->returnMappedValue($line);
+
+    if ($this->isArrayElement($line))
+     return $this->returnArrayElement($line);
+
+    if ($this->isPlainArray($line))
+     return $this->returnPlainArray($line); 
+     
+     
+    return $this->returnKeyValuePair($line);
+
+  }
+
+  /**
+     * Finds the type of the passed value, returns the value as the new type.
+     * @access private
+     * @param string $value
+     * @return mixed
+     */
+  function _toType($value) {
+    if ($value === '') return null;
+    $first_character = $value[0];
+    $last_character = substr($value, -1, 1);
+
+    $is_quoted = false;
+    do {
+      if (!$value) break;
+      if ($first_character != '"' && $first_character != "'") break;
+      if ($last_character != '"' && $last_character != "'") break;
+      $is_quoted = true;
+    } while (0);
+
+    if ($is_quoted)
+      return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\''));
+    
+    if (strpos($value, ' #') !== false)
+      $value = preg_replace('/\s+#(.+)$/','',$value);
+
+    if ($first_character == '[' && $last_character == ']') {
+      // Take out strings sequences and mappings
+      $innerValue = trim(substr ($value, 1, -1));
+      if ($innerValue === '') return array();
+      $explode = $this->_inlineEscape($innerValue);
+      // Propagate value array
+      $value  = array();
+      foreach ($explode as $v) {
+        $value[] = $this->_toType($v);
+      }
+      return $value;
+    }
+
+    if (strpos($value,': ')!==false && $first_character != '{') {
+      $array = explode(': ',$value);
+      $key   = trim($array[0]);
+      array_shift($array);
+      $value = trim(implode(': ',$array));
+      $value = $this->_toType($value);
+      return array($key => $value);
+    }
+    
+    if ($first_character == '{' && $last_character == '}') {
+      $innerValue = trim(substr ($value, 1, -1));
+      if ($innerValue === '') return array();
+      // Inline Mapping
+      // Take out strings sequences and mappings
+      $explode = $this->_inlineEscape($innerValue);
+      // Propagate value array
+      $array = array();
+      foreach ($explode as $v) {
+        $SubArr = $this->_toType($v);
+        if (empty($SubArr)) continue;
+        if (is_array ($SubArr)) {
+          $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
+        }
+        $array[] = $SubArr;
+      }
+      return $array;
+    }
+
+    if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
+      return null;
+    }
+
+    if (intval($first_character) > 0 && preg_match ('/^[1-9]+[0-9]*$/', $value)) {
+      $intvalue = (int)$value;
+      if ($intvalue != PHP_INT_MAX)
+        $value = $intvalue;
+      return $value;
+    }
+
+    if (in_array($value,
+                 array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) {
+      return true;
+    }
+
+    if (in_array(strtolower($value),
+                 array('false', 'off', '-', 'no', 'n'))) {
+      return false;
+    }
+
+    if (is_numeric($value)) {
+      if ($value === '0') return 0;
+      if (trim ($value, 0) === $value)
+        $value = (float)$value;
+      return $value;
+    }
+    
+    return $value;
+  }
+
+  /**
+     * Used in inlines to check for more inlines or quoted strings
+     * @access private
+     * @return array
+     */
+  function _inlineEscape($inline) {
+    // There's gotta be a cleaner way to do this...
+    // While pure sequences seem to be nesting just fine,
+    // pure mappings and mappings with sequences inside can't go very
+    // deep.  This needs to be fixed.
+
+    $seqs = array();
+    $maps = array();
+    $saved_strings = array();
+
+    // Check for strings
+    $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
+    if (preg_match_all($regex,$inline,$strings)) {
+      $saved_strings = $strings[0];
+      $inline  = preg_replace($regex,'YAMLString',$inline);
+    }
+    unset($regex);
+
+    $i = 0;
+    do {
+
+    // Check for sequences
+    while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
+      $seqs[] = $matchseqs[0];
+      $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
+    }
+
+    // Check for mappings
+    while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
+      $maps[] = $matchmaps[0];
+      $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
+    }
+
+    if ($i++ >= 10) break;
+
+    } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
+
+    $explode = explode(', ',$inline);
+    $stringi = 0; $i = 0;
+
+    while (1) {
+
+    // Re-add the sequences
+    if (!empty($seqs)) {
+      foreach ($explode as $key => $value) {
+        if (strpos($value,'YAMLSeq') !== false) {
+          foreach ($seqs as $seqk => $seq) {
+            $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
+            $value = $explode[$key];
+          }
+        }
+      }
+    }
+
+    // Re-add the mappings
+    if (!empty($maps)) {
+      foreach ($explode as $key => $value) {
+        if (strpos($value,'YAMLMap') !== false) {
+          foreach ($maps as $mapk => $map) {
+            $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
+            $value = $explode[$key];
+          }
+        }
+      }
+    }
+
+
+    // Re-add the strings
+    if (!empty($saved_strings)) {
+      foreach ($explode as $key => $value) {
+        while (strpos($value,'YAMLString') !== false) {
+          $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
+          unset($saved_strings[$stringi]);
+          ++$stringi;
+          $value = $explode[$key];
+        }
+      }
+    }
+
+    $finished = true;
+    foreach ($explode as $key => $value) {
+      if (strpos($value,'YAMLSeq') !== false) {
+        $finished = false; break;
+      }
+      if (strpos($value,'YAMLMap') !== false) {
+        $finished = false; break;
+      }
+      if (strpos($value,'YAMLString') !== false) {
+        $finished = false; break;
+      }
+    }
+    if ($finished) break;
+
+    $i++;
+    if ($i > 10) 
+      break; // Prevent infinite loops.
+    }
+
+    return $explode;
+  }
+
+  function literalBlockContinues ($line, $lineIndent) {
+    if (!trim($line)) return true;
+    if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
+    return false;
+  }
+
+  function referenceContentsByAlias ($alias) {
+    do {
+      if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
+      $groupPath = $this->SavedGroups[$alias];
+      $value = $this->result;
+      foreach ($groupPath as $k) {
+        $value = $value[$k];
+      }
+    } while (false);
+    return $value;
+  }
+
+  function addArrayInline ($array, $indent) {
+      $CommonGroupPath = $this->path;
+      if (empty ($array)) return false;
+      
+      foreach ($array as $k => $_) {
+        $this->addArray(array($k => $_), $indent);
+        $this->path = $CommonGroupPath;
+      }
+      return true;
+  }
+
+  function addArray ($incoming_data, $incoming_indent) {
+
+   // print_r ($incoming_data);
+
+    if (count ($incoming_data) > 1)
+      return $this->addArrayInline ($incoming_data, $incoming_indent);
+    
+    $key = key ($incoming_data);
+    $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
+    if ($key === '__!YAMLZero') $key = '0';
+
+    if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
+      if ($key || $key === '' || $key === '0') {
+        $this->result[$key] = $value;
+      } else {
+        $this->result[] = $value; end ($this->result); $key = key ($this->result);
+      }
+      $this->path[$incoming_indent] = $key;
+      return;
+    }
+
+
+    
+    $history = array();
+    // Unfolding inner array tree.
+    $history[] = $_arr = $this->result;
+    foreach ($this->path as $k) {
+      $history[] = $_arr = $_arr[$k];
+    }
+
+    if ($this->_containsGroupAlias) {
+      $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
+      $this->_containsGroupAlias = false;
+    }
+
+
+    // Adding string or numeric key to the innermost level or $this->arr.
+    if (is_string($key) && $key == '<<') {
+      if (!is_array ($_arr)) { $_arr = array (); }
+      $_arr = array_merge ($_arr, $value);
+    } else if ($key || $key === '' || $key === '0') {
+      $_arr[$key] = $value;
+    } else {
+      if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
+      else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
+    }
+
+    $reverse_path = array_reverse($this->path);
+    $reverse_history = array_reverse ($history);
+    $reverse_history[0] = $_arr;
+    $cnt = count($reverse_history) - 1;
+    for ($i = 0; $i < $cnt; $i++) {
+      $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
+    }
+    $this->result = $reverse_history[$cnt];
+
+    $this->path[$incoming_indent] = $key;
+
+    if ($this->_containsGroupAnchor) {
+      $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
+      if (is_array ($value)) {
+        $k = key ($value);
+        if (!is_int ($k)) {
+          $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
+        }
+      }
+      $this->_containsGroupAnchor = false;
+    }
+
+  }
+
+  function startsLiteralBlock ($line) {
+    $lastChar = substr (trim($line), -1);
+    if ($lastChar != '>' && $lastChar != '|') return false;
+    if ($lastChar == '|') return $lastChar;
+    // HTML tags should not be counted as literal blocks.
+    if (preg_match ('#<.*?>$#', $line)) return false;
+    return $lastChar;
+  }
+
+  function greedilyNeedNextLine($line) {
+    $line = trim ($line);
+    if (!strlen($line)) return false;
+    if (substr ($line, -1, 1) == ']') return false;
+    if ($line[0] == '[') return true;
+    if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
+    return false;
+  }
+
+  function addLiteralLine ($literalBlock, $line, $literalBlockStyle) {
+    $line = $this->stripIndent($line);
+    $line = rtrim ($line, "\r\n\t ") . "\n";
+    if ($literalBlockStyle == '|') {
+      return $literalBlock . $line;
+    }
+    if (strlen($line) == 0)
+      return rtrim($literalBlock, ' ') . "\n";
+    if ($line == "\n" && $literalBlockStyle == '>') {
+      return rtrim ($literalBlock, " \t") . "\n";
+    }
+    if ($line != "\n")
+      $line = trim ($line, "\r\n ") . " ";
+    return $literalBlock . $line;
+  }
+
+   function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
+     foreach ($lineArray as $k => $_) {
+      if (is_array($_))
+        $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
+      else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
+              $lineArray[$k] = rtrim ($literalBlock, " \r\n");
+     }
+     return $lineArray;
+   }
+
+  function stripIndent ($line, $indent = -1) {
+    if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
+    return substr ($line, $indent);
+  }
+
+  function getParentPathByIndent ($indent) {
+    if ($indent == 0) return array();
+    $linePath = $this->path;
+    do {
+      end($linePath); $lastIndentInParentPath = key($linePath);
+      if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
+    } while ($indent <= $lastIndentInParentPath);
+    return $linePath;
+  }
+
+
+  function clearBiggerPathValues ($indent) {
+
+
+    if ($indent == 0) $this->path = array();
+    if (empty ($this->path)) return true;
+
+    foreach ($this->path as $k => $_) {
+      if ($k > $indent) unset ($this->path[$k]);
+    }
+
+    return true;
+  }
+
+
+  function isComment ($line) {
+    if (!$line) return false;
+    if ($line[0] == '#') return true;
+    if (trim($line, " \r\n\t") == '---') return true;
+    return false;
+  }
+
+  function isEmpty ($line) {
+    return (trim ($line) === '');
+  }
+
+
+  function isArrayElement ($line) {
+    if (!$line) return false;
+    if ($line[0] != '-') return false;
+    if (strlen ($line) > 3)
+      if (substr($line,0,3) == '---') return false;
+    
+    return true;
+  }
+
+  function isHashElement ($line) {
+    return strpos($line, ':');
+  }
+
+  function isLiteral ($line) {
+    if ($this->isArrayElement($line)) return false;
+    if ($this->isHashElement($line)) return false;
+    return true;
+  }
+
+
+  function unquote ($value) {
+    if (!$value) return $value;
+    if (!is_string($value)) return $value;
+    if ($value[0] == '\'') return trim ($value, '\'');
+    if ($value[0] == '"') return trim ($value, '"');
+    return $value;
+  }
+
+  function startsMappedSequence ($line) {
+    return ($line[0] == '-' && substr ($line, -1, 1) == ':');
+  }
+
+  function returnMappedSequence ($line) {
+    $array = array();
+    $key         = $this->unquote(trim(substr($line,1,-1)));
+    $array[$key] = array();
+    $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
+    return array($array);
+  }
+
+  function returnMappedValue ($line) {
+    $array = array();
+    $key         = $this->unquote (trim(substr($line,0,-1)));
+    $array[$key] = '';
+    return $array;
+  }
+
+  function startsMappedValue ($line) {
+    return (substr ($line, -1, 1) == ':');
+  }
+  
+  function isPlainArray ($line) {
+    return ($line[0] == '[' && substr ($line, -1, 1) == ']');
+  }
+  
+  function returnPlainArray ($line) {
+    return $this->_toType($line); 
+  }  
+
+  function returnKeyValuePair ($line) {
+    $array = array();
+    $key = '';
+    if (strpos ($line, ':')) {
+      // It's a key/value pair most likely
+      // If the key is in double quotes pull it out
+      if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
+        $value = trim(str_replace($matches[1],'',$line));
+        $key   = $matches[2];
+      } else {
+        // Do some guesswork as to the key and the value
+        $explode = explode(':',$line);
+        $key     = trim($explode[0]);
+        array_shift($explode);
+        $value   = trim(implode(':',$explode));
+      }
+      // Set the type of the value.  Int, string, etc
+      $value = $this->_toType($value);
+      if ($key === '0') $key = '__!YAMLZero';
+      $array[$key] = $value;
+    } else {
+      $array = array ($line);
+    }
+    return $array;
+
+  }
+
+
+  function returnArrayElement ($line) {
+     if (strlen($line) <= 1) return array(array()); // Weird %)
+     $array = array();
+     $value   = trim(substr($line,1));
+     $value   = $this->_toType($value);
+     $array[] = $value;
+     return $array;
+  }
+
+
+  function nodeContainsGroup ($line) {    
+    $symbolsForReference = 'A-z0-9_\-';
+    if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
+    if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+    if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+    if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
+    if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
+    if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
+    return false;
+
+  }
+
+  function addGroup ($line, $group) {
+    if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
+    if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
+    //print_r ($this->path);
+  }
+
+  function stripGroup ($line, $group) {
+    $line = trim(str_replace($group, '', $line));
+    return $line;
+  }
+}
+
+// Enable use of Spyc from command line
+// The syntax is the following: php spyc.php spyc.yaml
+
+define ('SPYC_FROM_COMMAND_LINE', false);
+
+do {
+  if (!SPYC_FROM_COMMAND_LINE) break;
+  if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
+  if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break;
+  $file = $argv[1];
+  printf ("Spyc loading file: %s\n", $file);
+  print_r (spyc_load_file ($file));
+} while (0);
\ No newline at end of file
diff --git a/www/plugins/yaml/spyc/spyc.php b/www/plugins/yaml/spyc/spyc.php
new file mode 100644 (file)
index 0000000..e19d562
--- /dev/null
@@ -0,0 +1,1046 @@
+<?php
+/**
+   * Spyc -- A Simple PHP YAML Class
+   * @version 0.5
+   * @author Vlad Andersen <vlad.andersen@gmail.com>
+   * @author Chris Wanstrath <chris@ozmm.org>
+   * @link http://code.google.com/p/spyc/
+   * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen
+   * @license http://www.opensource.org/licenses/mit-license.php MIT License
+   * @package Spyc
+   */
+
+if (!function_exists('spyc_load')) {
+  /**
+   * Parses YAML to array.
+   * @param string $string YAML string.
+   * @return array
+   */
+  function spyc_load ($string) {
+    return Spyc::YAMLLoadString($string);
+  }
+}
+
+if (!function_exists('spyc_load_file')) {
+  /**
+   * Parses YAML to array.
+   * @param string $file Path to YAML file.
+   * @return array
+   */
+  function spyc_load_file ($file) {
+    return Spyc::YAMLLoad($file);
+  }
+}
+
+/**
+   * The Simple PHP YAML Class.
+   *
+   * This class can be used to read a YAML file and convert its contents
+   * into a PHP array.  It currently supports a very limited subsection of
+   * the YAML spec.
+   *
+   * Usage:
+   * <code>
+   *   $Spyc  = new Spyc;
+   *   $array = $Spyc->load($file);
+   * </code>
+   * or:
+   * <code>
+   *   $array = Spyc::YAMLLoad($file);
+   * </code>
+   * or:
+   * <code>
+   *   $array = spyc_load_file($file);
+   * </code>
+   * @package Spyc
+   */
+class Spyc {
+
+  // SETTINGS
+
+  const REMPTY = "\0\0\0\0\0";
+
+  /**
+   * Setting this to true will force YAMLDump to enclose any string value in
+   * quotes.  False by default.
+   * 
+   * @var bool
+   */
+  public $setting_dump_force_quotes = false;
+
+  /**
+   * Setting this to true will forse YAMLLoad to use syck_load function when
+   * possible. False by default.
+   * @var bool
+   */
+  public $setting_use_syck_is_possible = false;
+
+
+
+  /**#@+
+  * @access private
+  * @var mixed
+  */
+  private $_dumpIndent;
+  private $_dumpWordWrap;
+  private $_containsGroupAnchor = false;
+  private $_containsGroupAlias = false;
+  private $path;
+  private $result;
+  private $LiteralPlaceHolder = '___YAML_Literal_Block___';
+  private $SavedGroups = array();
+  private $indent;
+  /**
+   * Path modifier that should be applied after adding current element.
+   * @var array
+   */
+  private $delayedPath = array();
+
+  /**#@+
+  * @access public
+  * @var mixed
+  */
+  public $_nodeId;
+
+/**
+ * Load a valid YAML string to Spyc.
+ * @param string $input
+ * @return array
+ */
+  public function load ($input) {
+    return $this->__loadString($input);
+  }
+
+ /**
+ * Load a valid YAML file to Spyc.
+ * @param string $file
+ * @return array
+ */
+  public function loadFile ($file) {
+    return $this->__load($file);
+  }
+
+  /**
+     * Load YAML into a PHP array statically
+     *
+     * The load method, when supplied with a YAML stream (string or file),
+     * will do its best to convert YAML in a file into a PHP array.  Pretty
+     * simple.
+     *  Usage:
+     *  <code>
+     *   $array = Spyc::YAMLLoad('lucky.yaml');
+     *   print_r($array);
+     *  </code>
+     * @access public
+     * @return array
+     * @param string $input Path of YAML file or string containing YAML
+     */
+  public static function YAMLLoad($input) {
+    $Spyc = new Spyc;
+    return $Spyc->__load($input);
+  }
+
+  /**
+     * Load a string of YAML into a PHP array statically
+     *
+     * The load method, when supplied with a YAML string, will do its best 
+     * to convert YAML in a string into a PHP array.  Pretty simple.
+     *
+     * Note: use this function if you don't want files from the file system
+     * loaded and processed as YAML.  This is of interest to people concerned
+     * about security whose input is from a string.
+     *
+     *  Usage:
+     *  <code>
+     *   $array = Spyc::YAMLLoadString("---\n0: hello world\n");
+     *   print_r($array);
+     *  </code>
+     * @access public
+     * @return array
+     * @param string $input String containing YAML
+     */
+  public static function YAMLLoadString($input) {
+    $Spyc = new Spyc;
+    return $Spyc->__loadString($input);
+  }
+
+  /**
+     * Dump YAML from PHP array statically
+     *
+     * The dump method, when supplied with an array, will do its best
+     * to convert the array into friendly YAML.  Pretty simple.  Feel free to
+     * save the returned string as nothing.yaml and pass it around.
+     *
+     * Oh, and you can decide how big the indent is and what the wordwrap
+     * for folding is.  Pretty cool -- just pass in 'false' for either if
+     * you want to use the default.
+     *
+     * Indent's default is 2 spaces, wordwrap's default is 40 characters.  And
+     * you can turn off wordwrap by passing in 0.
+     *
+     * @access public
+     * @return string
+     * @param array $array PHP array
+     * @param int $indent Pass in false to use the default, which is 2
+     * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+     */
+  public static function YAMLDump($array,$indent = false,$wordwrap = false) {
+    $spyc = new Spyc;
+    return $spyc->dump($array,$indent,$wordwrap);
+  }
+
+
+  /**
+     * Dump PHP array to YAML
+     *
+     * The dump method, when supplied with an array, will do its best
+     * to convert the array into friendly YAML.  Pretty simple.  Feel free to
+     * save the returned string as tasteful.yaml and pass it around.
+     *
+     * Oh, and you can decide how big the indent is and what the wordwrap
+     * for folding is.  Pretty cool -- just pass in 'false' for either if
+     * you want to use the default.
+     *
+     * Indent's default is 2 spaces, wordwrap's default is 40 characters.  And
+     * you can turn off wordwrap by passing in 0.
+     *
+     * @access public
+     * @return string
+     * @param array $array PHP array
+     * @param int $indent Pass in false to use the default, which is 2
+     * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+     */
+  public function dump($array,$indent = false,$wordwrap = false) {
+    // Dumps to some very clean YAML.  We'll have to add some more features
+    // and options soon.  And better support for folding.
+
+    // New features and options.
+    if ($indent === false or !is_numeric($indent)) {
+      $this->_dumpIndent = 2;
+    } else {
+      $this->_dumpIndent = $indent;
+    }
+
+    if ($wordwrap === false or !is_numeric($wordwrap)) {
+      $this->_dumpWordWrap = 40;
+    } else {
+      $this->_dumpWordWrap = $wordwrap;
+    }
+
+    // New YAML document
+    $string = "---\n";
+
+    // Start at the base of the array and move through it.
+    if ($array) {
+      $array = (array)$array; 
+      $previous_key = -1;
+      foreach ($array as $key => $value) {
+        if (!isset($first_key)) $first_key = $key;
+        $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array);
+        $previous_key = $key;
+      }
+    }
+    return $string;
+  }
+
+  /**
+     * Attempts to convert a key / value array item to YAML
+     * @access private
+     * @return string
+     * @param $key The name of the key
+     * @param $value The value of the item
+     * @param $indent The indent of the current node
+     */
+  private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+    if (is_array($value)) {
+      if (empty ($value))
+        return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array);
+      // It has children.  What to do?
+      // Make it the right kind of item
+      $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array);
+      // Add the indent
+      $indent += $this->_dumpIndent;
+      // Yamlize the array
+      $string .= $this->_yamlizeArray($value,$indent);
+    } elseif (!is_array($value)) {
+      // It doesn't have children.  Yip.
+      $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array);
+    }
+    return $string;
+  }
+
+  /**
+     * Attempts to convert an array to YAML
+     * @access private
+     * @return string
+     * @param $array The array you want to convert
+     * @param $indent The indent of the current level
+     */
+  private function _yamlizeArray($array,$indent) {
+    if (is_array($array)) {
+      $string = '';
+      $previous_key = -1;
+      foreach ($array as $key => $value) {
+        if (!isset($first_key)) $first_key = $key;
+        $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array);
+        $previous_key = $key;
+      }
+      return $string;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+     * Returns YAML from a key and a value
+     * @access private
+     * @return string
+     * @param $key The name of the key
+     * @param $value The value of the item
+     * @param $indent The indent of the current node
+     */
+  private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+    // do some folding here, for blocks
+    if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
+      strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, '  ') !== false ||
+      strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 ||
+      substr ($value, -1, 1) == ':')
+    ) {
+      $value = $this->_doLiteralBlock($value,$indent);
+    } else {
+      $value  = $this->_doFolding($value,$indent);
+    }
+
+    if ($value === array()) $value = '[ ]';
+    if (in_array ($value, array ('true', 'TRUE', 'false', 'FALSE', 'y', 'Y', 'n', 'N', 'null', 'NULL'), true)) {
+       $value = $this->_doLiteralBlock($value,$indent);
+    }
+    if (trim ($value) != $value)
+       $value = $this->_doLiteralBlock($value,$indent);
+
+    if (is_bool($value)) {
+       $value = ($value) ? "true" : "false";
+    }
+    
+    if ($value === null) $value = 'null';
+    if ($value === "'" . self::REMPTY . "'") $value = null;
+
+    $spaces = str_repeat(' ',$indent);
+
+    //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
+    if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) {
+      // It's a sequence
+      $string = $spaces.'- '.$value."\n";
+    } else {
+      // if ($first_key===0)  throw new Exception('Keys are all screwy.  The first one was zero, now it\'s "'. $key .'"');
+      // It's mapped
+      if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; }
+      $string = rtrim ($spaces.$key.': '.$value)."\n";
+    }
+    return $string;
+  }
+
+  /**
+     * Creates a literal block for dumping
+     * @access private
+     * @return string
+     * @param $value
+     * @param $indent int The value of the indent
+     */
+  private function _doLiteralBlock($value,$indent) {
+    if ($value === "\n") return '\n';
+    if (strpos($value, "\n") === false && strpos($value, "'") === false) {
+      return sprintf ("'%s'", $value);
+    }
+    if (strpos($value, "\n") === false && strpos($value, '"') === false) {
+      return sprintf ('"%s"', $value);
+    }
+    $exploded = explode("\n",$value);
+    $newValue = '|';
+    $indent  += $this->_dumpIndent;
+    $spaces   = str_repeat(' ',$indent);
+    foreach ($exploded as $line) {
+      $newValue .= "\n" . $spaces . ($line);
+    }
+    return $newValue;
+  }
+
+  /**
+     * Folds a string of text, if necessary
+     * @access private
+     * @return string
+     * @param $value The string you wish to fold
+     */
+  private function _doFolding($value,$indent) {
+    // Don't do anything if wordwrap is set to 0
+
+    if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
+      $indent += $this->_dumpIndent;
+      $indent = str_repeat(' ',$indent);
+      $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
+      $value   = ">\n".$indent.$wrapped;
+    } else {
+      if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY)
+        $value = '"' . $value . '"';
+    }
+
+
+    return $value;
+  }
+
+// LOADING FUNCTIONS
+
+  private function __load($input) {
+    $Source = $this->loadFromSource($input);
+    return $this->loadWithSource($Source);
+  }
+
+  private function __loadString($input) {
+    $Source = $this->loadFromString($input);
+    return $this->loadWithSource($Source);
+  }
+
+  private function loadWithSource($Source) {
+    if (empty ($Source)) return array();
+    if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
+      $array = syck_load (implode ('', $Source));
+      return is_array($array) ? $array : array();
+    }
+
+    $this->path = array();
+    $this->result = array();
+
+    $cnt = count($Source);
+    for ($i = 0; $i < $cnt; $i++) {
+      $line = $Source[$i];
+      
+      $this->indent = strlen($line) - strlen(ltrim($line));
+      $tempPath = $this->getParentPathByIndent($this->indent);
+      $line = self::stripIndent($line, $this->indent);
+      if (self::isComment($line)) continue;
+      if (self::isEmpty($line)) continue;
+      $this->path = $tempPath;
+
+      $literalBlockStyle = self::startsLiteralBlock($line);
+      if ($literalBlockStyle) {
+        $line = rtrim ($line, $literalBlockStyle . " \n");
+        $literalBlock = '';
+        $line .= $this->LiteralPlaceHolder;
+        $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1]));
+        while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
+          $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent);
+        }
+        $i--;
+      }
+
+      while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
+        $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
+      }
+      $i--;
+
+
+
+      if (strpos ($line, '#')) {
+        if (strpos ($line, '"') === false && strpos ($line, "'") === false)
+          $line = preg_replace('/\s+#(.+)$/','',$line);
+      }
+
+      $lineArray = $this->_parseLine($line);
+
+      if ($literalBlockStyle)
+        $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
+
+      $this->addArray($lineArray, $this->indent);
+
+      foreach ($this->delayedPath as $indent => $delayedPath)
+        $this->path[$indent] = $delayedPath;
+
+      $this->delayedPath = array();
+
+    }
+    return $this->result;
+  }
+
+  private function loadFromSource ($input) {
+    if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
+    return file($input);
+
+    return $this->loadFromString($input);
+  }
+
+  private function loadFromString ($input) {
+    $lines = explode("\n",$input);
+    foreach ($lines as $k => $_) {
+      $lines[$k] = rtrim ($_, "\r");
+    }
+    return $lines;
+  }
+
+  /**
+     * Parses YAML code and returns an array for a node
+     * @access private
+     * @return array
+     * @param string $line A line from the YAML file
+     */
+  private function _parseLine($line) {
+    if (!$line) return array();
+    $line = trim($line);
+    if (!$line) return array();
+
+    $array = array();
+
+    $group = $this->nodeContainsGroup($line);
+    if ($group) {
+      $this->addGroup($line, $group);
+      $line = $this->stripGroup ($line, $group);
+    }
+
+    if ($this->startsMappedSequence($line))
+      return $this->returnMappedSequence($line);
+
+    if ($this->startsMappedValue($line))
+      return $this->returnMappedValue($line);
+
+    if ($this->isArrayElement($line))
+     return $this->returnArrayElement($line);
+
+    if ($this->isPlainArray($line))
+     return $this->returnPlainArray($line); 
+     
+     
+    return $this->returnKeyValuePair($line);
+
+  }
+
+  /**
+     * Finds the type of the passed value, returns the value as the new type.
+     * @access private
+     * @param string $value
+     * @return mixed
+     */
+  private function _toType($value) {
+    if ($value === '') return null;
+    $first_character = $value[0];
+    $last_character = substr($value, -1, 1);
+
+    $is_quoted = false;
+    do {
+      if (!$value) break;
+      if ($first_character != '"' && $first_character != "'") break;
+      if ($last_character != '"' && $last_character != "'") break;
+      $is_quoted = true;
+    } while (0);
+
+    if ($is_quoted)
+      return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\'\'' => '\'', '\\\'' => '\''));
+    
+    if (strpos($value, ' #') !== false && !$is_quoted)
+      $value = preg_replace('/\s+#(.+)$/','',$value);
+
+    if (!$is_quoted) $value = str_replace('\n', "\n", $value);
+
+    if ($first_character == '[' && $last_character == ']') {
+      // Take out strings sequences and mappings
+      $innerValue = trim(substr ($value, 1, -1));
+      if ($innerValue === '') return array();
+      $explode = $this->_inlineEscape($innerValue);
+      // Propagate value array
+      $value  = array();
+      foreach ($explode as $v) {
+        $value[] = $this->_toType($v);
+      }
+      return $value;
+    }
+
+    if (strpos($value,': ')!==false && $first_character != '{') {
+      $array = explode(': ',$value);
+      $key   = trim($array[0]);
+      array_shift($array);
+      $value = trim(implode(': ',$array));
+      $value = $this->_toType($value);
+      return array($key => $value);
+    }
+    
+    if ($first_character == '{' && $last_character == '}') {
+      $innerValue = trim(substr ($value, 1, -1));
+      if ($innerValue === '') return array();
+      // Inline Mapping
+      // Take out strings sequences and mappings
+      $explode = $this->_inlineEscape($innerValue);
+      // Propagate value array
+      $array = array();
+      foreach ($explode as $v) {
+        $SubArr = $this->_toType($v);
+        if (empty($SubArr)) continue;
+        if (is_array ($SubArr)) {
+          $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
+        }
+        $array[] = $SubArr;
+      }
+      return $array;
+    }
+
+    if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
+      return null;
+    }
+
+    if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){
+      $intvalue = (int)$value;
+      if ($intvalue != PHP_INT_MAX)
+        $value = $intvalue;
+      return $value;
+    }
+
+    if (in_array($value,
+                 array('true', 'on', '+', 'yes', 'y', 'True', 'TRUE', 'On', 'ON', 'YES', 'Yes', 'Y'))) {
+      return true;
+    }
+
+    if (in_array(strtolower($value),
+                 array('false', 'off', '-', 'no', 'n'))) {
+      return false;
+    }
+
+    if (is_numeric($value)) {
+      if ($value === '0') return 0;
+      if (rtrim ($value, 0) === $value)
+        $value = (float)$value;
+      return $value;
+    }
+    
+    return $value;
+  }
+
+  /**
+     * Used in inlines to check for more inlines or quoted strings
+     * @access private
+     * @return array
+     */
+  private function _inlineEscape($inline) {
+    // There's gotta be a cleaner way to do this...
+    // While pure sequences seem to be nesting just fine,
+    // pure mappings and mappings with sequences inside can't go very
+    // deep.  This needs to be fixed.
+
+    $seqs = array();
+    $maps = array();
+    $saved_strings = array();
+
+    // Check for strings
+    $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
+    if (preg_match_all($regex,$inline,$strings)) {
+      $saved_strings = $strings[0];
+      $inline  = preg_replace($regex,'YAMLString',$inline);
+    }
+    unset($regex);
+
+    $i = 0;
+    do {
+
+    // Check for sequences
+    while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
+      $seqs[] = $matchseqs[0];
+      $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
+    }
+
+    // Check for mappings
+    while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
+      $maps[] = $matchmaps[0];
+      $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
+    }
+
+    if ($i++ >= 10) break;
+
+    } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
+
+    $explode = explode(', ',$inline);
+    $stringi = 0; $i = 0;
+
+    while (1) {
+
+    // Re-add the sequences
+    if (!empty($seqs)) {
+      foreach ($explode as $key => $value) {
+        if (strpos($value,'YAMLSeq') !== false) {
+          foreach ($seqs as $seqk => $seq) {
+            $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
+            $value = $explode[$key];
+          }
+        }
+      }
+    }
+
+    // Re-add the mappings
+    if (!empty($maps)) {
+      foreach ($explode as $key => $value) {
+        if (strpos($value,'YAMLMap') !== false) {
+          foreach ($maps as $mapk => $map) {
+            $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
+            $value = $explode[$key];
+          }
+        }
+      }
+    }
+
+
+    // Re-add the strings
+    if (!empty($saved_strings)) {
+      foreach ($explode as $key => $value) {
+        while (strpos($value,'YAMLString') !== false) {
+          $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
+          unset($saved_strings[$stringi]);
+          ++$stringi;
+          $value = $explode[$key];
+        }
+      }
+    }
+
+    $finished = true;
+    foreach ($explode as $key => $value) {
+      if (strpos($value,'YAMLSeq') !== false) {
+        $finished = false; break;
+      }
+      if (strpos($value,'YAMLMap') !== false) {
+        $finished = false; break;
+      }
+      if (strpos($value,'YAMLString') !== false) {
+        $finished = false; break;
+      }
+    }
+    if ($finished) break;
+
+    $i++;
+    if ($i > 10) 
+      break; // Prevent infinite loops.
+    }
+
+    return $explode;
+  }
+
+  private function literalBlockContinues ($line, $lineIndent) {
+    if (!trim($line)) return true;
+    if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
+    return false;
+  }
+
+  private function referenceContentsByAlias ($alias) {
+    do {
+      if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
+      $groupPath = $this->SavedGroups[$alias];
+      $value = $this->result;
+      foreach ($groupPath as $k) {
+        $value = $value[$k];
+      }
+    } while (false);
+    return $value;
+  }
+
+  private function addArrayInline ($array, $indent) {
+      $CommonGroupPath = $this->path;
+      if (empty ($array)) return false;
+      
+      foreach ($array as $k => $_) {
+        $this->addArray(array($k => $_), $indent);
+        $this->path = $CommonGroupPath;
+      }
+      return true;
+  }
+
+  private function addArray ($incoming_data, $incoming_indent) {
+
+   // print_r ($incoming_data);
+
+    if (count ($incoming_data) > 1)
+      return $this->addArrayInline ($incoming_data, $incoming_indent);
+    
+    $key = key ($incoming_data);
+    $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
+    if ($key === '__!YAMLZero') $key = '0';
+
+    if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
+      if ($key || $key === '' || $key === '0') {
+        $this->result[$key] = $value;
+      } else {
+        $this->result[] = $value; end ($this->result); $key = key ($this->result);
+      }
+      $this->path[$incoming_indent] = $key;
+      return;
+    }
+
+
+    
+    $history = array();
+    // Unfolding inner array tree.
+    $history[] = $_arr = $this->result;
+    foreach ($this->path as $k) {
+      $history[] = $_arr = $_arr[$k];
+    }
+
+    if ($this->_containsGroupAlias) {
+      $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
+      $this->_containsGroupAlias = false;
+    }
+
+
+    // Adding string or numeric key to the innermost level or $this->arr.
+    if (is_string($key) && $key == '<<') {
+      if (!is_array ($_arr)) { $_arr = array (); }
+
+      $_arr = array_merge ($_arr, $value);
+    } else if ($key || $key === '' || $key === '0') {
+      if (!is_array ($_arr))
+        $_arr = array ($key=>$value);
+      else
+        $_arr[$key] = $value;
+    } else {
+      if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
+      else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
+    }
+
+    $reverse_path = array_reverse($this->path);
+    $reverse_history = array_reverse ($history);
+    $reverse_history[0] = $_arr;
+    $cnt = count($reverse_history) - 1;
+    for ($i = 0; $i < $cnt; $i++) {
+      $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
+    }
+    $this->result = $reverse_history[$cnt];
+
+    $this->path[$incoming_indent] = $key;
+
+    if ($this->_containsGroupAnchor) {
+      $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
+      if (is_array ($value)) {
+        $k = key ($value);
+        if (!is_int ($k)) {
+          $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
+        }
+      }
+      $this->_containsGroupAnchor = false;
+    }
+
+  }
+
+  private static function startsLiteralBlock ($line) {
+    $lastChar = substr (trim($line), -1);
+    if ($lastChar != '>' && $lastChar != '|') return false;
+    if ($lastChar == '|') return $lastChar;
+    // HTML tags should not be counted as literal blocks.
+    if (preg_match ('#<.*?>$#', $line)) return false;
+    return $lastChar;
+  }
+
+  private static function greedilyNeedNextLine($line) {
+    $line = trim ($line);
+    if (!strlen($line)) return false;
+    if (substr ($line, -1, 1) == ']') return false;
+    if ($line[0] == '[') return true;
+    if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
+    return false;
+  }
+
+  private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) {
+    $line = self::stripIndent($line, $indent);
+    if ($literalBlockStyle !== '|') {
+        $line = self::stripIndent($line);
+    }
+    $line = rtrim ($line, "\r\n\t ") . "\n";
+    if ($literalBlockStyle == '|') {
+      return $literalBlock . $line;
+    }
+    if (strlen($line) == 0)
+      return rtrim($literalBlock, ' ') . "\n";
+    if ($line == "\n" && $literalBlockStyle == '>') {
+      return rtrim ($literalBlock, " \t") . "\n";
+    }
+    if ($line != "\n")
+      $line = trim ($line, "\r\n ") . " ";
+    return $literalBlock . $line;
+  }
+
+   function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
+     foreach ($lineArray as $k => $_) {
+      if (is_array($_))
+        $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
+      else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
+              $lineArray[$k] = rtrim ($literalBlock, " \r\n");
+     }
+     return $lineArray;
+   }
+
+  private static function stripIndent ($line, $indent = -1) {
+    if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
+    return substr ($line, $indent);
+  }
+
+  private function getParentPathByIndent ($indent) {
+    if ($indent == 0) return array();
+    $linePath = $this->path;
+    do {
+      end($linePath); $lastIndentInParentPath = key($linePath);
+      if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
+    } while ($indent <= $lastIndentInParentPath);
+    return $linePath;
+  }
+
+
+  private function clearBiggerPathValues ($indent) {
+
+
+    if ($indent == 0) $this->path = array();
+    if (empty ($this->path)) return true;
+
+    foreach ($this->path as $k => $_) {
+      if ($k > $indent) unset ($this->path[$k]);
+    }
+
+    return true;
+  }
+
+
+  private static function isComment ($line) {
+    if (!$line) return false;
+    if ($line[0] == '#') return true;
+    if (trim($line, " \r\n\t") == '---') return true;
+    return false;
+  }
+
+  private static function isEmpty ($line) {
+    return (trim ($line) === '');
+  }
+
+
+  private function isArrayElement ($line) {
+    if (!$line) return false;
+    if ($line[0] != '-') return false;
+    if (strlen ($line) > 3)
+      if (substr($line,0,3) == '---') return false;
+    
+    return true;
+  }
+
+  private function isHashElement ($line) {
+    return strpos($line, ':');
+  }
+
+  private function isLiteral ($line) {
+    if ($this->isArrayElement($line)) return false;
+    if ($this->isHashElement($line)) return false;
+    return true;
+  }
+
+
+  private static function unquote ($value) {
+    if (!$value) return $value;
+    if (!is_string($value)) return $value;
+    if ($value[0] == '\'') return trim ($value, '\'');
+    if ($value[0] == '"') return trim ($value, '"');
+    return $value;
+  }
+
+  private function startsMappedSequence ($line) {
+    return ($line[0] == '-' && substr ($line, -1, 1) == ':');
+  }
+
+  private function returnMappedSequence ($line) {
+    $array = array();
+    $key         = self::unquote(trim(substr($line,1,-1)));
+    $array[$key] = array();
+    $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
+    return array($array);
+  }
+
+  private function returnMappedValue ($line) {
+    $array = array();
+    $key         = self::unquote (trim(substr($line,0,-1)));
+    $array[$key] = '';
+    return $array;
+  }
+
+  private function startsMappedValue ($line) {
+    return (substr ($line, -1, 1) == ':');
+  }
+  
+  private function isPlainArray ($line) {
+    return ($line[0] == '[' && substr ($line, -1, 1) == ']');
+  }
+  
+  private function returnPlainArray ($line) {
+    return $this->_toType($line); 
+  }  
+
+  private function returnKeyValuePair ($line) {
+    $array = array();
+    $key = '';
+    if (strpos ($line, ':')) {
+      // It's a key/value pair most likely
+      // If the key is in double quotes pull it out
+      if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
+        $value = trim(str_replace($matches[1],'',$line));
+        $key   = $matches[2];
+      } else {
+        // Do some guesswork as to the key and the value
+        $explode = explode(':',$line);
+        $key     = trim($explode[0]);
+        array_shift($explode);
+        $value   = trim(implode(':',$explode));
+      }
+      // Set the type of the value.  Int, string, etc
+      $value = $this->_toType($value);
+      if ($key === '0') $key = '__!YAMLZero';
+      $array[$key] = $value;
+    } else {
+      $array = array ($line);
+    }
+    return $array;
+
+  }
+
+
+  private function returnArrayElement ($line) {
+     if (strlen($line) <= 1) return array(array()); // Weird %)
+     $array = array();
+     $value   = trim(substr($line,1));
+     $value   = $this->_toType($value);
+     $array[] = $value;
+     return $array;
+  }
+
+
+  private function nodeContainsGroup ($line) {    
+    $symbolsForReference = 'A-z0-9_\-';
+    if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
+    if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+    if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+    if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
+    if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
+    if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
+    return false;
+
+  }
+
+  private function addGroup ($line, $group) {
+    if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
+    if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
+    //print_r ($this->path);
+  }
+
+  private function stripGroup ($line, $group) {
+    $line = trim(str_replace($group, '', $line));
+    return $line;
+  }
+}
+
+// Enable use of Spyc from command line
+// The syntax is the following: php spyc.php spyc.yaml
+
+define ('SPYC_FROM_COMMAND_LINE', false);
+
+do {
+  if (!SPYC_FROM_COMMAND_LINE) break;
+  if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
+  if (empty ($_SERVER['PHP_SELF']) || $_SERVER['PHP_SELF'] != 'spyc.php') break;
+  $file = $argv[1];
+  printf ("Spyc loading file: %s\n", $file);
+  print_r (spyc_load_file ($file));
+} while (0);
\ No newline at end of file
diff --git a/www/plugins/yaml/svn.revision b/www/plugins/yaml/svn.revision
new file mode 100644 (file)
index 0000000..5ca4cee
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/yaml
+Revision: 72284
+Dernier commit: 2013-04-24 06:01:18 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/yaml</origine>
+<revision>72284</revision>
+<commit>2013-04-24 06:01:18 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/yaml/yaml.png b/www/plugins/yaml/yaml.png
new file mode 100644 (file)
index 0000000..9c14d44
Binary files /dev/null and b/www/plugins/yaml/yaml.png differ
diff --git a/www/plugins/yaml/yaml_fonctions.php b/www/plugins/yaml/yaml_fonctions.php
new file mode 100644 (file)
index 0000000..de176f3
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+
+// Sécurité
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// Filtre permettant d'utiliser yaml_decode_file() dans un squelette
+function decoder_yaml($fichier){
+       include_spip('inc/yaml');
+       return yaml_decode_file($fichier);
+}
+
+function inc_yaml_to_array_dist($u) {
+       include_spip('inc/yaml');
+       return yaml_decode($u);
+}
+
+?>
diff --git a/www/plugins/zen-garden-2/action/zengarden_activer_switcher.php b/www/plugins/zen-garden-2/action/zengarden_activer_switcher.php
new file mode 100644 (file)
index 0000000..a7eecef
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Plugin Zen-Garden pour Spip 3.0
+ * Licence GPL (c) 2006-2013 Cedric Morin
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_zengarden_activer_switcher_dist(){
+       $securiser_action = charger_fonction('securiser_action','inc');
+       $arg = $securiser_action();
+
+       include_spip('inc/meta');
+       if ($arg=='on'){
+               ecrire_meta("zengarden_switcher", 'on');
+       }
+       else {
+               effacer_meta("zengarden_switcher");
+       }
+}
+
+?>
diff --git a/www/plugins/zen-garden-2/action/zengarden_activer_theme.php b/www/plugins/zen-garden-2/action/zengarden_activer_theme.php
new file mode 100644 (file)
index 0000000..1c8d357
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Plugin Zen-Garden pour Spip 3.0
+ * Licence GPL (c) 2006-2013 Cedric Morin
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+function action_zengarden_activer_theme_dist(){
+       $securiser_action = charger_fonction('securiser_action','inc');
+       $arg = $securiser_action();
+
+       if (strncmp('defaut:',$arg,7) == 0){
+               $dir_theme = _DIR_RACINE . substr($arg,7);
+               $flux = pipeline('zengarden_activer_theme', array('args' => array('dir' =>$dir_theme, 'action'=>'effacer'), 'data' => true));
+               if ($flux) {
+                       include_spip('inc/meta');
+                       effacer_meta("zengarden_theme");
+               }
+       }
+       elseif (strncmp('apercu:',$arg,7) == 0){
+               $theme = substr($arg,7);
+               $dir_theme = _DIR_RACINE . $theme;
+               if (is_dir($dir_theme)) {
+                       $flux = pipeline('zengarden_activer_theme', array('args' => array('dir' =>$dir_theme, 'action'=>'apercevoir'), 'data' => true));
+                       if ($flux) {
+                               include_spip('inc/cookie');
+                               spip_setcookie('spip_zengarden_theme', $theme);
+                       }
+               }
+       }
+       elseif (strncmp('activation:',$arg,11) == 0) {
+               $theme = substr($arg,11);
+               $dir_theme = _DIR_RACINE . $theme;
+               if (is_dir($dir_theme)) {
+                       $flux = pipeline('zengarden_activer_theme', array('args' => array('dir' => $dir_theme, 'action'=>'activer'), 'data' => true));
+                       if ($flux) {
+                               include_spip('inc/meta');
+                               ecrire_meta("zengarden_theme", $theme);
+                       }
+               }
+       }
+}
+
+?>
diff --git a/www/plugins/zen-garden-2/images/themes-128.png b/www/plugins/zen-garden-2/images/themes-128.png
new file mode 100644 (file)
index 0000000..05da9de
Binary files /dev/null and b/www/plugins/zen-garden-2/images/themes-128.png differ
diff --git a/www/plugins/zen-garden-2/images/themes-32.png b/www/plugins/zen-garden-2/images/themes-32.png
new file mode 100644 (file)
index 0000000..7b6e426
Binary files /dev/null and b/www/plugins/zen-garden-2/images/themes-32.png differ
diff --git a/www/plugins/zen-garden-2/images/themes-64.png b/www/plugins/zen-garden-2/images/themes-64.png
new file mode 100644 (file)
index 0000000..28d544a
Binary files /dev/null and b/www/plugins/zen-garden-2/images/themes-64.png differ
diff --git a/www/plugins/zen-garden-2/inc/zengarden.php b/www/plugins/zen-garden-2/inc/zengarden.php
new file mode 100644 (file)
index 0000000..a4135ce
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Plugin Zen-Garden pour Spip 3.0
+ * Licence GPL (c) 2006-2013 Cedric Morin
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+if (!defined('_DIR_THEMES'))
+       define('_DIR_THEMES',_DIR_RACINE."themes/");
+
+function zengarden_charge_themes($dir = _DIR_THEMES, $tous = false, $force = false){
+       $themes = array();
+
+       include_spip('inc/plugin');
+       $files = liste_plugin_files($dir);
+
+       if (count($files)) {
+               $get_infos = charger_fonction('get_infos','plugins');
+
+               $t = $get_infos($files,$force,$dir);
+               $themes = array();
+
+               foreach($files as $d){
+                       if (isset($t[$d])){
+                               if (isset($t[$d]['categorie']) and $t[$d]['categorie']=='theme'
+                                 AND ($tous OR $t[$d]['etat']=='stable')){
+                                       $t[$d]['tri'] = strtolower(basename($d));
+                                       $themes[substr($dir.$d,strlen(_DIR_RACINE))] = $t[$d];
+                               }
+                       }
+                       unset($t[$d]);
+               }
+       }
+
+       return $themes;
+}
+
+?>
diff --git a/www/plugins/zen-garden-2/inclure/zengarden_switcher.css b/www/plugins/zen-garden-2/inclure/zengarden_switcher.css
new file mode 100644 (file)
index 0000000..31874eb
--- /dev/null
@@ -0,0 +1,3 @@
+#switcher_zen select { margin:2px 0.5em;       width:20em;     float:left;}
+#switcher_zen input {  float:right;}
+#switcher_zen {        background-color:transparent; left:20px; position:absolute; top:0; z-index:10000; }
\ No newline at end of file
diff --git a/www/plugins/zen-garden-2/inclure/zengarden_switcher.html b/www/plugins/zen-garden-2/inclure/zengarden_switcher.html
new file mode 100644 (file)
index 0000000..5f645c9
--- /dev/null
@@ -0,0 +1,15 @@
+<div id="switcher_zen">
+<form action='' method='post' class='formulaire_switcher_zen'>
+<B_themes>
+       <select name="var_theme">
+               <option value=""><:zengarden:themes:></option>
+               <BOUCLE_themes(POUR){tableau #ENV{tous,''}|zengarden_liste_themes}{par tri}>
+                       <option value="#CLE">[(#VALEUR{nom}|typo|extraire_multi|textebrut)]</option>
+               </BOUCLE_themes>
+       </select>
+       <input type="submit" value="<:bouton_choisir:>" />
+</B_themes>
+</form>
+</div>
+[<style type="text/css">/* <![(#VAL{91}|chr)]CDATA[(#VAL{91}|chr)] */ (#INCLURE{inclure/zengarden_switcher.css}|compacte{css}) /* [(#VAL{93}|chr)][(#VAL{93}|chr)]> */</style>]
+[<script type="text/javascript">/* <![(#VAL{91}|chr)]CDATA[(#VAL{91}|chr)] */ (#INCLURE{inclure/zengarden_switcher.js}|compacte{js}) /* [(#VAL{93}|chr)][(#VAL{93}|chr)]> */</script>]
diff --git a/www/plugins/zen-garden-2/inclure/zengarden_switcher.js b/www/plugins/zen-garden-2/inclure/zengarden_switcher.js
new file mode 100644 (file)
index 0000000..4fc2029
--- /dev/null
@@ -0,0 +1,8 @@
+jQuery(function() {
+       jQuery("#switcher_zen select")
+               .change(function(){
+                       jQuery(this).parents('form').get(0).submit();
+               })
+               .attr('value',theme_selected)
+         .siblings("input[type=submit]").hide();
+});
\ No newline at end of file
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden.xml b/www/plugins/zen-garden-2/lang/paquet-zengarden.xml
new file mode 100644 (file)
index 0000000..689e32a
--- /dev/null
@@ -0,0 +1,21 @@
+<traduction module="paquet-zengarden" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/zen-garden/trunk/lang/" reference="fr">
+       <langue code="en" url="http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=en">
+               <traducteur nom="kent1" lien="http://trad.spip.net/auteur/kent1" />
+       </langue>
+       <langue code="es" url="http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=es">
+               <traducteur nom="Raquel S. Bujaldón" lien="http://trad.spip.net/auteur/raquel" />
+       </langue>
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="nl" url="http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=nl">
+               <traducteur nom="Suske" lien="http://trad.spip.net/auteur/suske" />
+       </langue>
+       <langue code="ru" url="http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=ru">
+               <traducteur nom="nazar" lien="http://trad.spip.net/auteur/nazar" />
+       </langue>
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden_en.php b/www/plugins/zen-garden-2/lang/paquet-zengarden_en.php
new file mode 100644 (file)
index 0000000..4a7a463
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'zengarden_description' => ' ',
+       'zengarden_slogan' => 'A Zen garden for the skeletons'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden_es.php b/www/plugins/zen-garden-2/lang/paquet-zengarden_es.php
new file mode 100644 (file)
index 0000000..2f4b473
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'zengarden_description' => ' ',
+       'zengarden_slogan' => 'Un jardín Zen para los esqueletos'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden_fa.php b/www/plugins/zen-garden-2/lang/paquet-zengarden_fa.php
new file mode 100644 (file)
index 0000000..197f251
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'zengarden_description' => ' ',
+       'zengarden_slogan' => 'باغ ذن براي اسپيپ ' # MODIF
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden_fr.php b/www/plugins/zen-garden-2/lang/paquet-zengarden_fr.php
new file mode 100644 (file)
index 0000000..ce52b90
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/zen-garden/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'zengarden_description' => ' ',
+       'zengarden_slogan' => 'Un jardin Zen pour les squelettes'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden_nl.php b/www/plugins/zen-garden-2/lang/paquet-zengarden_nl.php
new file mode 100644 (file)
index 0000000..97d7baa
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=nl
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'zengarden_description' => ' Zie, proef en kies het juiste thema voor je site. ',
+       'zengarden_slogan' => 'Een Zen tuintje voor Zpip' # MODIF
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden_ru.php b/www/plugins/zen-garden-2/lang/paquet-zengarden_ru.php
new file mode 100644 (file)
index 0000000..a9e8233
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=ru
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'zengarden_description' => ' ',
+       'zengarden_slogan' => 'Плагин "Zengarden" для SPIP' # MODIF
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/paquet-zengarden_sk.php b/www/plugins/zen-garden-2/lang/paquet-zengarden_sk.php
new file mode 100644 (file)
index 0000000..638f449
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/paquet-zengarden?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // Z
+       'zengarden_description' => ' ',
+       'zengarden_slogan' => 'Zenová záhrada pre šablóny'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/zengarden.xml b/www/plugins/zen-garden-2/lang/zengarden.xml
new file mode 100644 (file)
index 0000000..309ada3
--- /dev/null
@@ -0,0 +1,14 @@
+<traduction module="zengarden" gestionnaire="salvatore" url="http://trad.spip.net" source="svn://zone.spip.org/spip-zone/_plugins_/zen-garden/trunk/lang/" reference="fr">
+       <langue code="de" />
+       <langue code="en" url="http://trad.spip.net/tradlang_module/zengarden?lang_cible=en">
+               <traducteur nom="George" lien="http://trad.spip.net/auteur/جورج-قندلفت" />
+       </langue>
+       <langue code="es" />
+       <langue code="fa" url="http://trad.spip.net/tradlang_module/zengarden?lang_cible=fa">
+               <traducteur nom="Davood Hossein" lien="http://trad.spip.net/auteur/davood-hossein" />
+       </langue>
+       <langue code="fr" />
+       <langue code="sk" url="http://trad.spip.net/tradlang_module/zengarden?lang_cible=sk">
+               <traducteur nom="jaro" lien="http://trad.spip.net/auteur/jaro" />
+       </langue>
+</traduction>
diff --git a/www/plugins/zen-garden-2/lang/zengarden_de.php b/www/plugins/zen-garden-2/lang/zengarden_de.php
new file mode 100644 (file)
index 0000000..2926626
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/zengarden?lang_cible=de
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'apercevoir_ce_theme' => 'Vorschau',
+
+       // B
+       'bandeau_personalisable' => 'Sie können das Banner im Kopf des Themas anpassen',
+
+       // C
+       'choisir_ce_theme' => 'Auswählen',
+       'choix_theme' => 'Bitte Thema auswählen',
+
+       // D
+       'desactiver_ce_theme' => 'Deaktivieren und Standarddesign wiederherstellen',
+
+       // I
+       'info_page' => 'Sie können entweder ein Thema aktivieren oder die Vorschau nutzen,
+       wenn Sie das Aussehen der Website für Besucher nicht ändern möchten.',
+       'intitule_compatiblite_squelette' => 'Design setzt eines dieser Skelette voraus',
+       'intitule_version' => 'Version',
+
+       // S
+       'switcher_activer' => 'Öffentliches Themen-Menü aktivieren.',
+       'switcher_desactiver' => 'Öffentliches Themen-Menü deaktivieren',
+
+       // T
+       'theme_actif' => 'Dieses Thema wird zur Zeit verwendet',
+       'themes' => 'Themen'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/zengarden_en.php b/www/plugins/zen-garden-2/lang/zengarden_en.php
new file mode 100644 (file)
index 0000000..64cb417
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/zengarden?lang_cible=en
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'apercevoir_ce_theme' => 'Preview',
+
+       // B
+       'bandeau_personalisable' => 'You can customize the image in the banner of this theme',
+
+       // C
+       'choisir_ce_theme' => 'Choose',
+       'choix_theme' => 'Choose your theme',
+
+       // D
+       'desactiver_ce_theme' => 'Deactivate and return to default style',
+
+       // I
+       'info_page' => 'You can choose one of the suggested theme or just see its rendering without changing the display for your visitors',
+       'intitule_compatiblite_squelette' => 'Compatible only with the templates',
+       'intitule_version' => 'version',
+
+       // S
+       'switcher_activer' => 'Activate the theme switcher on the public site',
+       'switcher_desactiver' => 'Disable the themes switcher',
+
+       // T
+       'theme_actif' => 'This theme is currently used',
+       'themes' => 'Themes'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/zengarden_es.php b/www/plugins/zen-garden-2/lang/zengarden_es.php
new file mode 100644 (file)
index 0000000..b2d1a98
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/zengarden?lang_cible=es
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'apercevoir_ce_theme' => 'Previsualizar',
+
+       // B
+       'bandeau_personalisable' => 'Personalizar la imagen de la cabecera para este tema',
+
+       // C
+       'choisir_ce_theme' => 'Seleccionar',
+       'choix_theme' => 'Seleccionar un tema',
+
+       // D
+       'desactiver_ce_theme' => 'Desactivar el tema y volver al estilo inicial del sitio',
+
+       // I
+       'info_page' => 'Puedes seleccionar uno de los temas propuestos, o sólo previsualizarlos sin modificar la visualización actual del sitio',
+       'intitule_compatiblite_squelette' => 'Sólo es compatible con un esqueleto',
+       'intitule_version' => 'versión',
+
+       // S
+       'switcher_activer' => 'Activar el switcher de temas en el sitio público',
+       'switcher_desactiver' => 'Desactivar el switcher de temas',
+
+       // T
+       'theme_actif' => 'Este tema se utiliza actualmente',
+       'themes' => 'Temas'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/zengarden_fa.php b/www/plugins/zen-garden-2/lang/zengarden_fa.php
new file mode 100644 (file)
index 0000000..b92bad3
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/zengarden?lang_cible=fa
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'apercevoir_ce_theme' => 'تماشا',
+
+       // B
+       'bandeau_personalisable' => 'مي‌توانيد تصوير سرصفحه‌ (بنر) اين تم را شخصي سازي كنيد',
+
+       // C
+       'choisir_ce_theme' => 'انتخاب',
+       'choix_theme' => 'تم خود را انتخاب كنيد',
+
+       // D
+       'desactiver_ce_theme' => 'غيرفعال‌سازي و بازگشت به شيوه‌ي پيش‌گزيده',
+
+       // I
+       'info_page' => 'اين صفحه به شما امكان مديريت مناطق دسترسي محدود سايت شما را فراهم مي‌سازد',
+       'intitule_compatiblite_squelette' => 'انطباق منحصر به فرد با اسكلت‌ها',
+       'intitule_version' => 'نسخه',
+
+       // S
+       'switcher_activer' => 'فعال‌سازي سويچ تم‌ها روي سايت همگاني ',
+       'switcher_desactiver' => 'فعال‌سازي سويچ تم‌ها',
+
+       // T
+       'theme_actif' => 'در حال حاضر اين تم مورد استفاده است',
+       'themes' => 'تم‌ها'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/zengarden_fr.php b/www/plugins/zen-garden-2/lang/zengarden_fr.php
new file mode 100644 (file)
index 0000000..1a0ca8e
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/zen-garden/trunk/lang/
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'apercevoir_ce_theme' => 'Apercevoir',
+
+       // B
+       'bandeau_personalisable' => 'Vous pouvez personnaliser l\'image du bandeau de ce thème',
+
+       // C
+       'choisir_ce_theme' => 'Choisir',
+       'choix_theme' => 'Choisissez votre thème',
+
+       // D
+       'desactiver_ce_theme' => 'Désactiver et revenir au style par défaut',
+
+       // I
+       'info_page' => 'Vous pouvez choisir un thème proposé ou simplement apercevoir son rendu sans modifier l\'affichage pour vos visiteurs',
+       'intitule_compatiblite_squelette' => 'Compatible uniquement avec les squelettes',
+       'intitule_version' => 'version',
+
+       // S
+       'switcher_activer' => 'Activer le switcher de thèmes sur le site public',
+       'switcher_desactiver' => 'Desactiver le switcher de thèmes',
+
+       // T
+       'theme_actif' => 'Ce thème est actuellement utilisé',
+       'themes' => 'Thèmes'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/lang/zengarden_sk.php b/www/plugins/zen-garden-2/lang/zengarden_sk.php
new file mode 100644 (file)
index 0000000..7ef76c6
--- /dev/null
@@ -0,0 +1,37 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// extrait automatiquement de http://trad.spip.net/tradlang_module/zengarden?lang_cible=sk
+// ** ne pas modifier le fichier **
+
+if (!defined('_ECRIRE_INC_VERSION')) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'apercevoir_ce_theme' => 'Zobraziť',
+
+       // B
+       'bandeau_personalisable' => 'Môžete si upraviť obrázok v pútači tohto farebného motívu',
+
+       // C
+       'choisir_ce_theme' => 'Vybrať',
+       'choix_theme' => 'Vyberte si farebný motív',
+
+       // D
+       'desactiver_ce_theme' => 'Deaktivovať a vrátiť sa k predvolenému štýlu',
+
+       // I
+       'info_page' => 'Môžete si vybrať navrhovaný farebný motív alebo si nejaký jednoducho nechať zobraziť bez toho, aby sa tým zmenilo zobrazenie pre návštevníkov',
+       'intitule_compatiblite_squelette' => 'Iba kompatibilné so šablónami',
+       'intitule_version' => 'verzia',
+
+       // S
+       'switcher_activer' => 'Aktivovať prepínanie farebných tém na verejne prístupnej stránke',
+       'switcher_desactiver' => 'Deaktivovať prepínanie farebných motívov',
+
+       // T
+       'theme_actif' => 'Tento farebný motív sa používa teraz',
+       'themes' => 'Farebné motívy'
+);
+
+?>
diff --git a/www/plugins/zen-garden-2/paquet.xml b/www/plugins/zen-garden-2/paquet.xml
new file mode 100644 (file)
index 0000000..1ec339e
--- /dev/null
@@ -0,0 +1,23 @@
+<paquet
+       prefix="zengarden"
+       categorie="maintenance"
+       version="2.5.2"
+       etat="test"
+       compatibilite="[3.0.0;3.0.*]"
+       logo="images/themes-32.png"
+       documentation="http://www.spip-contrib.net/SPIP-Zen-Garden"
+>
+       <nom>Zen-Garden</nom>
+       <!-- Un jardin Zen pour les squelettes -->
+
+       <auteur lien='http://www.yterium.com'>Cedric Morin, Yterium</auteur>
+
+       <pipeline nom="zengarden_activer_theme" action="" />
+
+       <pipeline nom="affichage_final" />
+       <pipeline nom="filtrer_liste_plugins" inclure="zengarden_fonctions.php" />
+       <pipeline nom="header_prive" inclure="zengarden_pipelines.php" />
+
+       <menu nom='zengarden' parent='menu_squelette' titre="zengarden:themes" icone="images/themes-16.png" />
+
+</paquet>
diff --git a/www/plugins/zen-garden-2/prive/squelettes/contenu/zengarden.html b/www/plugins/zen-garden-2/prive/squelettes/contenu/zengarden.html
new file mode 100644 (file)
index 0000000..4fe92c8
--- /dev/null
@@ -0,0 +1,4 @@
+[(#AUTORISER{administrer,theme}|sinon_interdire_acces)]
+<h1 class="grostitre"><:zengarden:choix_theme:></h1>
+
+<INCLURE{fond=prive/squelettes/inclure/zengarden_theme,env,selection=#CONFIG{zengarden_theme,''}}>
\ No newline at end of file
diff --git a/www/plugins/zen-garden-2/prive/squelettes/inclure/zengarden_theme.html b/www/plugins/zen-garden-2/prive/squelettes/inclure/zengarden_theme.html
new file mode 100644 (file)
index 0000000..e25fb4b
--- /dev/null
@@ -0,0 +1,46 @@
+#SET{themes,#ENV{tous,''}|zengarden_liste_themes}
+<INCLURE{fond=prive/squelettes/inclure/zengarden_theme_actif,env,themes=#GET{themes}}>
+<B_themes>
+[<p class='pagination'>(#PAGINATION)</p>]
+<ul class='liste_themes'>
+<BOUCLE_themes(POUR){tableau #GET{themes}}{cle!=#ENV{selection}}{par tri}{pagination 20}>
+       <li class='theme'>
+               <div class="qTip target_leftMiddle tooltip_rightMiddle">
+               [(#EVAL{_DIR_RACINE}|concat{#CLE,'/',#VALEUR{logo}}
+               |image_reduire{#ENV{largeur_previsu,100},#ENV{hauteur_previsu,75}}
+               |inserer_attribut{class,''}
+               |inserer_attribut{alt,#VALEUR|table_valeur{nom}|typo|extraire_multi})]
+               <h3 class="">[(#VALEUR|table_valeur{nom}|typo|extraire_multi)]</h3>
+               </div>
+               <div class="qTipContent">
+               <div class='descriptif'>[(#VALEUR{description}|propre)]</div>
+               <div class='auteur'>[(#VAL{info_les_auteurs_1}|_T{#ARRAY{les_auteurs,#VALEUR{auteur}|implode{', '}|propre|PtoBR}})]</div>
+               <div class='licence'>[<:intitule_licence:> (#VALEUR{licence}|implode{','}|propre|PtoBR)]</div>
+               <B_squelettes>
+                       <div class='squelette'>
+                               <:zengarden:intitule_compatiblite_squelette:>
+                               <ul>
+                               <BOUCLE_squelettes(POUR){tableau #VALEUR{utilise}}>[(#VALEUR{nom}|in_any{#LISTE{Z,Zpip}}|non)[
+                                                       <li>
+                                                               (#VALEUR{name}|sinon{#VALEUR{nom}}|propre|PtoBR)
+                                                               [: (#VALEUR{version}|zengarden_affiche_version_compatible|propre|PtoBR)]
+                                                       </li>
+                               ]]</BOUCLE_squelettes>
+                               </ul>
+                       </div>
+                       <br class="nettoyeur" />
+               </B_squelettes>
+
+               [<div class='bandeau'>(#VALEUR{bandeau}|?{<:zengarden:bandeau_personalisable:>})</div>]
+               </div>
+               <p class='actions'>
+               <a class="apercevoir" target='_blank' href='[(#URL_ACTION_AUTEUR{zengarden_activer_theme,apercu:#CLE,[(#EVAL{_DIR_RACINE}|sinon{#ENV{redirect}})]})]'>\[<:zengarden:apercevoir_ce_theme:>\]</a>
+               <a class='ajax' href='#URL_ACTION_AUTEUR{zengarden_activer_theme,activation:#CLE,#SELF|parametre_url{debut_themes,''}}'>\[<:zengarden:choisir_ce_theme:>\]</a>
+               </p>
+       </li>
+</BOUCLE_themes>
+</ul>
+<br class="nettoyeur" />
+[<p class='pagination'>(#PAGINATION)</p>]
+
+</B_themes>
diff --git a/www/plugins/zen-garden-2/prive/squelettes/inclure/zengarden_theme_actif.html b/www/plugins/zen-garden-2/prive/squelettes/inclure/zengarden_theme_actif.html
new file mode 100644 (file)
index 0000000..7f14f57
--- /dev/null
@@ -0,0 +1,15 @@
+<B_sel>
+<ul class='liste_items themes'>
+<BOUCLE_sel(POUR){tableau #ENV{themes}}{cle=#ENV{selection}}>
+<li class='item on'>
+[(#EVAL{_DIR_RACINE}|concat{#CLE,'/',#VALEUR{logo}}|image_reduire{200,150}|inserer_attribut{class,spip_documents_left}|inserer_attribut{alt,#VALEUR{nom}|typo|extraire_multi})]
+<h2><:zengarden:theme_actif:></h2>
+<h3>[(#VALEUR{nom}|typo|extraire_multi)]</h3>
+<div class='descriptif'>[(#VALEUR{description}|propre)]</div>
+<div class='auteur'>[(#VAL{info_les_auteurs_1}|_T{#ARRAY{les_auteurs,#VALEUR{auteur}|implode{', '}|propre|PtoBR}})]</div>
+<div class='licence'>[<:intitule_licence:> (#VALEUR{licence}|implode{','}|propre|PtoBR)]</div>
+<p class='actions'>[<a class='ajax' href='#URL_ACTION_AUTEUR{zengarden_activer_theme,defaut:#CLE,#SELF}'><:zengarden:desactiver_ce_theme:></a>]</p>
+</li>
+</BOUCLE_sel>
+</ul>
+</B_sel>
\ No newline at end of file
diff --git a/www/plugins/zen-garden-2/prive/squelettes/navigation/zengarden.html b/www/plugins/zen-garden-2/prive/squelettes/navigation/zengarden.html
new file mode 100644 (file)
index 0000000..0277765
--- /dev/null
@@ -0,0 +1,13 @@
+[(#AUTORISER{administrer,theme}|sinon_interdire_acces)]
+
+#BOITE_OUVRIR{'',info}
+       [(#CHEMIN_IMAGE{themes-128.png}|balise_img)]
+       <:zengarden:info_page|propre:>
+
+       [(#CONFIG{zengarden_switcher}|oui)
+               [(#BOUTON_ACTION{<:zengarden:switcher_desactiver:>,#URL_ACTION_AUTEUR{zengarden_activer_switcher,off,#SELF},'switcher ajax'})]
+       ]
+       [(#CONFIG{zengarden_switcher}|non)
+               [(#BOUTON_ACTION{<:zengarden:switcher_activer:>,#URL_ACTION_AUTEUR{zengarden_activer_switcher,on,#SELF},'switcher ajax'})]
+       ]
+#BOITE_FERMER
diff --git a/www/plugins/zen-garden-2/prive/style_prive_plugin_zengarden.html b/www/plugins/zen-garden-2/prive/style_prive_plugin_zengarden.html
new file mode 100644 (file)
index 0000000..f5f2581
--- /dev/null
@@ -0,0 +1,22 @@
+[(#REM) <style>]
+#SET{claire,##ENV{couleur_claire,edf3fe}}
+#SET{foncee,##ENV{couleur_foncee,3874b0}}
+#SET{left,#ENV{ltr}|choixsiegal{left,left,right}}
+#SET{right,#ENV{ltr}|choixsiegal{left,right,left}}
+
+.zengarden .themes li.item {padding-#GET{left}:227px;}
+.zengarden .themes li.item .spip_documents_left {background:#eee;padding:5px;border:1px solid #e1e1e1;margin-#GET{left}:-227px;position:relative;display:inline;}
+.zengarden .themes li.item .bandeau {margin-top:5px;font-style:italic;}
+.zengarden .themes li.item .squelette {margin-top: 1em;}
+
+.zengarden .liste_themes {list-style:none;margin:0;padding:0;font-size:11px;}
+.zengarden .liste_themes .theme {margin:0;padding:10px 5px;border-bottom:1px solid #e1e1e1;overflow:hidden;float:left;width:115px;height:150px;position:relative;}
+.zengarden .liste_themes .theme:hover {background-color:[#(#GET{claire}|couleur_eclaircir)];}
+.zengarden .liste_themes .theme img {margin:0;display:block;float:none;position:absolute;top:10px;left:5px;padding:5px;background:#eee;border:1px solid #e1e1e1;}
+.zengarden .liste_themes .theme h3 {margin-top:0;padding-top:95px;font-size:1.2em;}
+.zengarden .liste_themes .theme h3 span {font-size:0.9em;}
+
+.zengarden .liste_themes .theme .actions {text-align:#GET{right};font-size:0.9em;}
+.zengarden .liste_themes .theme .bandeau {margin-top:5px;font-style:italic;}
+.zengarden .liste_themes .theme .squelette {margin-top: 1em;}
+.zengarden .liste_themes .theme .qTipContent {display:none;}
diff --git a/www/plugins/zen-garden-2/prive/themes/spip/images/themes-16.png b/www/plugins/zen-garden-2/prive/themes/spip/images/themes-16.png
new file mode 100644 (file)
index 0000000..ebfc103
Binary files /dev/null and b/www/plugins/zen-garden-2/prive/themes/spip/images/themes-16.png differ
diff --git a/www/plugins/zen-garden-2/svn.revision b/www/plugins/zen-garden-2/svn.revision
new file mode 100644 (file)
index 0000000..7310523
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_plugins_/zen-garden/trunk
+Revision: 70615
+Dernier commit: 2013-03-12 03:42:31 +0100 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_plugins_/zen-garden/trunk</origine>
+<revision>70615</revision>
+<commit>2013-03-12 03:42:31 +0100 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/zen-garden-2/zengarden_fonctions.php b/www/plugins/zen-garden-2/zengarden_fonctions.php
new file mode 100644 (file)
index 0000000..715edd8
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Plugin Zen-Garden pour Spip 3.0
+ * Licence GPL (c) 2006-2013 Cedric Morin
+ * 
+ * @package SPIP\Zen-Garden\Fonctions
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+function zengarden_affiche_version_compatible($intervalle){
+       if (!strlen($intervalle)) return '';
+       if (!preg_match(',^[\[\(]([0-9.a-zRC\s]*)[;]([0-9.a-zRC\s]*)[\]\)]$,',$intervalle,$regs)) return false;
+       $mineure = $regs[1];
+       $majeure = $regs[2];
+       $mineure_inc = $intervalle{0}=="[";
+       $majeure_inc = substr($intervalle,-1)=="]";
+       if (strlen($mineure)){
+               if (!strlen($majeure))
+                       $version = _T('zengarden:intitule_version') . ($mineure_inc ? ' &ge; ' : ' &gt; ') . $mineure;
+               else
+                       $version = $mineure . ($mineure_inc ? ' &le; ' : ' &lt; ') . _T('zengarden:intitule_version') . ($majeure_inc ? ' &le; ' : ' &lt; ') . $majeure;
+       }
+       else {
+               $version = _T('zengarden:intitule_version') . ($majeure_inc ? ' &le; ' : ' &lt; ') . $majeure;
+       }
+
+       return $version;
+}
+
+/**
+ * Lister les thèmes
+ * 
+ * Les thèmes peuvent être présent dans :
+ * - themes/* à la racine (ou autre _DIR_THEMES défini);
+ * - squelettes/themes/*;
+ * - plugins/*;
+ *
+ * @param bool $tous
+ * @return array
+ */
+function zengarden_liste_themes($tous){
+       include_spip('inc/zengarden');
+
+       $themes = array();
+
+       // charger les themes de themes/
+       if (is_dir(_DIR_THEMES))
+               $themes = array_merge($themes,zengarden_charge_themes(_DIR_THEMES,$tous));
+
+       // ceux de squelettes/themes/
+       if (is_dir($skels=_DIR_RACINE."squelettes/themes/"))
+               $themes = array_merge($themes,zengarden_charge_themes($skels,$tous));
+
+       // ceux de chaque  dossier_squelettes/themes/
+       if (strlen($GLOBALS['dossier_squelettes'])){
+               $s = explode(":",$GLOBALS['dossier_squelettes']);
+               foreach($s as $d){
+                       if (_DIR_RACINE AND strncmp($d,_DIR_RACINE,strlen(_DIR_RACINE))!==0)
+                               $d = _DIR_RACINE . $d;
+                       if (is_dir($f="$d/themes/") AND $f!=$skels)
+                               $themes = array_merge($themes,zengarden_charge_themes($f,$tous));
+               }
+       }
+
+       // ceux de plugins/
+       $themes = array_merge($themes,zengarden_charge_themes(_DIR_PLUGINS,$tous));
+
+       /**
+        * Recherche spécifique
+        * Invalider les thèmes incompatibles
+        * 
+        * Si le squelette ou un plugin définit la constante _ZENGARDEN_FILTRE_THEMES, 
+        * on ne prend que les thèmes compatibles
+        * Sinon, si on a le plugin zpip-dist, on ne liste que les thèmes compatibles avec zpip-dist
+        * 
+        * Pour être compatible un thème doit avoir un <utilise...> du squelette en question dans son paquet.xml
+        */
+       $search = "";
+       if (defined('_ZENGARDEN_FILTRE_THEMES')) $search=_ZENGARDEN_FILTRE_THEMES;
+       elseif (defined('_DIR_PLUGIN_ZPIP')) $search="zpip";
+       elseif (defined('_DIR_PLUGIN_Z')) $search="z";
+       
+       if ($search){
+               foreach ($themes as $k => $theme){
+                       $keep = false;
+                       foreach ($theme['utilise'] as $u){
+                               if (strncasecmp($u['nom'],$search,max(strlen($u['nom']),strlen($search)))==0){
+                                       $keep = true;
+                                       continue;
+                               }
+                       }
+                       if (!$keep)
+                               unset($themes[$k]);
+               }
+       }
+
+       // et voila
+       return $themes;
+}
+
+/**
+ * Insertion dans le pipeline filter_liste_plugins (SPIP)
+ * 
+ * Enlève les thèmes de la liste des plugins dans le privé
+ * 
+ * @param array $flux 
+ *              Le tableau de la liste des plugins
+ * @return array $flux 
+ *              Le tableau de la liste des plugins modifié
+ */
+function zengarden_filtrer_liste_plugins($flux){
+       foreach($flux['data'] as $d=>$info){
+               if ($info['categorie']=='theme'){
+                       unset($flux['data'][$d]);
+               }
+       }
+       return $flux;
+}
+
+?>
\ No newline at end of file
diff --git a/www/plugins/zen-garden-2/zengarden_options.php b/www/plugins/zen-garden-2/zengarden_options.php
new file mode 100644 (file)
index 0000000..48cb81f
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Plugin Zen-Garden pour Spip 3.0
+ * Licence GPL (c) 2006-2013 Cedric Morin
+ * 
+ * Fichier des options du plugins
+ * 
+ * @package SPIP\Zen-Garden\Options
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+if (!defined('_DIR_PLUGIN_THEME')){
+       // si on est en mode apercu, il suffit de repasser dans l'espace prive pour desactiver l'apercu
+       if (test_espace_prive()){
+               if (isset($_COOKIE['spip_zengarden_theme'])){
+                       include_spip('inc/cookie');
+                       spip_setcookie('spip_zengarden_theme',$_COOKIE['spip_zengarden_theme']='',-1);
+               }
+       }
+       // si le switcher est actif ou la globale var_theme
+       elseif(isset($GLOBALS['meta']['zengarden_switcher']) OR defined('_ZEN_VAR_THEME')){
+               if (!is_null($arg = _request('var_theme'))){
+                       include_spip('inc/cookie');
+                       if ($arg)
+                               spip_setcookie('spip_zengarden_theme',$_COOKIE['spip_zengarden_theme'] = $arg);
+                       else
+                               spip_setcookie('spip_zengarden_theme',$_COOKIE['spip_zengarden_theme']='',-1);
+               }
+       }
+       
+       // ajouter le theme au path
+       if (
+       (
+               // on est en mode apercu
+               (isset($_COOKIE['spip_zengarden_theme']) AND $t = $_COOKIE['spip_zengarden_theme'])
+        // ou avec le cookie du switcher
+               OR
+               // ou un theme est vraiment selectionne
+               (isset($GLOBALS['meta']['zengarden_theme']) AND $t = $GLOBALS['meta']['zengarden_theme'])
+       )
+       AND is_dir(_DIR_RACINE . $t)){
+               _chemin(_DIR_RACINE . $t);
+               $GLOBALS['marqueur'] = (isset($GLOBALS['marqueur'])?$GLOBALS['marqueur']:"").":theme-$t";
+               // @experimental : sauver le nom du repertoire theme utilise
+               // a defaut de connaitre le vrai prefixe
+               if (!defined('NOM_THEME')) { define('NOM_THEME', basename($t));}
+       }
+       
+       // @experimental : balise #THEME qui retourne le nom du theme selectionne
+       function balise_THEME_dist($p){
+               $p->code = "(defined('NOM_THEME') ? NOM_THEME : '')";
+               return $p;
+       }
+}
+
+/**
+ * Insertion dans le pipeline affichage_final (SPIP)
+ * 
+ * Ajoute le switcher de thème dans l'espace public
+ * 
+ * @param string $texte
+ *             Le contenu html de la page avant affichage au client
+ * @return string $texte
+ *             Le contenu html de la page modifié
+ */
+function zengarden_affichage_final($texte){
+       if ($GLOBALS['html'] and isset($GLOBALS['meta']['zengarden_switcher'])){
+               include_spip('prive/zengarden_theme_fonctions');
+               // on passe le theme selectionne en js pour ne pas polluer le cache du switcher
+               $code = 
+                       "<script type='text/javascript'>var theme_selected='".$_COOKIE['spip_zengarden_theme']."'</script>"
+                       . recuperer_fond('inclure/zengarden_switcher');
+               // On rajoute le code du selecteur de squelettes avant la balise </body>
+               $texte=str_replace("</body>",$code."</body>",$texte);
+       }
+       return $texte;
+}
+
+?>
diff --git a/www/plugins/zen-garden-2/zengarden_pipelines.php b/www/plugins/zen-garden-2/zengarden_pipelines.php
new file mode 100644 (file)
index 0000000..44f5ee2
--- /dev/null
@@ -0,0 +1,32 @@
+<?php\r
+/**\r
+ * Plugin Zen-Garden pour Spip 3.0\r
+ * Licence GPL (c) 2006-2013 Cedric Morin\r
+ * \r
+ * Fichier des utilisations des pipelines du plugin\r
+ * \r
+ * @package SPIP\Zen-Garden\Pipelines\r
+ */\r
+\r
+if (!defined('_ECRIRE_INC_VERSION')) return;\r
+\r
+/**\r
+ * Insertion dans le pipeline header_prive\r
+ * \r
+ * Insertion des deux scripts javascript pour les tooltips dans l'espace privé\r
+ * \r
+ * @param string $flux\r
+ *             Le code html du head de l'espace privé\r
+ * @return string $flux\r
+ *             Le code html du head complété\r
+ */\r
+function zengarden_header_prive($flux){\r
+       if (_request('exec') == 'zengarden')\r
+               $flux .='\r
+               <script src="'.find_in_path('javascript/jquery.qtip-1.0.0-rc3.js').'" type="text/javascript"></script>\r
+               <script src="'.find_in_path('javascript/jquery.qtip.activate.js').'" type="text/javascript"></script>';\r
+\r
+       return $flux;\r
+}\r
+\r
+?>\r
diff --git a/www/plugins/zpip_v1/404.html b/www/plugins/zpip_v1/404.html
new file mode 100644 (file)
index 0000000..4ebccac
--- /dev/null
@@ -0,0 +1,4 @@
+#HTTP_HEADER{#VAL{"HTTP/1.0 "}|concat{#ENV{code,"404 Not Found"}}}
+#HTTP_HEADER{"Cache-Control: no-store, no-cache, must-revalidate"}
+#HTTP_HEADER{Pragma: no-cache}
+<INCLURE{fond=structure}{env}{type=page}{composition=#ENV{status,404}} />
diff --git a/www/plugins/zpip_v1/article.html b/www/plugins/zpip_v1/article.html
new file mode 100644 (file)
index 0000000..0ef7ea0
--- /dev/null
@@ -0,0 +1,3 @@
+<BOUCLE_principale_article(ARTICLES){id_article}>
+<INCLURE{fond=structure}{env}{id_rubrique=#ENV{id_rubrique,#ID_RUBRIQUE}}{id_secteur=#ID_SECTEUR}{type=article}{composition=#COMPOSITION} />
+</BOUCLE_principale_article>
diff --git a/www/plugins/zpip_v1/auteur.html b/www/plugins/zpip_v1/auteur.html
new file mode 100644 (file)
index 0000000..bd18e58
--- /dev/null
@@ -0,0 +1,3 @@
+<BOUCLE_principale_auteur(AUTEURS){id_auteur}>
+<INCLURE{fond=structure}{env}{type=auteur}{composition=#COMPOSITION} />
+</BOUCLE_principale_auteur>
diff --git a/www/plugins/zpip_v1/backend.html b/www/plugins/zpip_v1/backend.html
new file mode 100644 (file)
index 0000000..803ef9c
--- /dev/null
@@ -0,0 +1,43 @@
+[(#REM)
+       Ce fichier sert à créer les flux RSS
+       qui permettent aux visiteurs de suivre l'actualité
+       de votre site depuis un lecteur de news.
+
+       Cette page génère un code XML/RSS adapté
+
+][(#HTTP_HEADER{Content-type: text/xml[; charset=(#CHARSET)]})]<?xml
+version="1.0"[ encoding="(#CHARSET)"]?>
+<rss version="2.0" [(#REM) rss 2.0.9)]
+       xmlns:dc="http://purl.org/dc/elements/1.1/"
+       xmlns:content="http://purl.org/rss/1.0/modules/content/"
+       xmlns:atom="http://www.w3.org/2005/Atom"
+>
+
+<channel[ xml:lang="(#LANG)"]>
+       <title>[(#NOM_SITE_SPIP|textebrut|texte_backend)]</title>
+       <link>#URL_SITE_SPIP/</link>
+       [<description>(#DESCRIPTIF_SITE_SPIP|supprimer_tags|texte_backend)</description>]
+       <language>#LANG</language>
+       <generator>SPIP - www.spip.net</generator>
+       <atom:link href="[(#SELF|url_absolue)]" rel="self" type="application/rss+xml" />
+
+[      <image>
+               <title>[(#NOM_SITE_SPIP|texte_backend)]</title>
+               <url>(#LOGO_SITE_SPIP||image_reduire{144,400}|extraire_attribut{src}|url_absolue|texte_backend)</url>
+               <link>#URL_SITE_SPIP/</link>
+               [<height>(#LOGO_SITE_SPIP||image_reduire{144,400}|extraire_attribut{height})</height>]
+               [<width>(#LOGO_SITE_SPIP||image_reduire{144,400}|extraire_attribut{width})</width>]
+       </image>
+]
+
+<BOUCLE_10recents(ARTICLES) {lang ?}{branche ?}{id_mot ?}{id_auteur ?} {par date}{inverse}{0,10}{unique}>
+<INCLURE{fond=inclure/rss-item}{id_article}>
+</BOUCLE_10recents>
+
+<BOUCLE_tres_recents(ARTICLES){lang ?}{branche ?}{id_mot ?}{id_auteur ?} {par date}{inverse}{age<3}{unique}>
+<INCLURE{fond=inclure/rss-item}{id_article}>
+</BOUCLE_tres_recents>
+
+</channel>
+
+</rss>
diff --git a/www/plugins/zpip_v1/body.html b/www/plugins/zpip_v1/body.html
new file mode 100644 (file)
index 0000000..539de2a
--- /dev/null
@@ -0,0 +1,23 @@
+<div id="page">
+       <div id="entete">
+               <INCLURE{fond=inclure/entete,env}>
+       </div>
+       <div id="nav">
+               <INCLURE{fond=inclure/barre-nav,env}>
+       </div>
+       
+       <div id="conteneur">    
+               <div id="contenu">
+                       <INCLURE{fond=contenu/#ENV{type},env}>
+               </div>
+
+               <div id="navigation">
+                       <INCLURE{fond=navigation/#ENV{type},env}>
+                       <INCLURE{fond=extra/#ENV{type},env}>
+               </div>
+       </div>
+
+       <div id="pied">
+               <INCLURE{fond=inclure/pied,env}>
+       </div>
+</div>
diff --git a/www/plugins/zpip_v1/breve.html b/www/plugins/zpip_v1/breve.html
new file mode 100644 (file)
index 0000000..cf9ec45
--- /dev/null
@@ -0,0 +1,3 @@
+<BOUCLE_breve_principal(BREVES) {id_breve}>
+<INCLURE{fond=structure}{env}{id_rubrique=#ENV{id_rubrique,#ID_RUBRIQUE}}{type=breve}{composition=#COMPOSITION} />
+</BOUCLE_breve_principal>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contact.html b/www/plugins/zpip_v1/contact.html
new file mode 100644 (file)
index 0000000..7b5b214
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=structure}{env}{type=page}{composition=contact} />
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/article.html b/www/plugins/zpip_v1/contenu/article.html
new file mode 100644 (file)
index 0000000..049eb05
--- /dev/null
@@ -0,0 +1,46 @@
+<BOUCLE_contenu_article(ARTICLES){id_article}>
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a><BOUCLE_ariane(HIERARCHIE){id_article}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a></BOUCLE_ariane>[ &gt; <strong class="on">(#TITRE|couper{80})</strong>]</p>
+
+<div class="contenu-principal">
+       <div class="cartouche">
+               [(#LOGO_ARTICLE||image_reduire{200,200})]
+               [<p class="#EDIT{surtitre} surtitre">(#SURTITRE)</p>]
+               <h1 class="h1 #EDIT{titre}">#TITRE</h1>
+               [<p class="#EDIT{soustitre} soustitre">(#SOUSTITRE)</p>]
+
+               <p class="info-publi"><abbr class="published" title="[(#DATE|date_iso)]">[(#DATE|nom_jour) ][(#DATE|affdate)]</abbr>[, <span class="auteurs"><:par_auteur:> (#LESAUTEURS)</span>]</p>
+               [(#REM) Inclure le modele des liens de traductions ]
+               #MODELE{article_traductions}
+       </div>
+
+       <div class="surlignable">
+               [<div class="#EDIT{chapo} chapo">(#CHAPO|image_reduire{500,0})</div>]
+               [<div class="#EDIT{texte} texte">(#TEXTE|image_reduire{500,0})</div>]
+       </div>
+
+       [<p class="#EDIT{hyperlien} hyperlien"><:voir_en_ligne:> : <a href="(#URL_SITE)" class="spip_out">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+
+       [<div class="ps">
+               <h2 class="h2"><:info_ps:></h2>
+               <div class="#EDIT{ps} surlignable">(#PS|image_reduire{500,0})</div>
+       </div>]
+
+[(#REM) Gestion du portfolio et des documents ]
+[(#INCLURE{fond=inclure/documents}{id_article})]
+
+</div>
+
+[(#REM) Petition :
+La petition ayant une PAGINATION il faut absolument {env}
+et pourquoi pas ajax
+][(#PETITION|oui)<INCLURE{fond=inclure/petition}{id_article}{env}{ajax}>]
+
+[<div class="notes surlignable"><h2 class="h2 pas_surlignable"><:info_notes:></h2>(#NOTES)</div>]
+
+[(#REM) Forum de l'article ]
+<a href="#forum" name="forum" id="forum"></a>
+<INCLURE{fond=inclure/forum}{id_article} />
+[<p class="repondre"><a href="(#PARAMETRES_FORUM|url_reponse_forum)" rel="noindex nofollow"><:repondre_article:></a></p>]
+
+</BOUCLE_contenu_article>
diff --git a/www/plugins/zpip_v1/contenu/auteur.html b/www/plugins/zpip_v1/contenu/auteur.html
new file mode 100644 (file)
index 0000000..da0f11e
--- /dev/null
@@ -0,0 +1,37 @@
+<BOUCLE_contenu_auteur(AUTEURS){id_auteur}>
+    
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a> &gt; <:info_auteurs:>[ &gt; <strong class="on">(#NOM|couper{80})</strong>]</p>
+
+<div class="contenu-principal">
+       <div class="vcard">[(#REM) microformat vcard]
+       <div class="cartouche">
+               [(#LOGO_AUTEUR||image_reduire{200,200})]
+               <h1 class="h1 #EDIT{qui} fn">#NOM</h1>
+       </div>
+
+       [<div class="#EDIT{bio} texte note">(#BIO)</div>]
+       [<p class="#EDIT{hyperlien} hyperlien"><:voir_en_ligne:> : <a href="(#URL_SITE)" class="url spip_out">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+       </div>[(#REM) / vcard]
+
+       [(#REM) Articles de l'auteur ]
+       <B_articles>
+       <div class="liste articles">
+               #ANCRE_PAGINATION
+               <h2 class="h2"><:articles_auteur:> (#GRAND_TOTAL)</h2>
+               <ul class="liste-items">
+                       <BOUCLE_articles(ARTICLES) {id_auteur} {!par popularite} {pagination 10}>
+                       <li class="item"><a href="#URL_ARTICLE">#TITRE</a></li>
+                       </BOUCLE_articles>
+               </ul>
+               [<p class="pagination">(#PAGINATION)</p>]
+       </div>
+       </B_articles>
+
+</div>
+
+#FORMULAIRE_ECRIRE_AUTEUR
+
+[<div class="notes"><h2 class="h2"><:info_notes:></h2>(#NOTES)</div>]
+
+</BOUCLE_contenu_auteur>
diff --git a/www/plugins/zpip_v1/contenu/breve.html b/www/plugins/zpip_v1/contenu/breve.html
new file mode 100644 (file)
index 0000000..a7f38cd
--- /dev/null
@@ -0,0 +1,22 @@
+<BOUCLE_breve_principal(BREVES) {id_breve}>
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/" ><:accueil_site:></a><BOUCLE_ariane(RUBRIQUES){id_rubrique}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a></BOUCLE_ariane>[ &gt; <strong class="on">(#TITRE|couper{80})</strong>]</p>
+
+<div class="contenu-principal">
+
+  <div class="cartouche">
+      [(#LOGO_BREVE||image_reduire{200,200})]
+      <h1 class="h1 #EDIT{titre}">#TITRE</h1>
+      <p class="info-publi"><abbr class="published" title="[(#DATE|date_iso)]">[(#DATE|nom_jour) ][(#DATE|affdate)]</abbr></p>
+  </div>
+  
+  [<div class="#EDIT{texte} texte">(#TEXTE)</div>]
+  [<p class="lien"><:voir_en_ligne:> : <a href="(#URL_SITE)" class="spip_out">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+  [<div class="notes"><h2 class="h2"><:info_notes:></h2>(#NOTES)</div>]
+</div>
+[(#REM) Forum de la breve
+NB : pour desactiver les forums de breve, supprimez simplement les lignes ci-dessous ]
+<a href="#forum" name="forum" id="forum"></a>
+<INCLURE{fond=inclure/forum}{id_breve}>
+[<p class="repondre"><a href="(#PARAMETRES_FORUM|url_reponse_forum)" rel="noindex nofollow"><:repondre_breve:></a></p>]
+</BOUCLE_breve_principal>
diff --git a/www/plugins/zpip_v1/contenu/mot.html b/www/plugins/zpip_v1/contenu/mot.html
new file mode 100644 (file)
index 0000000..fb48887
--- /dev/null
@@ -0,0 +1,80 @@
+<BOUCLE_principale(MOTS) {id_mot} {doublons}>
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a> &gt; <:mots_clefs:><BOUCLE_ariane(GROUPES_MOTS){id_groupe}> &gt; [(#TITRE|couper{80})]</BOUCLE_ariane>[ &gt; <strong class="on">(#TITRE|couper{80})</strong>]</p>
+
+<div class="contenu-principal">
+
+  <div class="cartouche">
+      [(#LOGO_MOT||image_reduire{200,200})]
+      <h1 class="h1 #EDIT{titre}">#TITRE</h1>
+  </div>
+
+  [<div class="#EDIT{texte} chapo">(#TEXTE)</div>]
+
+  [(#REM) Articles lies au mot-cle ]
+  <B_articles>
+  <div class="liste articles">
+      #ANCRE_PAGINATION
+      <h2 class="h2"><:articles:></h2>
+      <ul class="liste-items">
+          <BOUCLE_articles(ARTICLES) {id_mot} {par popularite}{inverse} {pagination 10}>
+          <li class="item">
+          <h3 class="h3"><a href="#URL_ARTICLE">#TITRE</a></h3>
+          <div class="small">[(#DATE|affdate_jourcourt)][, <:par_auteur:> (#LESAUTEURS)]</div></li>
+          </BOUCLE_articles>
+      </ul>
+      [<p class="pagination">(#PAGINATION)</p>]
+  </div>
+  </B_articles>
+
+  [(#REM) Rubriques liees au mot-cle ]
+  <B_rubriques>
+  <div class="liste rubriques">
+      <h2 class="h2"><:rubriques:></h2>
+      <ul class="liste-items">
+          <BOUCLE_rubriques(RUBRIQUES) {id_mot} {par titre}>
+          <li class="item"><a href="#URL_RUBRIQUE">#TITRE</a></li>
+          </BOUCLE_rubriques>
+      </ul>
+  </div>
+  </B_rubriques>
+
+  [(#REM) Breves liees au mot-cle ]
+  <B_breves>
+  <div class="liste breves">
+      <h2 class="h2"><:breves:></h2>
+      <ul class="liste-items">
+          <BOUCLE_breves(BREVES) {id_mot} {par titre}>
+          <li class="item"><a href="#URL_BREVE">#TITRE</a></li>
+          </BOUCLE_breves>
+      </ul>
+  </div>
+  </B_breves>
+
+  [(#REM) Liens des forums ]
+  <B_forums_liens>
+  <div class="liste forums">
+      <h2 class="h2"><:messages_forum:></h2>
+      <ul class="liste-items">
+          <BOUCLE_forums_liens(FORUMS) {id_mot} {plat} {par date}{inverse}>
+          <li class="item">[(#DATE|affdate_jourcourt) &ndash; ]<a href="#URL_FORUM">[(#TEXTE|couper{80})]</a></li>
+          </BOUCLE_forums_liens>
+      </ul>
+  </div>
+  </B_forums_liens>
+
+  [(#REM) Sites web lies au mot-cle ]
+  <B_sites>
+  <div class="liste sites">
+      <h2 class="h2"><:sites_web:></h2>
+      <ul class="liste-items">
+          <BOUCLE_sites(SITES) {id_mot} {par nom_site}>
+                                       <li class="item"><a href="[(#ID_SYNDIC|generer_url_entite{site,'','',#CONNECT})]">#NOM_SITE</a></li>
+                                       </BOUCLE_sites>
+      </ul>
+  </div>
+  </B_sites>
+</div>
+
+[<div class="notes"><h2 class="h2"><:info_notes:></h2>(#NOTES)</div>]
+</BOUCLE_principale>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/page-401.html b/www/plugins/zpip_v1/contenu/page-401.html
new file mode 100644 (file)
index 0000000..e16575b
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a> &gt; <strong class="on"><:pass_erreur:>[ (#ENV{status})]</strong></p>
+
+<div class="contenu-principal">
+       <div class="cartouche">
+               <h1 class="h1"><:pass_erreur:>[ (#ENV{status})]</h1>
+       </div>
+       [<div class="chapo">(#ENV*{erreur}|propre)</div>]
+       #FORMULAIRE_LOGIN{#ENV{cible},'',0}
+</div>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/page-404.html b/www/plugins/zpip_v1/contenu/page-404.html
new file mode 100644 (file)
index 0000000..754951d
--- /dev/null
@@ -0,0 +1,9 @@
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a> &gt; <strong class="on"><:pass_erreur:> 404</strong></p>
+
+<div class="contenu-principal">
+       <div class="cartouche">
+               <h1 class="h1"><:pass_erreur:> 404</h1>
+       </div>
+       [<div class="chapo">(#ENV{erreur})</div>]
+</div>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/page-forum.html b/www/plugins/zpip_v1/contenu/page-forum.html
new file mode 100644 (file)
index 0000000..38792d8
--- /dev/null
@@ -0,0 +1,89 @@
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a>
+
+    <BOUCLE_contexte_article(ARTICLES) {id_article}>
+    <BOUCLE_ariane_article(HIERARCHIE) {id_article}>
+    &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a>
+    </BOUCLE_ariane_article>
+    &gt; <a href="#URL_ARTICLE">[(#TITRE|couper{80})]</a>
+    </BOUCLE_contexte_article>
+    </B_contexte_article>
+
+    <BOUCLE_contexte_breve(BREVES) {id_breve}>
+    <BOUCLE_ariane_breve(RUBRIQUES) {id_rubrique}>
+    &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a>
+    </BOUCLE_ariane_breve>
+    &gt; <a href="#URL_BREVE">[(#TITRE|couper{80})]</a>
+    </BOUCLE_contexte_breve>
+
+    <BOUCLE_contexte_rubrique(RUBRIQUES) {id_rubrique}>
+    <BOUCLE_ariane_rubrique(HIERARCHIE) {id_rubrique}>
+    &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a>
+    </BOUCLE_ariane_rubrique>
+    &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a>
+    </BOUCLE_contexte_rubrique>
+
+    <BOUCLE_contexte_site(SITES) {id_syndic}>
+    <BOUCLE_ariane_site(HIERARCHIE) {id_rubrique}>
+    &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a>
+    </BOUCLE_ariane_site>
+    &gt; <a href="[(#ID_SYNDIC|generer_url_entite{'site'})]">[(#TITRE|couper{80})]</a>
+    </BOUCLE_contexte_site>
+
+    <//B_contexte_site>
+    <//B_contexte_rubrique>
+    <//B_contexte_breve>
+    <//B_contexte_article>
+
+    <BOUCLE_contexte_forum(FORUMS) {id_forum}>
+    &gt; <a href="#URL_FORUM">[(#TITRE|couper{80})]</a>
+    </BOUCLE_contexte_forum>
+
+    &gt; <strong class="on"><:poster_message:></strong>
+    
+</p><!--#hierarchie-->
+
+<div class="contenu-principal">
+
+<div class="cartouche">
+    <h1 class="h1"><:poster_message:></h1>
+</div>
+
+<div class="resume articles">
+    <h2 class="h2"><:en_reponse:></h2>
+
+    <BOUCLE_forum_parent(FORUMS) {id_forum}>
+    <h3 class="h3"><a href="#URL_FORUM">#TITRE</a></h3>
+               <div class="info-publi">[<abbr class="published" title="[(#DATE|date_iso)]">(#DATE|affdate_jourcourt)[&nbsp;(#DATE|heures)][:(#DATE|minutes)]</abbr>][<span class="sep">, </span><span class="auteurs"><:par_auteur:> (#NOM)</span>]</div>
+    [<div class="introduction">(#INTRODUCTION|lignes_longues)</div>]
+    </BOUCLE_forum_parent>
+    
+    <BOUCLE_article(ARTICLES) {id_article}>
+               <ul class="liste-items">
+               #INCLURE{fond=inclure/article-resume,id_article}
+               </ul>
+    </BOUCLE_article>
+    
+    <BOUCLE_breve(BREVES) {id_breve}>
+    [(#LOGO_BREVE||image_reduire{150,100})]
+    <h3 class="h3"><a href="#URL_BREVE">#TITRE</a></h3>
+               <div class="info-publi">[<abbr class="published" title="[(#DATE|date_iso)]">(#DATE|affdate_jourcourt)</abbr>]</div>
+    [<div class="introduction">(#INTRODUCTION)</div>]
+    </BOUCLE_breve>
+    
+    <BOUCLE_rubrique(RUBRIQUES) {id_rubrique}>
+    <h3 class="h3"><a href="#URL_RUBRIQUE">#TITRE</a></h3>
+    [<div class="texte">(#TEXTE)</div>]
+    </BOUCLE_rubrique>
+    
+    <BOUCLE_syndic(SITES) {id_syndic}>
+    <h3 class="h3"><a href="[(#ID_SYNDIC|generer_url_entite{'site'})]">#NOM_SITE</a></h3>
+    [<div class="texte">(#DESCRIPTIF)</div>]
+    </BOUCLE_syndic>
+    
+    <//B_forum_parent>
+
+</div>
+
+#FORMULAIRE_FORUM
+</div>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/page-login.html b/www/plugins/zpip_v1/contenu/page-login.html
new file mode 100644 (file)
index 0000000..4e386aa
--- /dev/null
@@ -0,0 +1,18 @@
+[(#REM)
+       Est-ce qu'on se connecte a l'espace prive ou pas ?
+]#SET{prive,''}
+[(#ENV{url}|=={''}|?{#SET{prive,' '}})]
+[(#ENV{url}|match{^#EVAL{_DIR_RESTREINT_ABS}}|?{#SET{prive,' '}})]
+
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a>[ &gt; <strong class="on">(#GET{prive}|?{<:login_acces_prive:>,<:lien_connecter:>})</strong>]</p>
+
+<div class="contenu-principal">
+       <div class="cartouche">
+               [<h1 class="h1">(#GET{prive}|?{<:login_acces_prive:>,<:lien_connecter:>})</h1>]
+               <p class="soustitre">#NOM_SITE_SPIP</p>
+       </div>
+       #MENU_LANG_ECRIRE
+       
+       [(#FORMULAIRE_LOGIN{#ENV{url}|sinon{#URL_ECRIRE{accueil}}})]
+</div>
diff --git a/www/plugins/zpip_v1/contenu/page-plan.html b/www/plugins/zpip_v1/contenu/page-plan.html
new file mode 100644 (file)
index 0000000..4d532d7
--- /dev/null
@@ -0,0 +1,45 @@
+      
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a> &gt; <strong class="on"><:plan_site:></strong></p>
+
+<div class="contenu-principal">
+<div class="cartouche">
+       <h1 class="h1"><:plan_site:></h1>
+</div>
+
+<BOUCLE_secteurs(RUBRIQUES) {racine} {par titre}>
+
+       <h2 class="h2"><a href="#URL_RUBRIQUE">#TITRE</a></h2>
+
+       [(#REM) Articles et sous-rubriques ]
+       <B_articles_racine>
+       <h3 class="h3"><:articles:></h3>
+       <ul class="plan">
+               <BOUCLE_articles_racine(ARTICLES) {id_rubrique} {par titre}>
+               <li><a href="#URL_ARTICLE">#TITRE</a></li>
+               </BOUCLE_articles_racine>
+       </ul>
+       </B_articles_racine>
+
+       <B_rubriques>
+       <ul class="plan">
+               <BOUCLE_rubriques(RUBRIQUES) {id_parent} {par titre}>
+               <li>
+                       <strong><a href="#URL_RUBRIQUE">#TITRE</a></strong>
+                       
+                       <B_articles>
+                       <ul>
+                               <BOUCLE_articles(ARTICLES) {id_rubrique} {par titre}>
+                               <li><a href="#URL_ARTICLE">#TITRE</a></li>
+                               </BOUCLE_articles>
+                       </ul>
+                       </B_articles>
+                       
+                       <BOUCLE_sous_rubriques(BOUCLE_rubriques)></BOUCLE_sous_rubriques>
+               </li>
+               </BOUCLE_rubriques>
+       </ul>
+       </B_rubriques>
+
+</BOUCLE_secteurs>
+</div>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/page-recherche.html b/www/plugins/zpip_v1/contenu/page-recherche.html
new file mode 100644 (file)
index 0000000..06950cb
--- /dev/null
@@ -0,0 +1,38 @@
+               
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a> &gt; <:info_rechercher:>[ &gt; <strong class="on">(#RECHERCHE)</strong>]</p>
+
+<div class="contenu-principal">
+       [<div class="cartouche">
+               <h1 class="h1"><:resultats_recherche:></h1>
+               <p class="soustitre">&#171;&nbsp;(#RECHERCHE)&nbsp;&#187;</p>
+       </div>]
+
+       [(#REM) Articles trouves ]
+       <B_articles>
+       <div class="liste resultats articles">
+               #ANCRE_PAGINATION
+               <h2 class="h2"><:articles:> (#GRAND_TOTAL)</h2>
+               <ul class="liste-items">
+                       <BOUCLE_articles(ARTICLES) {recherche} {par points}{inverse} {pagination}>
+                       <li class="item"><a href="#URL_ARTICLE">#TITRE</a></li>
+                       </BOUCLE_articles>
+               </ul>
+               [<p class="pagination">(#PAGINATION)</p>]
+       </div>
+       </B_articles>
+
+       [(#REM) Rubriques trouvees ]
+       <B_rubriques>
+       <div class="liste resultats rubriques">
+               #ANCRE_PAGINATION
+               <h2 class="h2"><:rubriques:> (#GRAND_TOTAL)</h2>
+               <ul class="liste-items">
+                       <BOUCLE_rubriques(RUBRIQUES) {recherche} {par points}{inverse} {pagination 5}>
+                       <li class="item"><a href="#URL_RUBRIQUE">#TITRE</a></li>
+                       </BOUCLE_rubriques>
+               </ul>
+               [<p class="pagination">(#PAGINATION)</p>]
+       </div>
+       </B_rubriques>
+</div>
diff --git a/www/plugins/zpip_v1/contenu/page-sommaire.html b/www/plugins/zpip_v1/contenu/page-sommaire.html
new file mode 100644 (file)
index 0000000..90c7afe
--- /dev/null
@@ -0,0 +1,20 @@
+<div class="contenu-principal">
+       <div class="cartouche invisible">
+               <h1 class="h1 invisible">#NOM_SITE_SPIP</h1>
+       </div>
+
+       [<div id="descriptif_site_spip">(#DESCRIPTIF_SITE_SPIP)</div>]
+</div>
+
+<B_articles>
+<div class="liste articles sommaire">
+       #ANCRE_PAGINATION
+       <h2 class="h2"><:derniers_articles:></h2>
+       <ul class="liste-items">
+               <BOUCLE_articles(ARTICLES) {!par date} {pagination 5}>
+               #INCLURE{fond=inclure/article-resume,id_article}
+               </BOUCLE_articles>
+       </ul>
+       [<p class="pagination">(#PAGINATION)</p>]
+</div>
+</B_articles>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/page-spip_pass.html b/www/plugins/zpip_v1/contenu/page-spip_pass.html
new file mode 100644 (file)
index 0000000..70a2d8b
--- /dev/null
@@ -0,0 +1,12 @@
+<div class="contenu-principal">
+       <h1 class="h1 spip">#NOM_SITE_SPIP</h1>
+
+       <div class="pass">
+               [(#ENV{p}|non)
+                       #FORMULAIRE_OUBLI
+               ]
+               [(#ENV{p}|oui)
+                       #FORMULAIRE_MOT_DE_PASSE
+               ]
+       </div>
+</div>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/page.html b/www/plugins/zpip_v1/contenu/page.html
new file mode 100644 (file)
index 0000000..03c6f7b
--- /dev/null
@@ -0,0 +1,5 @@
+[(#REM)
+ Ce squelette n'est necessaire que pour SPIP 2.0
+ A partir de SPIP 2.1, le compilateur trouve directement contenu/page-xxx
+]<INCLURE{fond=contenu/page-#ENV{composition,sommaire}}{env}>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/rubrique.html b/www/plugins/zpip_v1/contenu/rubrique.html
new file mode 100644 (file)
index 0000000..5f82e2b
--- /dev/null
@@ -0,0 +1,99 @@
+<BOUCLE_contenu_rubrique(RUBRIQUES){id_rubrique}>
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a><BOUCLE_ariane(HIERARCHIE){id_rubrique}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a></BOUCLE_ariane>[ &gt; <strong class="on">(#TITRE|couper{80})</strong>]</p>
+
+<div class="contenu-principal">
+
+       <div class="cartouche">
+               [(#LOGO_RUBRIQUE||image_reduire{200,200})]
+               <h1 class="h1 #EDIT{titre}">#TITRE</h1>
+               [<p class="info-publi"><span class="published"><:dernier_ajout:> : (#DATE|affdate_jourcourt).</span></p>]
+       </div>
+
+       [<div class="#EDIT{texte} chapo">(#TEXTE)</div>]
+</div>
+
+<B_articles>
+<div class="liste articles">
+       #ANCRE_PAGINATION
+       <h2 class="h2"><:articles_rubrique:></h2>
+       <ul class="liste-items">
+               <BOUCLE_articles(ARTICLES){id_rubrique} {!par date} {pagination 5}>
+               #INCLURE{fond=inclure/article-resume,id_article}
+               </BOUCLE_articles>
+       </ul>
+       [<p class="pagination">(#PAGINATION)</p>]
+</div>
+</B_articles>
+
+       [(#REM) Si aucun article, affiche un plan de la rubrique ]
+       <B_sous_rubriques>
+       <div class="menu rubriques">
+               <h2 class="h2"><:sous_rubriques:></h2>
+               <ul class="menu-liste">
+                       <BOUCLE_sous_rubriques(RUBRIQUES) {id_parent} {par num titre, titre}>
+                       <li class="menu-entree">
+                               <a href="#URL_RUBRIQUE">[(#TITRE)]</a>
+
+                               [(#REM) Une boucle recursive pour le mini plan]
+                               <B_miniplan>
+                               <ul class="menu-liste">
+                                       <BOUCLE_miniplan(RUBRIQUES) {id_parent} {par num titre, titre}>
+                                       <li class="menu-entree">
+                                               <a href="#URL_RUBRIQUE">[(#TITRE)]</a>
+                                               <BOUCLE_m2(BOUCLE_miniplan)></BOUCLE_m2>
+                                       </li>
+                                       </BOUCLE_miniplan>
+                               </ul>
+                               </B_miniplan>
+
+                       </li>
+                       </BOUCLE_sous_rubriques>
+               </ul>
+               </div>
+       </B_sous_rubriques>
+<//B_articles>
+
+[(#REM) Gestion du portfolio et des documents ]
+[(#INCLURE{fond=inclure/documents}{id_rubrique})]      
+
+[(#REM) Breves du secteur ]
+<B_breves>
+<div class="liste breves">
+               #ANCRE_PAGINATION
+               <h2 class="h2"><:breves:></h2>
+               <ul class="liste-items">
+                               <BOUCLE_breves(BREVES) {id_rubrique} {par date}{inverse} {pagination 5}>
+                               <li class="item">[(#DATE|affdate_jourcourt) &ndash; ]<a href="#URL_BREVE">#TITRE</a></li>
+                               </BOUCLE_breves>
+               </ul>
+               [<p class="pagination">(#PAGINATION)</p>]
+</div>
+</B_breves>
+
+[(#REM) Sites de la rubrique ]
+<B_sites>
+<div class="liste sites">
+               <h2 class="h2"><:sur_web:></h2>
+               <ul class="liste-items">
+                               <BOUCLE_sites(SITES) {id_rubrique} {par nom_site}>
+                               <li class="item">
+       <a href="[(#ID_SYNDIC|generer_url_entite{site,'','',#CONNECT})]">#NOM_SITE</a>
+                                               <B_syndic>
+                                               <ul>
+                                                               <BOUCLE_syndic(SYNDIC_ARTICLES) {id_syndic} {age<180} {par date}{inverse} {0,3}>
+                                                               <li><a href="#URL_ARTICLE" class="spip_out">#TITRE</a></li>
+                                                               </BOUCLE_syndic>
+                                               </ul>
+                                               </B_syndic>
+                               </li>
+                               </BOUCLE_sites>
+               </ul>
+</div>
+</B_sites>
+
+[(#REM) Proposer un site ]
+#FORMULAIRE_SITE
+
+[<div class="notes"><h2 class="h2"><:info_notes:></h2>(#NOTES)</div>]
+</BOUCLE_contenu_rubrique>
diff --git a/www/plugins/zpip_v1/contenu/site.html b/www/plugins/zpip_v1/contenu/site.html
new file mode 100644 (file)
index 0000000..97650b3
--- /dev/null
@@ -0,0 +1,36 @@
+<BOUCLE_site(SITES){id_syndic}>
+[(#REM) Fil d'Ariane ]
+<p id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a><BOUCLE_ariane(HIERARCHIE){id_syndic}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a></BOUCLE_ariane>[ &gt; <strong class="on">(#NOM_SITE|couper{80})</strong>]</p>
+
+<div class="contenu-principal">
+
+  <div class="cartouche">
+      <a href="#URL_SITE">[(#LOGO_SITE||image_reduire{150,100})]</a>
+      <h1 class="h1 #EDIT{nom_site}">#NOM_SITE</h1>
+  </div>
+
+  [<div class="#EDIT{descriptif} chapo">(#DESCRIPTIF)</div>]
+  [<p class="#EDIT{url_site} hyperlien"><a href="#URL_SITE" class="spip_out">(#URL_SITE|couper{80})</a></p>]
+</div>
+
+  [(#REM) Articles issus de la syndication ]
+  <B_articles>
+  <div class="liste articles syndic">
+      #ANCRE_PAGINATION
+      <h2 class="h2"><:articles:></h2>
+      <ul class="liste-items">
+          <BOUCLE_articles(SYNDIC_ARTICLES) {id_syndic} {age<180} {par date}{inverse} {pagination 5}>
+          <li class="item">
+              <h3 class="h3"><a href="#URL_ARTICLE" class="spip_out">#TITRE</a></h3>
+              [<div class="enclosures">(#TAGS|afficher_enclosures)</div>]
+              <div class="small">[(#DATE|affdate_jourcourt)][, <:par_auteur:> (#LESAUTEURS)][ &mdash; <em>(#TAGS|afficher_tags)</em>]</div>
+              [<div class="introduction">(#DESCRIPTIF|image_reduire{300})</div>]
+          </li>
+          </BOUCLE_articles>
+      </ul>
+      [<p class="pagination">(#PAGINATION)</p>]
+  </div>
+  </B_articles>
+
+  [<div class="notes"><h2 class="h2"><:info_notes:></h2>(#NOTES)</div>]
+</BOUCLE_site>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/contenu/z_apl.html b/www/plugins/zpip_v1/contenu/z_apl.html
new file mode 100644 (file)
index 0000000..2ba4dc1
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM)
+
+  Squelette Big_Pipe
+       http://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
+
+  (c) 2010 Cedric Morin
+  Distribue sous licence GPL
+
+]#CACHE{0}
+#INCLURE{fond=inclure/ajax_parallel_load,bloc=#SQUELETTE}
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/conventions.txt b/www/plugins/zpip_v1/conventions.txt
new file mode 100644 (file)
index 0000000..083938e
--- /dev/null
@@ -0,0 +1,160 @@
+Le layout intègre 6 entités logiques de contenu qui structure dans le html a sa guise.
+Les 6 entités sont nommées ici selon la convention ci-dessous, eu égard à leur contenu informationnel
+et sans préjuger d'une quelconque structure définie par le theme :
+
+entete fournit la présentation de la page et d'identité
+barre-nav      constitue la navigation principale du site - peut être vide
+contenu        contient l'information principale de la page
+navigation     fournit des élements de navigation secondaire
+extra fournit des eléments d'information connexes
+pied   fournit des éléments de repérages et de rappels secondaires
+
+
+entete
+
+- un lien bloc .accueil contenant
+       - le logo eventuel [x], encadré par un element a
+       - le nom du site
+               dans un #nom_site_spip, qui peut être porté par toute balise. Il appartient au theme de fixer si il doit se comporter comme un block ou comme un inline
+               qui peut contenir un element a
+       - le slogan du site
+               dans un #slogan_site_spip
+
+Peut contenir
+- .formulaire_menu_lang  le formulaire de changement de langue qui n'apparaitra que sur les sites multilingues
+
+barre-nav
+       si elle est non vide, est structurée d'éléments imbriqués de classes
+       .menu-liste
+               encadre un lot de .menu-entree
+               contient exlusivement des elements .menu-entree
+       .menu-entree doit etre dans un element .menu-liste
+               contient un unique element a
+               peut contenir un unique element .sep contenant un separateur textuel
+               peut contenir des sous groupes .menu-entree
+
+       cette convention permet par exemple
+               une navigation hierarchisée de type ul.menu-liste/li.menu-entree a un ou plusieurs niveau
+               une navigation plate constituée d'une suite de liens
+
+       le theme devra prendre en charge au moins l'affichage du premier niveau de navigation
+       le theme pourra prendre en charge l'affichage d'un eventuel menu déroulant a 1 ou plusieurs niveaux si le squelette les fournit
+
+contenu
+
+       #hierarchie le fil d'ariane,
+               des liens 'a'
+               des elements separateurs '.sep'
+               un element en exergue '.on'
+
+       .cartouche      le cartouche de présentation du contenu
+               .titre  le titre
+               .spip_logos le logo
+               .surtitre
+               .soustitre
+               .traductions
+               .info-publi     Infos de publication
+                       .published      date de publication
+                       .auteurs        auteur de publication, avec seperateurs .sep eventuels
+                       .past-published date de publication anterieure
+
+       .postmeta cartouche de présentation des réactions
+               .date
+               a.comments
+               a.readmore
+
+               .post-info
+               .post-info a
+
+       .introduction
+       .descriptif
+       .chapo
+       .texte
+       .hyperlien
+       .ps
+       .notes
+
+       Portfolios :
+       .documents_portfolio (classe et pas id car il pourrait en avoir plusieurs)
+
+       Forums :
+               garder la structure de la dist ?
+
+       Petitions :
+               garder la structure de la dist ?
+
+
+navigation
+
+Peut contenir
+- une navigation de second niveau, structurée comme barre-nav, par .menu-liste, .menu-entree, .sep et a
+- Le formulaire de recherche. Les themes qui voudront le placer visuellement dans le bandeau supérieur procèderont par un positionnement absolu
+
+des intertitres .hx
+des listes d'items
+...
+
+extra
+...
+
+
+
+pied
+       peut contenir
+               TBD des registres horizontaux
+               TBD des colonnes verticales
+
+
+
+
+Elements généraux
+
+les intertitrages
+       .h1, .h2, .h3, .h4, .h5, .h6
+la pagination
+       .pagination contient a, .on et .separateur
+
+les listes d'items (liste d'articles, de breves, de rubriques ...)
+       .liste  : bloc englobant
+               peut contenir des p, .hx, .pagination ...
+               contient au moins un ul.liste-items
+                       qui contient un ou des li.item
+
+les formulaires
+       selon convention décrite dans http://www.spip.net/fr_article3791.html
+
+les tableaux de données
+       tables.spip
+               tr
+               tr.row_odd
+               tr.row_even
+                       th, td
+
+les liens :
+       a
+       a.spip_note /* liens vers notes de bas de page */
+       a.spip_ancre /* liens internes a la page */
+       a.spip_in /* liens internes */
+       a.spip_out /* liens sortants */
+a.external ?
+       a.spip_url /* liens url sortants */
+       a.spip_glossaire /* liens vers encyclopedie */
+
+
+les documents :
+       .spip_documents, .spip_documents_right, .spip_documents_left
+               img, peut etre dans un 'a'
+               .spip_doc_titre
+               .spip_doc_descriptif
+
+la "typo" (cf spip_styles.css)
+       .spip_code du code inline
+       .spip_cadre du code en block
+       acronym
+       abbr
+       blockquote.spip
+       blockquote.spip_poesie
+
+hr.spip
+.nettoyeur { clear: both; height: 0; margin: 0; padding: 0; border: 0; line-height: 1px; font-size: 1px; }
+.invisible { position: absolute; top: -3000em; height: 1%; }
diff --git a/www/plugins/zpip_v1/extra/article.html b/www/plugins/zpip_v1/extra/article.html
new file mode 100644 (file)
index 0000000..710d715
--- /dev/null
@@ -0,0 +1,26 @@
+<BOUCLE_extra_article(ARTICLES){id_article}>
+       [(#REM) Articles dans la meme rubrique ]
+       <B_articles_rubrique>
+       <div class="liste articles">
+               <h2 class="h2"><a href="#URL_RUBRIQUE"><:meme_rubrique:></a></h2>
+               <ul class="liste-items">
+                       <BOUCLE_articles_rubrique(ARTICLES) {id_rubrique} {par date}{inverse} {0,10}>
+                       <li class="item"><a href="#URL_ARTICLE"[ class="(#EXPOSE)"]>#TITRE</a></li>
+                       </BOUCLE_articles_rubrique>
+               </ul>
+       </div>
+       </B_articles_rubrique>
+
+  [(#REM) Menu de navigation mots-cles ]
+  <B_mots>
+  <div class="liste mots">
+      <h2 class="h2"><:mots_clefs:></h2>
+      <ul class="liste-items">
+      <BOUCLE_mots(MOTS) {id_article} {par titre}>
+          <li class="item"><a href="#URL_MOT" rel="tag">#TITRE</a></li>
+      </BOUCLE_mots>
+      </ul>
+  </div>
+  </B_mots>
+
+</BOUCLE_extra_article>
diff --git a/www/plugins/zpip_v1/extra/auteur.html b/www/plugins/zpip_v1/extra/auteur.html
new file mode 100644 (file)
index 0000000..7a351ce
--- /dev/null
@@ -0,0 +1,15 @@
+<BOUCLE_extra_auteur(AUTEURS){id_auteur}>
+       [(#REM) Autres auteurs ]
+       <B_auteurs>
+       <div class="liste auteurs">
+               #ANCRE_PAGINATION
+               <h2 class="h2"><:info_auteurs:></h2>
+               <ul class="liste-items">
+                       <BOUCLE_auteurs(AUTEURS) {par nom} {pagination 20}>
+                       <li class="item"><a href="#URL_AUTEUR"[ class="(#EXPOSE)"]>[(#NOM|couper{80})]</a></li>
+                       </BOUCLE_auteurs>
+               </ul>
+               [<p class="pagination">(#PAGINATION)</p>]
+       </div>
+       </B_auteurs>
+</BOUCLE_extra_auteur>
diff --git a/www/plugins/zpip_v1/extra/breve.html b/www/plugins/zpip_v1/extra/breve.html
new file mode 100644 (file)
index 0000000..f2f4227
--- /dev/null
@@ -0,0 +1,25 @@
+<BOUCLE_breve_principal(BREVES) {id_breve}>
+  [(#REM) Breves dans la meme rubrique ]
+  <B_breves>
+  <div class="liste breves">
+      <h2 class="h2"><:autres_breves:></h2>
+      <ul class="liste-items">
+          <BOUCLE_breves(BREVES) {id_rubrique} {par date}{inverse} {0,10}>
+          <li class="item">[(#DATE|affdate_jourcourt) &ndash; ]<a href="#URL_BREVE"[ class="(#EXPOSE)"]>#TITRE</a></li>
+          </BOUCLE_breves>
+      </ul>
+  </div>
+  </B_breves>
+
+  [(#REM) Menu de navigation mots-cles ]
+  <B_mots>
+  <div class="liste mots">
+      <h2 class="h2"><:mots_clefs:></h2>
+      <ul class="liste-items">
+      <BOUCLE_mots(MOTS) {id_breve} {par titre}>
+          <li class="item"><a href="#URL_MOT" rel="tag">#TITRE</a></li>
+      </BOUCLE_mots>
+      </ul>
+  </div>
+  </B_mots>
+</BOUCLE_breve_principal>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/extra/dist.html b/www/plugins/zpip_v1/extra/dist.html
new file mode 100644 (file)
index 0000000..0242055
--- /dev/null
@@ -0,0 +1,2 @@
+[(#REM) Inscription au site ]
+#FORMULAIRE_INSCRIPTION
diff --git a/www/plugins/zpip_v1/extra/mot.html b/www/plugins/zpip_v1/extra/mot.html
new file mode 100644 (file)
index 0000000..55327fa
--- /dev/null
@@ -0,0 +1,29 @@
+<BOUCLE_principale(MOTS) {id_mot} {doublons}>
+       [(#REM) Menu de navigation mots-cles : les autres mots cles du meme groupe ]
+  <B_mots_freres>
+  <div class="liste mots">
+      #ANCRE_PAGINATION
+      <h2 class="h2"><:mots_clefs_meme_groupe:></h2>
+      <ul class="liste-items">
+          <BOUCLE_mots_freres(MOTS) {type} {par titre} {pagination 20}>
+          <li class="item"><a href="#URL_MOT"[ class="(#EXPOSE)"]>#TITRE</a></li>
+          </BOUCLE_mots_freres>
+      </ul>
+      [<p class="pagination">(#PAGINATION)</p>]
+  </div>
+  </B_mots_freres>
+
+  [(#REM) Menu de navigation mots-cles : les autres groupes avec un lien sur le premier mot du groupe ]
+  <B_groupes_freres>
+  <div class="liste groupes_mots">
+      <h2 class="h2"><:autres_groupes_mots_clefs:></h2>
+      <ul class="liste-items">
+          <BOUCLE_groupes_freres(GROUPES_MOTS) {!id_groupe} {par titre} {doublons}>
+          <BOUCLE_mot_cousin(MOTS) {id_groupe} {par titre} {0,1}>
+          <li class="item"><a href="#URL_MOT">#TYPE</a></li>
+          </BOUCLE_mot_cousin>
+          </BOUCLE_groupes_freres>
+      </ul>
+  </div>
+  </B_groupes_freres>
+</BOUCLE_principale>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/extra/page-sommaire.html b/www/plugins/zpip_v1/extra/page-sommaire.html
new file mode 100644 (file)
index 0000000..633646c
--- /dev/null
@@ -0,0 +1,27 @@
+[(#REM) Inscription au site ]
+#FORMULAIRE_INSCRIPTION
+
+[(#REM) Liens des forums ]
+<B_forums_liens>
+<div class="liste forums">
+       <h2 class="h2"><:derniers_commentaires:></h2>
+       <ul class="liste-items">
+               <BOUCLE_forums_liens(FORUMS?) {plat} {par date}{inverse} {0,8}>
+               <li class="item">[(#DATE|affdate_jourcourt) &ndash; ]<a href="#URL_FORUM"[ title="(#TITRE|attribut_html|couper{80})"]>[(#TEXTE|couper{80})]</a></li>
+               </BOUCLE_forums_liens>
+       </ul>
+</div>
+</B_forums_liens>
+
+
+[(#REM) Sur le Web ]
+<B_syndic>
+<div class="liste syndic_articles">
+       <h2 class="h2"><:nouveautes_web:></h2>
+       <ul class="liste-items">
+               <BOUCLE_syndic(SYNDIC_ARTICLES) {age<180} {par date}{inverse} {0,6}>
+               <li class="item">[(#DATE|affdate_jourcourt) &ndash; ]<a href="#URL_ARTICLE"[ title="(#NOM_SITE|attribut_html|couper{80})"] class="spip_out">#TITRE</a></li>
+               </BOUCLE_syndic>
+       </ul>
+</div>
+</B_syndic>
diff --git a/www/plugins/zpip_v1/extra/page.html b/www/plugins/zpip_v1/extra/page.html
new file mode 100644 (file)
index 0000000..9b1db02
--- /dev/null
@@ -0,0 +1,6 @@
+[(#REM)
+ Ce squelette n'est necessaire que pour SPIP 2.0
+ A partir de SPIP 2.1, le compilateur trouve directement extra/page-xxx
+
+]#SET{composition,#CHEMIN{extra/page-#ENV{composition}|concat{.html}}|?{page-#ENV{composition},dist}}
+<INCLURE{fond=extra/#GET{composition}}{env}>
diff --git a/www/plugins/zpip_v1/extra/rubrique.html b/www/plugins/zpip_v1/extra/rubrique.html
new file mode 100644 (file)
index 0000000..dce6eed
--- /dev/null
@@ -0,0 +1,13 @@
+<BOUCLE_extra_rubrique(RUBRIQUES){id_rubrique}>
+       [(#REM) Menu de navigation mots-cles ]
+       <B_mots>
+       <div class="liste mots">
+               <h2 class="h2"><:mots_clefs:></h2>
+               <ul class="liste-items">
+                       <BOUCLE_mots(MOTS) {id_rubrique} {par titre}>
+                       <li class="item"><a href="#URL_MOT" rel="tag">#TITRE</a></li>
+                       </BOUCLE_mots>
+               </ul>
+       </div>
+       </B_mots>
+</BOUCLE_extra_rubrique>
diff --git a/www/plugins/zpip_v1/extra/site.html b/www/plugins/zpip_v1/extra/site.html
new file mode 100644 (file)
index 0000000..d045f66
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM) Autres sites web ]
+<B_sites>
+<div class="liste sites">
+    #ANCRE_PAGINATION
+    <h2 class="h2"><:sites_web:></h2>
+    <ul class="liste-items">
+        <BOUCLE_sites(SITES) {par nom_site} {pagination 20}>
+        <li class="item"><a href="[(#ID_SYNDIC|generer_url_entite{site,'','',#CONNECT})]"[ class="(#EXPOSE)"]>#NOM_SITE</a></li>
+        </BOUCLE_sites>
+    </ul>
+    [<p class="pagination">(#PAGINATION)</p>]
+</div>
+</B_sites>
+
+[(#REM) Menu de navigation mots-cles ]
+<B_mots>
+<div class="liste mots">
+    <h2 class="h2"><:mots_clefs:></h2>
+    <ul class="liste-items">
+        <BOUCLE_mots(MOTS) {id_syndic} {par titre}>
+        <li class="item"><a href="#URL_MOT" rel="tag">#TITRE</a></li>
+        </BOUCLE_mots>
+    </ul>
+</div>
+</B_mots>
diff --git a/www/plugins/zpip_v1/extra/z_apl.html b/www/plugins/zpip_v1/extra/z_apl.html
new file mode 100644 (file)
index 0000000..2ba4dc1
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM)
+
+  Squelette Big_Pipe
+       http://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
+
+  (c) 2010 Cedric Morin
+  Distribue sous licence GPL
+
+]#CACHE{0}
+#INCLURE{fond=inclure/ajax_parallel_load,bloc=#SQUELETTE}
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/feed.png b/www/plugins/zpip_v1/feed.png
new file mode 100644 (file)
index 0000000..eb47e19
Binary files /dev/null and b/www/plugins/zpip_v1/feed.png differ
diff --git a/www/plugins/zpip_v1/forum.html b/www/plugins/zpip_v1/forum.html
new file mode 100644 (file)
index 0000000..11ecd8b
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM)
+
+       La page d'accueil est la première page du site.
+       Elle s'affiche lorsque l'on ecrit l'adresse du site
+       dans la barre du navigateur.
+
+       Pour toutes les pages appelées par SPIP
+       (article, rubrique, sommaire, ...),
+       nous choisissons d'inclure la structure de la page
+       avec une balise INCLURE. De cette façon, un seul fichier
+       décrit l'organisation des blocs de la page, le fichier structure.html.
+
+       Nous passons en argument via le critere {env}
+       tout ce qui arrive dans l'environnement de SPIP,
+       comme les variables d'URL (spip.php?page=sommaire&variable=valeur).
+
+       Enfin, nous ajoutons une variable {type=sommaire} pour indiquer de
+       quel type de page il s'agit et afficher alors du contenu en conséquence.
+
+       Allez découvrir ce fameux fichier structure.html.
+       
+]
+<INCLURE{fond=structure}{env}{type=page}{composition=forum} />
+
+
diff --git a/www/plugins/zpip_v1/habillage.css b/www/plugins/zpip_v1/habillage.css
new file mode 100755 (executable)
index 0000000..0ba91d7
--- /dev/null
@@ -0,0 +1,295 @@
+/* ----------------------------------------------------------- */
+/* Feuille de style des squelettes par defaut de Zpip-dist v1  */
+/* ----------------------------------------------------------- */
+
+/* couleurs utilisees
+ *
+ * - #46839B
+ * - #f9f9f9
+ * - #ddd
+ * - #f63
+ */
+
+
+/* ------------------------------------------
+/* Typographie generale (style transversaux)
+/* ------------------------------------------ */
+html { font-size: 100%; } /* Cf.: http://pompage.net/pompe/definir-des-tailles-de-polices-en-CSS/ */
+body { font-size: 0.8125em; font-family: "Luxi sans", "Lucida Grande", Lucida, "Lucida Sans Unicode", sans-serif; color: #333; }
+
+/* Titraille / Intertitres */
+h1,h2,h3,h4,h5,h6,
+.h1,.h2,.h3,.h4,.h5,.h6 { margin: 0; padding: 0; font-weight: normal; font-size: 1em; font-family: Georgia, Times, serif; }
+h1,.h1 { font-size: 1.70em; color: #000; }
+h2,.h2 { font-size: 1.40em; font-weight: normal; }
+h2, h2 a, h2 a:focus, h2 a:hover, h2 a:active { color: #70617E; }
+.h2, .h2 a, .h2 a:focus, .h2 a:hover, .h2 a:active { color: #70617E; }
+h3,.h3 { font-size: 1.20em; font-weight: bold; }
+h3.spip {} /* Cf.: spip_style.css */
+hr.spip {} /* Cf.: spip_style.css */
+
+/* Autres enrichissements typo */
+strong { font-weight: bold; }
+em { font-style: italic; }
+abbr, acronym { border-bottom: 1px dotted; cursor: help; }
+small { font-size: 0.90em; color: #666; }
+dfn { font-weight: bold; color: #666; }
+del { text-decoration: line-through; }
+ins { color: red !important; text-decoration: none; }
+sup, sub { font-size: .8em; font-variant: normal; }
+
+/* Listes */
+ul.spip {} /* Cf.: spip_style.css */
+ol.spip {} /* Cf.: spip_style.css */
+dl {}
+dt {}
+dd {}
+
+/* Citations, code et poesie */
+cite {}
+q {}
+blockquote {}
+blockquote.spip {} /* Cf.: spip_style.css */
+blockquote.spip_poesie {} /* Cf.: spip_style.css */
+/* Cf.: spip_style.css */
+.spip_code {color:#8B2703;}
+.spip_cadre {color:#444; background-color: #fff; border: 1px solid #ddd; font-size:1em; padding:0.5em;width:90%; }
+address {}
+
+/* Tableaux */
+/* Cf.: spip_style.css */
+table.spip { width: 99%; }
+table.spip tr.row_first { background: #46839B; color:white;}
+table.spip td, table.spip th {border:white 2px solid;}
+
+/* Logos, documents et images */
+img { margin: 0; padding: 0; border: 0; }
+.spip_logos {} /* Cf.: spip_style.css */
+.spip_documents {} /* Cf.: spip_style.css */
+.spip_documents_center {} /* Cf.: spip_style.css */
+.spip_documents_left {} /* Cf.: spip_style.css */
+.spip_documents_right {} /* Cf.: spip_style.css */
+.spip_doc_titre {} /* Cf.: spip_style.css */
+.spip_doc_descriptif {} /* Cf.: spip_style.css */
+
+
+/* ------------------------------------------
+/* Disposition a l'ecran des blocs principaux
+/* ------------------------------------------ */
+body { background: #f9f9f9; margin: 0; padding: 0; text-align: center; }
+
+#page { position: relative; background: #fff; width: 58em; margin: 1em auto; padding:1em 2em; text-align: left; border:3px solid #ddd; }
+
+#entete { width: 100%; margin: 0; padding-top: 1.60em; padding-bottom: 1.60em; margin-bottom:1em; border-bottom: 2px solid #46839B;}
+#entete .accueil { display: block; width: 67%; }
+#entete .accueil .spip_logos { vertical-align: bottom; line-height: 1em; }
+#entete .accueil #nom_site_spip { vertical-align: bottom; font-size: 2.2em; font-family: Georgia, Times, serif; font-weight: normal; }
+#entete .formulaire_menu_lang { position: absolute; right: 0; top: 0.90em; display: block; width: 30%; } /*Cf.: spip_formulaires.css*/
+
+#conteneur { clear: both; overflow: hidden; }
+#contenu { padding-top: 0.30em; float:left; width:65%;}
+
+#navigation { float: right; width: 30%; margin-top: 1em; overflow: hidden; }
+
+#pied { clear: both; width: 100%; margin: 1em 0 0 0; padding: 0.60em 0; border: 2px solid #ddd; background:#f9f9f9; text-align: center; font-size: 0.90em; }
+#pied a { /*color:#666;*/ } /* ne pas utiliser de selecteur trop precis, et eviter de toucher aux liens */
+#pied img { vertical-align: middle; }
+
+
+/* ------------------------------------------
+/* Habillage des elements du contenu
+/* ------------------------------------------ */
+
+#hierarchie { clear: both; margin-bottom: 2em; font-size: 0.84em; }
+#hierarchie, #hierarchie a { color: #666; }
+
+.cartouche { margin-bottom: 2em; }
+.cartouche .spip_logos { float: right; margin-left: 16px; margin-bottom: 4px; }
+.cartouche .info-publi { margin: 0; padding: 0; clear: left; }
+
+.chapo { margin-bottom: 1.50em; line-height: 1.40em; font-size:1.1em; }
+.texte { line-height: 1.60em; }
+.ps, .notes { margin-bottom: 2em; line-height: 1.40em; }
+.notes { clear: both; font-size: 0.90em; }
+
+
+/* Portfolio */
+.documents_portfolio { clear: both; margin: 2em auto; text-align: center; }
+.documents_portfolio .spip_logos { margin: 6px 3px 0 3px; border: 4px solid #DDD; }
+.documents_portfolio a.on .spip_logos { border-color: #f63; }
+.documents_portfolio a:focus .spip_logos,
+.documents_portfolio a:hover .spip_logos,
+.documents_portfolio a:active .spip_logos { border-color: #46839B; }
+
+
+/* ------------------------------------------
+/* Sous-navigation et autres menus
+/* ------------------------------------------ */
+
+/* Habillage general des menus de navigation */
+
+.menu { clear: both; margin-bottom: 2em; text-align: left; }
+.menu p { margin: 0.20em 0; padding: 0.20em 0.10em; }
+.menu-liste { margin: 0; padding: 0; list-style: none; border-bottom: 1px solid #ddd; }
+.menu-liste .menu-entree { margin: 0.20em 0; padding: 0.20em;}
+.menu-liste .menu-entree .menu-liste { margin-left: 1em; border: 0; }
+.menu-liste .menu-entree .menu-entree { padding: 0; border: 0; }
+#nav .menu-liste .menu-entree {        display: inline;padding:0;margin:0 0 0 10px; }
+
+#navigation .menu {background:#fcfcfc; padding:0.5em; border: 1px solid #ddd;}
+#navigation .menu a {/*color:#666;*/} /* ne pas utiliser de selecteur trop precis, et eviter de toucher aux liens */
+#navigation .menu-liste {border-bottom:0;}
+#navigation .menu-liste .menu-entree {list-style:square; margin-left:15px; padding:0; color:#f63;}
+#navigation .menu-liste .menu-entree .menu-liste {margin-left:0;}
+#navigation .liste .h2 {margin-top:1em;}
+#navigation .formulaire_recherche{margin-bottom:2em;}
+
+/* Pagination */
+.pagination { clear: both; text-align: right; font-size: 0.90em; color: #666; }
+.pagination .on { font-weight: bold; color: #666; }
+
+/* Rubriques */
+/*
+.rubriques ul { border: 0; }
+.rubriques ul li { background: #EEE; border: 0; }
+*/
+
+
+/* Listes d'articles et extraits introductifs */
+.liste-items {margin: 0; padding: 0; list-style: none; border-bottom:0;}
+.liste-items .item {list-style:square; margin-left:0; padding:2px 0; clear:both; overflow:hidden;}
+#contenu .liste-items .item {margin-bottom:2em;}
+.liste-items .item .h3 { margin: 0.30em 0; border-bottom:1px solid #46839B;}
+.liste-items .item .h3 a:hover { text-decoration:none;}
+.liste-items .item .info-publi {  display:block; float:right; margin-top:0.6em; margin-left:.3em; padding:.3em; background:#ddd;}
+
+.liste.articles .spip_logos { float: right; clear: right; margin: .8em 0 4px 16px; }
+.liste .articles .item .introduction { margin-top: 0.30em; line-height: 1.40em; padding: 0.5em 0 1.5em 1em;}
+
+
+/* Couleurs des liens
+---------------------------------------------- */
+a { color: #3996BB; text-decoration: none; }
+a:focus,a:hover,a:active { color: #46839B; text-decoration: underline; }
+a.spip_out, a.spip_glossaire {
+       color: #46839B;
+       background:transparent url(img/out.gif) no-repeat scroll right center;
+       padding-right:12px;
+}
+
+
+/*  ------------------------------------------
+/*  Habillage des formulaires
+/*  ------------------------------------------ */
+input, select, textarea { font-size: 100%; font-family: inherit; }
+
+
+/* Structure generale des formulaires
+----------------------------------------------- */
+.formulaire_spip { clear: both; margin-bottom: 2em; padding: 0; border: 0; text-align: left; font-size: 1em; }
+.formulaire_spip form { margin: 0; padding: 0; } /* Bug IE/Win */
+
+/* Fieldset */
+.formulaire_spip fieldset { clear: both; margin: 0 0 1em 0; padding: 0; border: 0; }
+.formulaire_spip fieldset legend { margin: 0; padding: 0; font-size: 1.05em; font-weight: bold; background-color: #fff; color: #333; } /* Preciser la couleur des legend et du fond pour IE/Win */
+.formulaire_spip fieldset fieldset { margin-top: 1em; }
+.formulaire_spip fieldset fieldset legend { font-size: 1em; font-weight: normal; }
+
+/* Explications */
+.formulaire_spip .explication { margin: 0.50em 0; color: #444; }
+
+/* Lignes */
+.formulaire_spip ul { margin: 0; padding: 0; list-style: none; }
+.formulaire_spip ul li { clear: both; margin: 0; padding: 0.50em 0; }
+
+/* Labels */
+.formulaire_spip label { display: block; text-align: left; color: #444; font-weight: bold; /* pour IE/Win */ position: relative;  }
+.formulaire_spip li p { margin-top: 0; margin-bottom: 0; }
+
+.formulaire_spip .choix label{display:inline;font-weight:normal;}
+.formulaire_spip .choix input.radio,
+.formulaire_spip .choix input.checkbox {width:auto;}
+
+
+/* Champs de saisie */
+.formulaire_spip input.text { width: 15em; border: 1px inset; }
+.formulaire_spip textarea { width: 99%; border: 1px inset; }
+.formulaire_spip select { width: 99%; }
+
+/* Boutons */
+.formulaire_spip .boutons { clear: both; margin: 0; padding: 0; text-align: right; }
+.formulaire_spip .boutons input { margin-left: 1em; }
+.formulaire_spip .boutons input, input.submit {}
+
+
+/* Reponses, previsu et erreurs
+----------------------------------------------- */
+
+/* Champs obligatoires */
+.formulaire_spip li.obligatoire {}
+.formulaire_spip li.obligatoire label {}
+
+/* Previsualisation du message */
+.formulaire_spip fieldset.previsu { margin-bottom: 2em; padding: 1em; border: 2px dashed #F57900; }
+.formulaire_spip fieldset.previsu legend { padding: 0 0.50em; font-weight: bold; color: #F57900; }
+.formulaire_spip fieldset.previsu li { padding: 3px; border: none; }
+.formulaire_spip fieldset.previsu p { margin: 1em 0; } 
+
+/* Reponse du formulaire */
+.reponse_formulaire { font-weight: bold; color: #e86519; font-size: 1.20em; }
+fieldset.reponse_formulaire { border-color: #e86519; font-weight: normal; }
+fieldset.reponse_formulaire.reponse_formulaire legend { color: #F57900; } /* Preciser la couleur des legend et du fond pour IE/Win */
+
+/* * Erreurs */
+.formulaire_spip li.erreur .erreur_message { display: block; color: #C30; font-weight: bold; }
+.formulaire_spip li.erreur input.text, .formulaire_spip li.erreur textarea { background-color: #FCC; border-style: solid; border-color: #C30; }
+.reponse_formulaire_erreur { margin: 0; color: #C30; font-weight: bold; }
+
+/* * OK */
+.reponse_formulaire_ok { margin: 0; color: #53AD20; font-weight: bold; }
+
+
+/* Variantes et cas particuliers
+----------------------------------------------- */
+
+/* Barre de raccourcis typographiques */
+table.spip_barre { width: 100%; }
+table.spip_barre a img { background: #FDA; padding: 3px; border: 1px outset #CC9; }
+table.spip_barre a:focus img,
+table.spip_barre a:hover img,
+table.spip_barre a:active img { background: #FFF; border: 1px solid #CC9; }
+table.spip_barre input.barre { width: 99%; background: transparent; border: 0; }
+
+/* Formulaire de forum */
+.formulaire_forum .saisie_titre input.text, .formulaire_forum .saisie_titre textarea { width: 98%; }
+.forum {margin:1em 0 0 0; padding:1em; border:#888 1px solid; background:#f6f6f6; list-style-type:none;}
+.forum .forum-fil {margin-bottom:2em;}
+.forum .forum-fil .forum-chapo {background:#666; padding:.5em; color:white;}
+.forum .forum-fil .forum-chapo a {color:white;}
+.forum .ancre {float:left; margin-right:0.5em;}
+.forum .spip_logos {float:right; margin: 0 2px 4px 10px;}
+
+/* Selection des langues */
+.formulaire_menu_lang { padding: 0; background: none; }
+
+/* Formulaires de recherche (site / petitions) */
+.formulaire_recherche { margin: 0; padding: 0; background: none; }
+.formulaire_recherche * { display: inline; vertical-align: middle; }
+.formulaire_recherche label {}
+.formulaire_recherche input.text { width: 10em; }
+.formulaire_recherche input.submit {}
+
+/* Choix des mots-clefs */
+ul.choix_mots { display: block; margin: 0; padding: 0; list-style: none; }
+ul.choix_mots li { clear: none; float: left; display: block; width: 30%; padding: 1%; }
+ul.choix_mots li label { display: inline; font-weight: normal; }
+
+.formulaire_spip .bugajaxie { display: none; } /* Bug IE/Win */
+
+/* Formulaire de login dans une page */
+.formulaire_login ul li {clear:left;}
+.formulaire_login ul li input.password { width: 15em; border: 1px inset; }
+.formulaire_login .editer_password .details {display:block;}
+.formulaire_login #spip_logo_auteur {float:right;}
+
+/* end */
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/head/article.html b/www/plugins/zpip_v1/head/article.html
new file mode 100644 (file)
index 0000000..2d5bb4a
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_article_head(ARTICLES) {id_article}>
+<title>[(#TITRE|textebrut) - ][(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#INTRODUCTION{150}|attribut_html)" />]
+[<link rel="canonical" href="(#URL_ARTICLE|url_absolue)" />]
+</BOUCLE_article_head>
diff --git a/www/plugins/zpip_v1/head/auteur.html b/www/plugins/zpip_v1/head/auteur.html
new file mode 100644 (file)
index 0000000..15c1d4c
--- /dev/null
@@ -0,0 +1,11 @@
+<BOUCLE_auteur_head(AUTEURS) {id_auteur}>
+<title>[(#NOM|textebrut) - ][(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#BIO|couper{150}|attribut_html)" />]
+[<link rel="canonical" href="(#URL_AUTEUR|url_absolue)" />]
+
+[(#REM) Favicon personnalisee a partir du logo (si filtres d'image) ]
+[(#MODELE{favicon}{favicon=#LOGO_AUTEUR})]
+
+[(#REM) Lien vers le flux RSS des articles de l'auteur ]
+<link rel="alternate" type="application/rss+xml" title="[(#NOM|textebrut)]" href="[(#URL_PAGE{backend}|parametre_url{id_auteur,#ID_AUTEUR})]" />
+</BOUCLE_auteur_head>
diff --git a/www/plugins/zpip_v1/head/breve.html b/www/plugins/zpip_v1/head/breve.html
new file mode 100644 (file)
index 0000000..999c3ad
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_breve_principal(BREVES) {id_breve}>
+<title>[(#TITRE|textebrut) - ][(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#INTRODUCTION{150}|attribut_html)" />]
+[<link rel="canonical" href="(#URL_BREVE|url_absolue)" />]
+</BOUCLE_breve_principal>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/head/dist.html b/www/plugins/zpip_v1/head/dist.html
new file mode 100644 (file)
index 0000000..039affe
--- /dev/null
@@ -0,0 +1,26 @@
+[(#REM)
+  Cette inclusion est celle utilisee par defaut lorsqu'un head/xxx demande
+       n'existe pas
+
+       Ces deux balises #NOM_SITE_SPIP et #DESCRIPTIF_SITE_SPIP
+       permettent de récupérer des informations de configuration de SPIP
+       que l'on renseigne dans l'espace privé.
+
+       Ces enregistrements sont stockés en base de donnée dans une
+       table appelée "spip_meta". Les champs de la table peuvent aussi
+       être récupérés en utilisant la balise #CONFIG{nom de la configuration}
+       ce qui donnerait ici : #CONFIG{nom_site_spip}
+
+       Les |mot suivants les #BALISE indique qu'on applique certains traitements
+       au texte retourné par la balise.
+
+       |textebrut supprime toute balise HTML, |couper{150} coupe le texte
+       retourné à 150 caractères. Ces "filtres" peuvent se chaîner
+       |filtreA|filtreB ...
+
+       Ces deux lignes permettent au bout du compte de renseigner le titre
+       de la page affiché tout en haut du navigateur ainsi que la description du site
+       (utile aux moteurs de recherche)
+]
+<title>[(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#DESCRIPTIF_SITE_SPIP|couper{150}|textebrut)" />]
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/head/mot.html b/www/plugins/zpip_v1/head/mot.html
new file mode 100644 (file)
index 0000000..216cdc6
--- /dev/null
@@ -0,0 +1,6 @@
+<BOUCLE_principale(MOTS) {id_mot} >
+<title>[(#TITRE|textebrut) - ][(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#DESCRIPTIF|couper{150}|attribut_html)" />]
+[(#REM) Lien vers le flux RSS des articles du mot cle ]
+<link rel="alternate" type="application/rss+xml"[ title="(#TITRE|attribut_html)"] href="[(#URL_PAGE{backend}|parametre_url{id_mot,#ID_MOT})]" />
+</BOUCLE_principale>
diff --git a/www/plugins/zpip_v1/head/page-404.html b/www/plugins/zpip_v1/head/page-404.html
new file mode 100644 (file)
index 0000000..2536830
--- /dev/null
@@ -0,0 +1,2 @@
+<title><:pass_erreur:> 404 - [(#NOM_SITE_SPIP|textebrut)]</title>
+<meta name="robots" content="none" />
diff --git a/www/plugins/zpip_v1/head/page-plan.html b/www/plugins/zpip_v1/head/page-plan.html
new file mode 100644 (file)
index 0000000..0cfa210
--- /dev/null
@@ -0,0 +1,3 @@
+<title><:plan_site:> - [(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#DESCRIPTIF_SITE_SPIP|couper{150}|attribut_html)" />]
+<meta name="robots" content="none" />
diff --git a/www/plugins/zpip_v1/head/page-recherche.html b/www/plugins/zpip_v1/head/page-recherche.html
new file mode 100644 (file)
index 0000000..ae92aac
--- /dev/null
@@ -0,0 +1,2 @@
+<title><:resultats_recherche:> - [(#NOM_SITE_SPIP|textebrut)]</title>
+<meta name="robots" content="none" />
diff --git a/www/plugins/zpip_v1/head/page-sommaire.html b/www/plugins/zpip_v1/head/page-sommaire.html
new file mode 100644 (file)
index 0000000..d97b5af
--- /dev/null
@@ -0,0 +1,23 @@
+[(#REM)
+       Ces deux balises #NOM_SITE_SPIP et #DESCRIPTIF_SITE_SPIP
+       permettent de récupérer des informations de configuration de SPIP
+       que l'on renseigne dans l'espace privé.
+
+       Ces enregistrements sont stockés en base de donnée dans une
+       table appelée "spip_meta". Les champs de la table peuvent aussi
+       être récupérés en utilisant la balise #CONFIG{nom de la configuration}
+       ce qui donnerait ici : #CONFIG{nom_site_spip}
+
+       Les |mot suivants les #BALISE indique qu'on applique certains traitements
+       au texte retourné par la balise.
+
+       |textebrut supprime toute balise HTML, |couper{150} coupe le texte
+       retourné à 150 caractères. Ces "filtres" peuvent se chaîner
+       |filtreA|filtreB ...
+
+       Ces deux lignes permettent au bout du compte de renseigner le titre
+       de la page affiché tout en haut du navigateur ainsi que la description du site
+       (utile aux moteurs de recherche)
+]
+<title>[(#NOM_SITE_SPIP|typo|textebrut)][ - (#SLOGAN_SITE_SPIP|typo|textebrut)]</title>
+[<meta name="description" content="(#DESCRIPTIF_SITE_SPIP|couper{150}|textebrut)" />]
diff --git a/www/plugins/zpip_v1/head/page.html b/www/plugins/zpip_v1/head/page.html
new file mode 100644 (file)
index 0000000..b394001
--- /dev/null
@@ -0,0 +1,6 @@
+[(#REM)
+ Ce squelette n'est necessaire que pour SPIP 2.0
+ A partir de SPIP 2.1, le compilateur trouve directement head/page-xxx
+
+]#SET{composition,#CHEMIN{head/page-#ENV{composition}|concat{.html}}|?{page-#ENV{composition},dist}}
+<INCLURE{fond=head/#GET{composition}}{env}>
diff --git a/www/plugins/zpip_v1/head/rubrique.html b/www/plugins/zpip_v1/head/rubrique.html
new file mode 100644 (file)
index 0000000..683e1cf
--- /dev/null
@@ -0,0 +1,7 @@
+<BOUCLE_rubrique_head(RUBRIQUES) {id_rubrique}>
+<title>[(#TITRE|textebrut) - ][(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#INTRODUCTION{150}|textebrut)" />]
+[<link rel="canonical" href="(#URL_RUBRIQUE|url_absolue)" />]
+[(#REM) Lien vers le flux RSS de la rubrique ]
+<link rel="alternate" type="application/rss+xml" title="<:syndiquer_rubrique:>" href="[(#URL_PAGE{backend}|parametre_url{id_rubrique,#ID_RUBRIQUE})]" />
+</BOUCLE_rubrique_head>
diff --git a/www/plugins/zpip_v1/head/site.html b/www/plugins/zpip_v1/head/site.html
new file mode 100644 (file)
index 0000000..6619884
--- /dev/null
@@ -0,0 +1,5 @@
+<BOUCLE_site(SITES){id_syndic}>
+<title>[(#NOM_SITE|textebrut) - ][(#NOM_SITE_SPIP|textebrut)]</title>
+[<meta name="description" content="(#DESCRIPTIF|couper{150}|textebrut)" />]
+<meta name="robots" content="none" />
+</BOUCLE_site>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/img/out.gif b/www/plugins/zpip_v1/img/out.gif
new file mode 100644 (file)
index 0000000..d93105c
Binary files /dev/null and b/www/plugins/zpip_v1/img/out.gif differ
diff --git a/www/plugins/zpip_v1/img/zpip-128.png b/www/plugins/zpip_v1/img/zpip-128.png
new file mode 100644 (file)
index 0000000..b9d42d0
Binary files /dev/null and b/www/plugins/zpip_v1/img/zpip-128.png differ
diff --git a/www/plugins/zpip_v1/img/zpip-16.png b/www/plugins/zpip_v1/img/zpip-16.png
new file mode 100644 (file)
index 0000000..55cb907
Binary files /dev/null and b/www/plugins/zpip_v1/img/zpip-16.png differ
diff --git a/www/plugins/zpip_v1/img/zpip-32.png b/www/plugins/zpip_v1/img/zpip-32.png
new file mode 100644 (file)
index 0000000..609d81b
Binary files /dev/null and b/www/plugins/zpip_v1/img/zpip-32.png differ
diff --git a/www/plugins/zpip_v1/img/zpip-48.png b/www/plugins/zpip_v1/img/zpip-48.png
new file mode 100644 (file)
index 0000000..b86dbd1
Binary files /dev/null and b/www/plugins/zpip_v1/img/zpip-48.png differ
diff --git a/www/plugins/zpip_v1/img/zpip-64.png b/www/plugins/zpip_v1/img/zpip-64.png
new file mode 100644 (file)
index 0000000..0f5c6ef
Binary files /dev/null and b/www/plugins/zpip_v1/img/zpip-64.png differ
diff --git a/www/plugins/zpip_v1/inclure/ajax_parallel_load.html b/www/plugins/zpip_v1/inclure/ajax_parallel_load.html
new file mode 100644 (file)
index 0000000..46588aa
--- /dev/null
@@ -0,0 +1,27 @@
+[(#REM)
+
+  Squelette Big_Pipe
+       http://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
+
+  (c) 2010 Cedric Morin
+  Distribue sous licence GPL
+
+]
+#SET{bloc,#ENV{bloc}|dirname|basename}
+<div id="zapl-#GET{bloc}" class="zapl-loading"><:zpip:zapl_loading:></div>
+<script type="text/javascript">
+       var myurl = window.location + "";
+       myurl = myurl.split('#');
+       myurl = myurl[0] + ((myurl[0].indexOf("?")>0)?"&":"?") + "var_zajax=#GET{bloc}";
+       $.get(myurl, function(data) {
+               jQuery('document').ready(function(){
+                       jQuery("#zapl-#GET{bloc}").replaceWith(data);
+                       var h = window.location.hash;
+                       if (h && jQuery("<div></div>").html(data).find(h).length>0) jQuery(h).positionner(true);
+               });
+       });
+</script>
+<noscript>
+       <meta http-equiv="refresh" content="2;url=<?php echo ($url=parametre_url(self(),'var_zapl','non'));?>" />
+       <a href="<?php echo $url ?>"><:zpip:zapl_reload_off:></a>
+</noscript>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/inclure/article-resume.html b/www/plugins/zpip_v1/inclure/article-resume.html
new file mode 100644 (file)
index 0000000..db010c8
--- /dev/null
@@ -0,0 +1,22 @@
+[(#REM)\r
+\r
+  Squelette Presentation d'un article dans une liste\r
+  (c) 2009 Zpip\r
+  Distribue sous licence GPL\r
+\r
+]\r
+<BOUCLE_articles(ARTICLES) {id_article} {statut?}>\r
+<li class="item hentry">\r
+       <h3 class="h3 entry-title"><a href="#URL_ARTICLE" rel="bookmark">[(#LOGO_ARTICLE_RUBRIQUE||image_reduire{150,100})]#TITRE</a></h3>\r
+       <div class="info-publi">[<abbr class="published" title="[(#DATE|date_iso)]">(#DATE|affdate_jourcourt)</abbr>][<span class="sep">, </span><span class="auteurs"><:par_auteur:> (#LESAUTEURS)</span>]</div>\r
+       [<div class="#EDIT{intro} introduction entry-content">(#INTRODUCTION)</div>]\r
+       <div class="meta-publi">\r
+       <a class="lire-la-suite" href="#URL_ARTICLE"><:zpip:lire_la_suite:><span class="lire-la-suite-titre"><:zpip:lire_la_suite_de:> <em>#TITRE</em></span></a>\r
+       <BOUCLE_nb_commentaires(FORUMS) {id_article}{plat} />   [(#TOTAL_BOUCLE|oui)\r
+               <span class="sep">|</span>\r
+               <a[ href="(#URL_ARTICLE|ancre_url{forum})"] class="nb_commentaires">[(#TOTAL_BOUCLE)]&nbsp;[(#TOTAL_BOUCLE|=={1}|?{<:zpip:commentaire:>,<:zpip:commentaires:>})]</a>\r
+               ]\r
+       <//B_nb_commentaires>\r
+       </div>\r
+</li>\r
+</BOUCLE_articles>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/inclure/barre-nav-secteurs.html b/www/plugins/zpip_v1/inclure/barre-nav-secteurs.html
new file mode 100644 (file)
index 0000000..ceed968
--- /dev/null
@@ -0,0 +1,11 @@
+<B_rubriques>
+  <div class="menu-conteneur">
+        <ul class="menu-liste">
+        <BOUCLE_rubriques(RUBRIQUES) {racine} {par num titre, titre}>
+               <li class="menu-entree[ (#EXPOSE)]">
+                       <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a>
+               </li>
+        </BOUCLE_rubriques>
+        </ul>
+  </div>
+</B_rubriques>
diff --git a/www/plugins/zpip_v1/inclure/barre-nav.html b/www/plugins/zpip_v1/inclure/barre-nav.html
new file mode 100644 (file)
index 0000000..66fdeb5
--- /dev/null
@@ -0,0 +1,4 @@
+[(#SESSION{statut}|=={0minirezo}|oui)
+<ul class="menu-liste">
+       <li class="menu-entree"><a href="http://www.spip-contrib.net/?article3344" target="_blank"><:zpip:personaliser_nav:></a></li>
+</ul>]
diff --git a/www/plugins/zpip_v1/inclure/documents.html b/www/plugins/zpip_v1/inclure/documents.html
new file mode 100644 (file)
index 0000000..1a37f92
--- /dev/null
@@ -0,0 +1,34 @@
+[(#REM) Portfolio : album d'images ]
+<B_documents_portfolio>
+<div class="documents documents_portfolio">
+       <h2 class="h2"><:info_portfolio:></h2>
+       <BOUCLE_documents_portfolio(DOCUMENTS) {id_article?}{id_rubrique?} {mode=document}{extension IN png,jpg,gif} {par num titre, date}{vu=non}>[
+       <a href="(#URL_DOCUMENT)"
+                type="#MIME_TYPE"
+                rel="documents_portfolio[-a(#ID_ARTICLE)][-r(#ID_RUBRIQUE)]"
+       [ title="(#TITRE|attribut_html|couper{80})"]>[(#FICHIER
+               |image_reduire{0,100}
+               |inserer_attribut{class,spip_logos}
+               |inserer_attribut{alt,[(#TITRE|attribut_html|couper{80})]})]</a>
+       ]</BOUCLE_documents_portfolio>
+</div>
+</B_documents_portfolio>
+
+
+[(#REM)
+       Liste des autres documents joints
+]
+<B_documents_joints>
+       <div class="liste documents documents_joints">
+       <h2 class="h2"><:titre_documents_joints:></h2>
+       <ul class="liste-items">
+               <BOUCLE_documents_joints(DOCUMENTS) {id_article?}{id_rubrique?} {extension !IN gif,jpg,png} {vu=non}{par num titre, date}>[
+               <li class="item">
+                       <strong><a href="(#URL_DOCUMENT)" title="<:bouton_telecharger:>" type="#MIME_TYPE">[(#TITRE|sinon{<:info_document:>})]</a></strong>
+                       <span class="small">(<span>#TYPE_DOCUMENT[ &ndash; (#TAILLE|taille_en_octets)]</span>)</span>
+                       #DESCRIPTIF
+               ]</li>
+               </BOUCLE_documents_joints>
+       </ul>
+       </div>
+</B_documents_joints>
diff --git a/www/plugins/zpip_v1/inclure/entete.html b/www/plugins/zpip_v1/inclure/entete.html
new file mode 100644 (file)
index 0000000..6d9125b
--- /dev/null
@@ -0,0 +1,7 @@
+<div class="accueil">
+       [<a rel="start home" href="#URL_SITE_SPIP/" title="<:accueil_site:>">(#LOGO_SITE_SPIP||image_reduire{300,100})</a>]
+       <strong id="nom_site_spip"><a rel="start home" href="#URL_SITE_SPIP/" title="<:accueil_site:>">#NOM_SITE_SPIP</a></strong>
+       [<div id='slogan_site_spip'>(#SLOGAN_SITE_SPIP|PtoBR)</div>]
+</div>
+#MENU_LANG
+
diff --git a/www/plugins/zpip_v1/inclure/forum.html b/www/plugins/zpip_v1/inclure/forum.html
new file mode 100644 (file)
index 0000000..6ededd1
--- /dev/null
@@ -0,0 +1,88 @@
+[(#REM) Cette balise (invisible) provoque le recalcul du forum
+la premiere fois qu'un message est poste (cf. inc/invalideur). ]
+[(#PARAMETRES_FORUM|?{''})]
+
+<div class="comments" id="comments">
+       [(#REM) Nombre total de messages ]
+       <BOUCLE_decompte(FORUMS) {id_rubrique ?}{id_article ?}{id_breve ?}{id_syndic ?} {plat} />[<h2 class="h2">(#TOTAL_BOUCLE|>{0}|?{#TOTAL_BOUCLE,''})
+       [(#TOTAL_BOUCLE|=={1}|?{<:message:>,<:messages_forum:>})]</h2>]<//B_decompte>
+
+       [(#REM) Messages du forum ]
+       <B_forums>
+       <ul class="forum comments-list">
+
+               <BOUCLE_forums(FORUMS) {id_rubrique ?}{id_article ?}{id_breve ?}{id_syndic ?} {par date}>
+
+               <li class="forum-fil comment[ (#COMPTEUR_BOUCLE|alterner{'odd','even'})][ (#COMPTEUR_BOUCLE|=={1}|oui)first][ (#EXPOSE)]">
+                       <div class="comment-message forum-message">
+                               <div class="comment-meta forum-chapo">
+                                       <a href="#forum#ID_FORUM" title="#ID_FORUM" class="ancre permalink comment-number">#</a>
+                                       <strong class="#EDIT{titre} forum-titre"><a href="#forum#ID_FORUM" name="forum#ID_FORUM" id="forum#ID_FORUM">#TITRE</a></strong>
+                                       [(#DATE|oui)<abbr class="date"[ title="(#DATE|date_iso)"]>
+                                               [(#SET{date,[(#DATE|affdate_jourcourt)]})]
+                                               [(#SET{heure,[(#DATE|heures)][:(#DATE|minutes)]})]
+                                               <:zpip:date_forum{date=#GET{date},heure=#GET{heure}}:></abbr>][<span class="comment-author vcard">, <:par_auteur:> <strong class="fn n #EDIT{qui}">(#NOM)</strong></span>]
+                               </div>
+                               <div class="comment-content forum-texte">
+                                       #LOGO_AUTEUR
+                                       [<div class="#EDIT{texte} comment-texte">(#TEXTE|lignes_longues)</div>]
+                                       [<div class="comment-notes">(#NOTES|safehtml|lignes_longues)</div>]
+                                       [<p class="#EDIT{hyperlien} comment-external-link hyperlien"><:voir_en_ligne:> : <a href="(#URL_SITE)" class="spip_out">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+                                       <BOUCLE_doc(DOCUMENTS){id_forum}>
+                                       [(#EXTENSION|match{'^(gif|jpg|png)$'}|?{
+                                               [(#EMBED_DOCUMENT|image_reduire{300})]
+                                       ,
+                                               [(#LOGO_DOCUMENT|#URL_DOCUMENT)]
+                                       })]
+                                       </BOUCLE_doc>
+
+                                       [<p class="comment-reply repondre"><a href="(#PARAMETRES_FORUM|url_reponse_forum)" rel="noindex nofollow"><:lien_repondre_message:></a></p>]
+                               </div>
+                       </div>
+
+                       <B_forums_fils>
+                       <ul>
+                               <BOUCLE_forums_fils(FORUMS) {id_parent} {par date}>
+
+                               <li class="forum-fil comment[ (#COMPTEUR_BOUCLE|alterner{'odd','even'})][ (#COMPTEUR_BOUCLE|=={1}|oui)first][ (#EXPOSE)]">
+                                       <div class="comment-message forum-message">
+                                               <div class="comment-meta forum-chapo">
+                                                       <a href="#forum#ID_FORUM" title="#ID_FORUM" class="ancre permalink comment-number">#</a>
+                                                       <strong class="#EDIT{titre} forum-titre"><a href="#forum#ID_FORUM" name="forum#ID_FORUM" id="forum#ID_FORUM">#TITRE</a></strong>
+                                                       [(#DATE|oui)<abbr class="date"[ title="(#DATE|date_iso)"]>
+                                                               [(#SET{date,[(#DATE|affdate_jourcourt)]})]
+                                                               [(#SET{heure,[(#DATE|heures)][:(#DATE|minutes)]})]
+                                                               <:zpip:date_forum{date=#GET{date},heure=#GET{heure}}:></abbr>][<span class="comment-author vcard">, <:par_auteur:> <strong class="fn n #EDIT{qui}">(#NOM)</strong></span>]
+                                               </div>
+                                               <div class="comment-content forum-texte">
+                                                       #LOGO_AUTEUR
+                                                       [<div class="#EDIT{texte} comment-texte">(#TEXTE|lignes_longues)</div>]
+                                                       [<div class="comment-notes">(#NOTES|safehtml|lignes_longues)</div>]
+                                                       [<p class="#EDIT{hyperlien} comment-external-link hyperlien"><:voir_en_ligne:> : <a href="(#URL_SITE)" class="spip_out">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+
+                                                       <BOUCLE_doc2(DOCUMENTS){id_forum}>
+                                                       [(#EXTENSION|match{'^(gif|jpg|png)$'}|?{
+                                                               [(#EMBED_DOCUMENT|image_reduire{300})]
+                                                       ,
+                                                               [(#LOGO_DOCUMENT|#URL_DOCUMENT)]
+                                                       })]
+                                                       </BOUCLE_doc2>
+
+                                                       [<p class="comment-reply repondre"><a href="(#PARAMETRES_FORUM|url_reponse_forum)" rel="noindex nofollow"><:lien_repondre_message:></a></p>]
+                                               </div>
+                                       </div>
+
+                                       <BOUCLE_forums_boucle(boucle_forums_fils)></BOUCLE_forums_boucle>
+
+                               </li>
+
+                               </BOUCLE_forums_fils>
+                       </ul>
+                       </B_forums_fils>
+
+               </li>
+               </BOUCLE_forums>
+
+       </ul>
+       </B_forums>
+</div>
diff --git a/www/plugins/zpip_v1/inclure/head.html b/www/plugins/zpip_v1/inclure/head.html
new file mode 100644 (file)
index 0000000..62331c9
--- /dev/null
@@ -0,0 +1,43 @@
+[(#REM)\r
+       Head standard de toutes les pages ; les elements specifiques\r
+       (title, description) figurent dans les fichiers du dossier head/\r
+]\r
+[(#REM) Preciser le charset ]\r
+<meta http-equiv="Content-Type" content="text/html; charset=#CHARSET" />\r
+\r
+[(#REM) Fierement fabrique avec SPIP ]\r
+<meta name="generator" content="SPIP[ (#SPIP_VERSION)]" />\r
+\r
+[(#REM) Lien vers le flux RSS du site ]\r
+[<link rel="alternate" type="application/rss+xml" title="<:syndiquer_site:>" href="(#URL_PAGE{backend})" />]\r
+\r
+[(#REM) Feuille de style par defaut pour le code genere par SPIP ]\r
+[<link rel="stylesheet" href="(#CHEMIN{spip_style.css}|direction_css)" type="text/css" media="all" />]\r
+\r
+[(#REM) Feuille de style par defaut pour les formulaires de SPIP ]\r
+[<link rel="stylesheet" href="(#CHEMIN{spip_formulaires.css}|direction_css)" type="text/css" media="projection, screen, tv" />]\r
+\r
+[(#REM) Balise permettant aux plugins d'inserer des fichiers CSS ]\r
+#INSERT_HEAD_CSS\r
+\r
+[(#REM) Feuille de style CSS pour l'affichage du site a l'ecran ]\r
+[<link rel="stylesheet" href="(#CHEMIN{habillage.css}|direction_css)" type="text/css" media="projection, screen, tv" />]\r
+\r
+[(#REM) Feuille de style CSS pour l'impression ]\r
+[<link rel="stylesheet" href="(#CHEMIN{impression.css}|direction_css)" type="text/css" media="print" />]\r
+\r
+[(#CHEMIN{inc-theme-head.html}|oui)\r
+#INCLURE{fond=inc-theme-head,env}\r
+]\r
+\r
+[(#REM) Feuille de style personnalisee pour surcharger les precedentes\r
+       A noter par defaut cette css n'existe pas\r
+]\r
+[<link rel="stylesheet" href="(#CHEMIN{perso.css}|direction_css)" type="text/css" media="projection, screen, tv" />]\r
+\r
+[(#REM) Balise permettant aux plugins d'inserer des appels javascript ou css ;\r
+       C'est ici que SPIP va inserer l'appel de la librairie jQuery\r
+       Et appeler a la fin compacte_head pour agreger et compacter tout le head dans des fichiers statiques\r
+       si l'option est cochee dans Configuration\r
+]\r
+#INSERT_HEAD\r
diff --git a/www/plugins/zpip_v1/inclure/petition.html b/www/plugins/zpip_v1/inclure/petition.html
new file mode 100644 (file)
index 0000000..c689785
--- /dev/null
@@ -0,0 +1,45 @@
+[(#REM) Signer la petition ]
+#FORMULAIRE_SIGNATURE
+
+[(#REM) Signatures de la petition ]
+<B_signatures>
+<div id="signatures">
+       [<p class="pagination">(#PAGINATION)</p>]
+       <table class="spip">
+       <caption><h2 class="h2">#GRAND_TOTAL <:signatures_petition:></h2></caption>
+               <thead>
+                       <tr class="row_first">
+                               <th class="signature-date"><a href='[(#SELF|parametre_url{tri,date_time}|parametre_url{tri_inverse,''})]#signatures' title="<:lien_trier_date:>"><:date:></a></th>
+                               <th class="signature-nom"><a href='[(#SELF|parametre_url{tri,nom_email}|parametre_url{tri_inverse,''})]#signatures' title="<:lien_trier_nom:>"><:nom:></a></th>
+                               [(#REM) Afficher la colonne des messages si autorises ]
+                               <BOUCLE_signature-message-th(PETITIONS){id_article}{message=oui}>
+                               <th class="signature-message"><:message:></th>
+                               </BOUCLE_signature-message-th>
+                       </tr>
+               </thead>
+               <tbody>
+               <BOUCLE_signatures(SIGNATURES) {id_article} {pagination #ENV{pagination, 15} } {recherche ?#ENV{recherche_signatures}} {!par #ENV{tri}}{par #ENV{tri_inverse}} {!par #ENV{tri,#ENV{tri_inverse}}|?{'',date_time}}>
+               <tr [class="(#COMPTEUR_BOUCLE|alterner{row_even,row_odd})" ]id='id_signature#ID_SIGNATURE'>
+                       <td class="signature-date">[(#DATE|affdate_jourcourt)]</td>
+                       <td class="signature-nom"><strong class="#EDIT{qui}">#NOM</strong>[ <div class="small #EDIT{hyperlien}"><a href="(#URL_SITE)"[ title="(#NOM_SITE|attribut_html|couper{80})"] class="spip_out"><:site_web:></a></div>]</td>
+                       [(#REM) Afficher la colonne des messages si autorises ]
+                       <BOUCLE_signature-message-td(PETITIONS){id_article}{message=oui}> </BOUCLE_signature-message-td>
+                       <td class="signature-message #EDIT{message}">[(#MESSAGE|PtoBR)]</td>
+                       </B_signature-message-td>
+               </tr>
+               </BOUCLE_signatures>
+       </tbody>
+       </table>
+       [<p class="pagination">(#PAGINATION)</p>]
+
+       [(#REM) Afficher un moteur de recherche si plus de 30 signatures
+       ou s'il etait deja present au coup d'avant]
+       [(#ENV{recherche_signatures}|?{31,#_signatures:GRAND_TOTAL}|>{3}|oui)
+       <div class="formulaire_spip formulaire_recherche" id="formulaire_recherche_signatures">
+               <form method='get' action='#SELF'><div>[(#SELF|form_hidden)]
+               <label for="recherche_signatures"><:info_rechercher:></label> <input type="text" class="text" size="10" name="recherche_signatures" id="recherche_signatures" style='font-style: italic;' value=" <:entree_signature:>"/> <input type="submit" class="submit" value="<:info_rechercher:>" />
+               </div></form>
+       </div>
+       ]
+</div><!--#signatures-->
+</B_signatures>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/inclure/pied.html b/www/plugins/zpip_v1/inclure/pied.html
new file mode 100644 (file)
index 0000000..e35f0d1
--- /dev/null
@@ -0,0 +1,10 @@
+
+<a href="http://www.spip.net/" title="<:site_realise_avec_spip:>"><img src="#CHEMIN{spip.png}" alt="SPIP" width="48" height="16" /></a>
+<?php if (isset($GLOBALS['visiteur_session']['id_auteur']) AND $GLOBALS['visiteur_session']['id_auteur']) { ?>
+| <a href="#URL_LOGOUT" rel="nofollow"><:icone_deconnecter:></a>
+       <?php if (include_spip('inc/autoriser') AND autoriser('ecrire')){ ?>| <a href="#EVAL{_DIR_RESTREINT_ABS}"><:espace_prive:></a><?php } ?>
+<?php } else { ?>
+| <a href="[(#URL_PAGE{login}|parametre_url{url,#SELF|parametre_url{url,''}})]" rel="nofollow" class='login_modal'><:lien_connecter:></a>
+<?php } ?>
+| <a rel="contents" href="#URL_PAGE{plan}"><:plan_site:></a> |
+<a href="#URL_PAGE{backend}" rel="alternate" title="<:syndiquer_site:>"><img src="#CHEMIN{feed.png}" alt="<:icone_suivi_activite:>" width="16" height="16" />&nbsp;RSS&nbsp;2.0</a>
diff --git a/www/plugins/zpip_v1/inclure/rss-item.html b/www/plugins/zpip_v1/inclure/rss-item.html
new file mode 100644 (file)
index 0000000..c6e1020
--- /dev/null
@@ -0,0 +1,58 @@
+[(#REM)
+       Cette page génère le contenu d'un article
+       pour un flux RSS, appelé depuis backend.html
+
+]<BOUCLE_un_article(ARTICLES){id_article} {statut?}>
+       <item[ xml:lang="(#LANG)"]>
+               <title>[(#TITRE|supprimer_tags|texte_backend)]</title>
+               <link>[(#URL_ARTICLE|url_absolue)]</link>
+               [<guid isPermaLink="true">(#URL_ARTICLE|url_absolue)</guid>]
+               [<dc:date>(#DATE|date_iso)</dc:date>]
+               <dc:format>text/html</dc:format>
+               [<dc:language>(#LANG)</dc:language>]
+               [<dc:creator>(#LESAUTEURS|supprimer_tags|texte_backend)</dc:creator>]
+
+[(#REM)
+       Le bloc qui suit diffuse les mots-cles a la mode RSS
+
+]<BOUCLE_mots_rss(MOTS){id_article}>
+               [<dc:subject>(#TITRE|texte_backend)</dc:subject>]</BOUCLE_mots_rss>
+
+               <description>[(#INTRODUCTION|texte_backend)]
+
+[(#REM)
+       Le bloc qui suit diffuse la rubrique et les mots-cles
+       sous forme de "microformats"
+
+]<BOUCLE_rubrique_mf(RUBRIQUES){id_rubrique}{statut?}>-
+[&lt;a href="[(#URL_RUBRIQUE|url_absolue)]" rel="directory"&gt;(#TITRE|supprimer_tags|texte_backend)&lt;/a&gt;]
+</BOUCLE_rubrique_mf><B_mots_mf>
+/ <BOUCLE_mots_mf(MOTS){id_article}{", "}>
+[&lt;a href="[(#URL_MOT|url_absolue)]" rel="tag"&gt;(#TITRE|texte_backend)&lt;/a&gt;]</BOUCLE_mots_mf>
+
+               </description>
+
+[(#REM)
+       Le bloc qui suit diffuse aussi le texte integral de l'article,
+       ce qui permet une syndication plus riche (mais plus "lourde").
+       Fonction desactivable depuis les reglages du site.
+][
+(#CONFIG{syndication_integrale}|=={oui}|?{' ',''})<content:encoded>[(#LOGO_ARTICLE{right}||image_reduire{150,150}|texte_backend)
+               ][&lt;div class='rss_chapo'&gt;(#CHAPO|texte_backend)&lt;/div&gt;
+               ][&lt;div class='rss_texte'&gt;(#TEXTE|
+                       image_reduire{500,0}|texte_backend)&lt;/div&gt;
+               ][&lt;hr /&gt;
+               &lt;div class='rss_notes'&gt;(#NOTES|texte_backend)&lt;/div&gt;
+               ][&lt;div class='rss_ps'&gt;(#PS|texte_backend)&lt;/div&gt;]
+               </content:encoded>
+]
+
+[(#REM)
+       Le bloc qui suit diffuse l'adresse des documents associes aux articles ;
+       ajouter par ex. {extension=mp3} pour limiter a un certain type de document.
+]              <BOUCLE_documents(DOCUMENTS){id_article}{mode=document}{doublons}>[
+               <enclosure url="(#URL_DOCUMENT|url_absolue|unique)"[ length="(#TAILLE)"][ type="(#MIME_TYPE)"] />]
+               </BOUCLE_documents>
+
+       </item>
+</BOUCLE_un_article>
diff --git a/www/plugins/zpip_v1/inclure/rubriques.html b/www/plugins/zpip_v1/inclure/rubriques.html
new file mode 100644 (file)
index 0000000..20eb3c3
--- /dev/null
@@ -0,0 +1,27 @@
+[(#REM)
+       Barre de navigation, ouverte sur la hierarchie courante
+
+       On fait un plan, et, quand on avance vers une rubrique,
+       on l'affiche si son parent est expose ou est la racine du site. ]
+<B_rubriques>
+<div class="menu rubriques">
+       <h2 class="h2"><:rubriques:></h2>
+       <ul class="menu-liste">
+       <BOUCLE_rubriques(RUBRIQUES) {racine} {par num titre, titre}>
+               <li class="menu-entree">
+                       <a href="#URL_RUBRIQUE"[ class="(#EXPOSE)"]>[(#TITRE|couper{80})]</a>
+
+                       <B_sous_rubriques>
+                       <ul class="menu-liste">
+                               <BOUCLE_sous_rubriques(RUBRIQUES) {id_parent} {par num titre, titre}><BOUCLE_test_expose(RUBRIQUES) {id_enfant}>#EXPOSE{' '}</BOUCLE_test_expose>
+                                       <li class="menu-entree"><a href="#URL_RUBRIQUE"[ class="(#EXPOSE)"]>[(#TITRE|couper{80})]</a><BOUCLE_re(BOUCLE_sous_rubriques)></BOUCLE_re>     </li>
+                               </B_test_expose></BOUCLE_sous_rubriques>
+                       </ul>
+                       </B_sous_rubriques>
+
+               </li>
+       </BOUCLE_rubriques>
+
+       </ul>
+</div>
+</B_rubriques>
diff --git a/www/plugins/zpip_v1/lang/zpip_de.php b/www/plugins/zpip_v1/lang/zpip_de.php
new file mode 100644 (file)
index 0000000..8af2eb9
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/_stable_/acces_restreint/lang/
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'adapte_de' => 'auf Grundlage von',
+       // B
+
+       // C
+       'conception_graphique_par' => 'Design von (c)',
+       'commentaire' => 'Kommentar',
+       'commentaires' => 'Kommentare',
+
+       // D
+
+       // I
+
+       // L
+       'lire_la_suite' => 'Ganzer Text',
+       'lire_la_suite_de' => ' von ',
+
+       // M
+
+       // P
+       'personaliser_nav' => 'Men&uuml; anpassen',
+
+       // R
+
+       // S
+       'sous_licence' => 'Lizenz: ',
+
+       // T
+
+       // V
+
+       // Z
+);
+
+?>
diff --git a/www/plugins/zpip_v1/lang/zpip_en.php b/www/plugins/zpip_v1/lang/zpip_en.php
new file mode 100644 (file)
index 0000000..e0f5934
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/_stable_/acces_restreint/lang/
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'adapte_de' => 'adapted from',
+
+       // B
+
+       // C
+       'conception_graphique_par' => 'Graphic design (c)',
+       'commentaire' => 'comment',
+       'commentaires' => 'comments',
+
+       // D
+       'date_forum' => '@date@ at @heure@',
+
+       // I
+
+       // L
+       'lire_la_suite' => 'Read more',
+       'lire_la_suite_de' => ' of ',
+
+       // M
+
+       // P
+       'personaliser_nav' => 'Customize this menu',
+
+       // R
+
+       // S
+       'sous_licence' => 'under License',
+
+       // T
+
+       // V
+
+       // Z
+       'zapl_loading' => 'Loading...',
+       'zapl_reload_off' => 'Click here if this page remains empty (or activate javascript in your browser)',
+);
+
+?>
diff --git a/www/plugins/zpip_v1/lang/zpip_es.php b/www/plugins/zpip_v1/lang/zpip_es.php
new file mode 100644 (file)
index 0000000..5b2ec13
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+
+       // B
+
+       // C
+       'conception_graphique_par' => 'Dise&ntilde;o gr&aacute;fico (c)',
+       'commentaire' => 'comentario',
+       'commentaires' => 'comentarios',
+
+       // D
+
+       // I
+
+       // L
+       'lire_la_suite' => 'Seguir leyendo',
+       'lire_la_suite_de' => '',
+
+       // M
+
+       // P
+
+       // R
+
+       // S
+       'sous_licence' => 'bajo Licencia',
+
+       // T
+
+       // V
+
+       // Z
+);
+
+?>
diff --git a/www/plugins/zpip_v1/lang/zpip_fr.php b/www/plugins/zpip_v1/lang/zpip_fr.php
new file mode 100644 (file)
index 0000000..c04da08
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/_stable_/acces_restreint/lang/
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+       'adapte_de' => 'adapt&eacute; de',
+       // B
+
+       // C
+       'conception_graphique_par' => 'Habillage visuel &copy;',
+       'commentaire' => 'commentaire',
+       'commentaires' => 'commentaires',
+
+       // D
+       'date_forum' => 'Le @date@ &agrave; @heure@',
+
+       // I
+
+       // L
+       'lire_la_suite' => 'Lire la suite',
+       'lire_la_suite_de' => ' de ',
+
+       // M
+
+       // P
+       'personaliser_nav' => 'Personnaliser ce menu',
+
+       // R
+
+       // S
+       'sous_licence' => 'sous Licence',
+
+       // T
+
+       // V
+
+       // Z
+       'zapl_loading' => 'Chargement en cours...',
+       'zapl_reload_off' => 'Cliquer ici si la page reste incompl&egrave;te (ou activer le javascript dans votre navigateur)',
+);
+
+?>
diff --git a/www/plugins/zpip_v1/lang/zpip_nl.php b/www/plugins/zpip_v1/lang/zpip_nl.php
new file mode 100644 (file)
index 0000000..8b84871
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/_stable_/acces_restreint/lang/
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+       // A
+
+       // B
+
+       // C
+       'conception_graphique_par' => 'Ontwerp (c)',
+       'commentaire' => 'reactie',
+       'commentaires' => 'reacties ',
+
+       // D
+
+       // I
+
+       // L
+       'lire_la_suite' => 'Lees meer',
+       'lire_la_suite_de' => ' over ',
+
+       // M
+
+       // P
+       'personaliser_nav' => 'Personaliseer dit menu',
+
+       // R
+
+       // S
+       'sous_licence' => 'onder licensie',
+
+       // T
+
+       // V
+
+       // Z
+);
+
+?>
diff --git a/www/plugins/zpip_v1/lang/zpip_pt.php b/www/plugins/zpip_v1/lang/zpip_pt.php
new file mode 100644 (file)
index 0000000..36f18c4
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/_stable_/acces_restreint/lang/
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+
+       // B
+
+       // C
+
+// C
+       'conception_graphique_par' => 'Design (c)',
+       'commentaire' => 'coment&aacute;rio',
+       'commentaires' => 'coment&aacute;rios',
+
+       // D
+
+       // I
+
+       // L
+       'lire_la_suite' => 'l&ecirc; mais',
+       'lire_la_suite_de' => ' sobre ',
+
+       // M
+
+       // P
+       'personaliser_nav' => 'personalisar este menu',
+
+       // R
+
+       // S
+       'sous_licence' => 'sob licença',
+
+       // T
+
+       // V
+
+       // Z
+);
+
+?>
diff --git a/www/plugins/zpip_v1/lang/zpip_sv.php b/www/plugins/zpip_v1/lang/zpip_sv.php
new file mode 100644 (file)
index 0000000..908188a
--- /dev/null
@@ -0,0 +1,43 @@
+<?php
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+// Fichier source, a modifier dans svn://zone.spip.org/spip-zone/_plugins_/_stable_/acces_restreint/lang/
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+
+       // A
+
+       // B
+
+       // C
+
+       'conception_graphique_par' => 'Design (c)',
+       'commentaire' => 'kommentar',
+       'commentaires' => 'kommentarer ',
+
+       // D
+
+       // I
+
+       // L
+       'lire_la_suite' => 'L&auml;s mer',
+       'lire_la_suite_de' => ' om ',
+
+       // M
+
+       // P
+       'personaliser_nav' => 'Skr&auml;ddarsy denna meny',
+
+       // R
+
+       // S
+       'sous_licence' => 'under licens',
+
+       // T
+
+       // V
+
+       // Z
+);
+
+?>
diff --git a/www/plugins/zpip_v1/login.html b/www/plugins/zpip_v1/login.html
new file mode 100644 (file)
index 0000000..65f776b
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM)
+
+       La page d'accueil est la première page du site.
+       Elle s'affiche lorsque l'on ecrit l'adresse du site
+       dans la barre du navigateur.
+
+       Pour toutes les pages appelées par SPIP
+       (article, rubrique, sommaire, ...),
+       nous choisissons d'inclure la structure de la page
+       avec une balise INCLURE. De cette façon, un seul fichier
+       décrit l'organisation des blocs de la page, le fichier structure.html.
+
+       Nous passons en argument via le critere {env}
+       tout ce qui arrive dans l'environnement de SPIP,
+       comme les variables d'URL (spip.php?page=sommaire&variable=valeur).
+
+       Enfin, nous ajoutons une variable {type=sommaire} pour indiquer de
+       quel type de page il s'agit et afficher alors du contenu en conséquence.
+
+       Allez découvrir ce fameux fichier structure.html.
+       
+]
+<INCLURE{fond=structure}{env}{type=page}{composition=login} />
+
+
diff --git a/www/plugins/zpip_v1/mot.html b/www/plugins/zpip_v1/mot.html
new file mode 100644 (file)
index 0000000..fcfbcbb
--- /dev/null
@@ -0,0 +1,3 @@
+<BOUCLE_principale(MOTS) {id_mot} >
+<INCLURE{fond=structure}{env}{type=mot}{composition=#COMPOSITION} />
+</BOUCLE_principale>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/navigation/dist.html b/www/plugins/zpip_v1/navigation/dist.html
new file mode 100644 (file)
index 0000000..e2b4727
--- /dev/null
@@ -0,0 +1,4 @@
+[(#REM) Menu de navigation par rubriques ]
+<INCLURE{fond=inclure/rubriques}{id_rubrique}>
+
+#FORMULAIRE_RECHERCHE
diff --git a/www/plugins/zpip_v1/navigation/page.html b/www/plugins/zpip_v1/navigation/page.html
new file mode 100644 (file)
index 0000000..bd03c17
--- /dev/null
@@ -0,0 +1,6 @@
+[(#REM)
+ Ce squelette n'est necessaire que pour SPIP 2.0
+ A partir de SPIP 2.1, le compilateur trouve directement navigation/page-xxx
+
+]#SET{composition,#CHEMIN{navigation/page-#ENV{composition}|concat{.html}}|?{page-#ENV{composition},dist}}
+<INCLURE{fond=navigation/#GET{composition}}{env}>
diff --git a/www/plugins/zpip_v1/navigation/z_apl.html b/www/plugins/zpip_v1/navigation/z_apl.html
new file mode 100644 (file)
index 0000000..2ba4dc1
--- /dev/null
@@ -0,0 +1,10 @@
+[(#REM)
+
+  Squelette Big_Pipe
+       http://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919
+
+  (c) 2010 Cedric Morin
+  Distribue sous licence GPL
+
+]#CACHE{0}
+#INCLURE{fond=inclure/ajax_parallel_load,bloc=#SQUELETTE}
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/objet.html b/www/plugins/zpip_v1/objet.html
new file mode 100644 (file)
index 0000000..af1afcd
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=structure}{env}{type=#ENV{page,#ENV{type}}}{composition=#ENV{composition,''}}>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/page.html b/www/plugins/zpip_v1/page.html
new file mode 100644 (file)
index 0000000..af1c884
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=structure}{env}{type=page}{composition=#ENV{composition,#ENV{page}}}>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/plan.html b/www/plugins/zpip_v1/plan.html
new file mode 100644 (file)
index 0000000..bdff33a
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=structure}{env}{type=page}{composition=plan} />
diff --git a/www/plugins/zpip_v1/plugin.xml b/www/plugins/zpip_v1/plugin.xml
new file mode 100644 (file)
index 0000000..3ff6562
--- /dev/null
@@ -0,0 +1,43 @@
+<plugin>
+       <nom>Zpip-dist v1</nom>
+       <slogan>Squelette r&#233;utilisable, modulaire et th&#232;mable</slogan>
+       <auteur>Matthieu Marcillaud, C&#233;dric Morin, Romy T&#234;tue, Collectif SPIP</auteur>
+       <icon>img/zpip-128.png</icon>
+       <licence>GNU/GPL</licence>
+       <version>1.7.21</version>
+       <etat>stable</etat>
+       <description>
+Zpip est issu d'une fusion des projets Zesty et SPIP-Zen. Zpip-dist est la version de base de ce mod&#232;le de squelette, que vous pouvez utiliser telle quelle ou personnaliser et enrichir selon vos besoins.
+
+Plus qu'un squelette, Zpip est un exemple d'un syst&#232;me de squelette qui met en application les id&#233;es expos&#233;es dans [Mod&#232;le de squelette r&#233;utilisable->http://www.spip-contrib.net/Modele-de-squelette-reutilisable]. Il propose une organisation des squelettes visant &#224; le rendre :
+-* {{habillable}} par des th&#232;mes ind&#233;pendants du squelette
+-* {{maintenable}} dans le temps, par une duplication minimale du code
+-* {{rapidement d&#233;ployable}}, au prix d'un petit apprentissage initial sur son organisation
+
+Zpip s'adresse aussi bien aux d&#233;butants qui veulent profiter d'une galerie de th&#232;mes pr&#234;ts &#224; l'emploi, qu'aux webmestres avanc&#233;s auxquels il propose un fonctionnement et des m&#233;canismes productifs.
+
+Toute l'organisation et le fonctionnement de Zpip peuvent &#234;tre r&#233;utilis&#233;s pour construire de nouveaux squelettes qui b&#233;n&#233;ficieront des m&#234;mes avantages.
+       </description>
+       <prefix>Z</prefix>
+       <lien>http://www.spip-contrib.net/Le-Squelette-Zpip-dist</lien>
+       <fonctions>z_pipelines.php</fonctions>
+       <options>z_options.php</options>
+       <pipeline>
+               <nom>declarer_url_objets</nom>
+               <inclure>z_pipelines.php</inclure>
+       </pipeline>
+       <pipeline>
+               <nom>styliser</nom>
+               <inclure>z_pipelines.php</inclure>
+       </pipeline>
+       <pipeline>
+               <nom>insert_head</nom>
+               <inclure>z_pipelines.php</inclure>
+       </pipeline>
+       <pipeline>
+               <nom>pre_propre</nom>
+               <inclure>z_pipelines.php</inclure>
+       </pipeline>
+       <categorie>squelette</categorie>
+       <necessite id="SPIP" version="[2.0.10;3.0.99]" />
+</plugin>
diff --git a/www/plugins/zpip_v1/recherche.html b/www/plugins/zpip_v1/recherche.html
new file mode 100644 (file)
index 0000000..6199d4a
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=structure}{env}{type=page}{composition=recherche} />
diff --git a/www/plugins/zpip_v1/rechercher.gif b/www/plugins/zpip_v1/rechercher.gif
new file mode 100644 (file)
index 0000000..e7861df
Binary files /dev/null and b/www/plugins/zpip_v1/rechercher.gif differ
diff --git a/www/plugins/zpip_v1/rubrique.html b/www/plugins/zpip_v1/rubrique.html
new file mode 100644 (file)
index 0000000..2103694
--- /dev/null
@@ -0,0 +1,3 @@
+<BOUCLE_principale_rubrique(RUBRIQUES){id_rubrique}>
+<INCLURE{fond=structure}{env}{id_secteur=#ID_SECTEUR}{type=rubrique}{composition=#COMPOSITION} />
+</BOUCLE_principale_rubrique>
diff --git a/www/plugins/zpip_v1/site.html b/www/plugins/zpip_v1/site.html
new file mode 100644 (file)
index 0000000..2c3e6b6
--- /dev/null
@@ -0,0 +1,6 @@
+[(#REM)
+       Un cache plus court, pour la boucle syndic_articles
+]#CACHE{3600}
+<BOUCLE_site(SITES){id_syndic}>
+<INCLURE{fond=structure}{env}{id_rubrique=#ENV{id_rubrique,#ID_RUBRIQUE}}{type=site}{composition=#COMPOSITION} />
+</BOUCLE_site>
diff --git a/www/plugins/zpip_v1/sommaire.html b/www/plugins/zpip_v1/sommaire.html
new file mode 100644 (file)
index 0000000..4a475f2
--- /dev/null
@@ -0,0 +1,25 @@
+[(#REM)
+
+       La page d'accueil est la première page du site.
+       Elle s'affiche lorsque l'on ecrit l'adresse du site
+       dans la barre du navigateur.
+
+       Pour toutes les pages appelées par SPIP
+       (article, rubrique, sommaire, ...),
+       nous choisissons d'inclure la structure de la page
+       avec une balise INCLURE. De cette façon, un seul fichier
+       décrit l'organisation des blocs de la page, le fichier structure.html.
+
+       Nous passons en argument via le critere {env}
+       tout ce qui arrive dans l'environnement de SPIP,
+       comme les variables d'URL (spip.php?page=sommaire&variable=valeur).
+
+       Enfin, nous ajoutons une variable {type=sommaire} pour indiquer de
+       quel type de page il s'agit et afficher alors du contenu en conséquence.
+
+       Allez découvrir ce fameux fichier structure.html.
+       
+]
+<INCLURE{fond=structure}{env}{type=page}{composition=sommaire} />
+
+
diff --git a/www/plugins/zpip_v1/spip.png b/www/plugins/zpip_v1/spip.png
new file mode 100644 (file)
index 0000000..1b0c4db
Binary files /dev/null and b/www/plugins/zpip_v1/spip.png differ
diff --git a/www/plugins/zpip_v1/spip_formulaires.css b/www/plugins/zpip_v1/spip_formulaires.css
new file mode 100644 (file)
index 0000000..a05cee6
--- /dev/null
@@ -0,0 +1,108 @@
+/*  ------------------------------------------
+/*  Habillage des formulaires
+/*  ------------------------------------------ */
+input, select, textarea { font-size: 100%; font-family: inherit; }
+
+
+/* Structure generale des formulaires
+----------------------------------------------- */
+.formulaire_spip { clear: both; margin-bottom: 2em; padding: 0; border: 0; text-align: left; font-size: 1em; }
+.formulaire_spip form { margin: 0; padding: 0; } /* Bug IE/Win */
+
+/* Fieldset */
+.formulaire_spip fieldset { clear: both; margin: 0 0 1em 0; padding: 0; border: 0; }
+.formulaire_spip fieldset legend { margin: 0; padding: 0; font-size: 1.05em; font-weight: bold; background-color: #fff; color: #333; } /* Preciser la couleur des legend et du fond pour IE/Win */
+.formulaire_spip fieldset fieldset { margin-top: 1em; }
+.formulaire_spip fieldset fieldset legend { font-size: 1em; font-weight: normal; }
+
+/* Explications */
+.formulaire_spip .explication { margin: 0.50em 0; color: #444; }
+
+/* Lignes */
+.formulaire_spip ul { margin: 0; padding: 0; list-style: none; }
+.formulaire_spip ul li { clear: both; margin: 0; padding: 0.50em 0; }
+
+/* Labels */
+.formulaire_spip label { display: block; text-align: left; color: #444; font-weight: bold; /* pour IE/Win */ position: relative;  }
+.formulaire_spip li p { margin-top: 0; margin-bottom: 0; }
+
+.formulaire_spip .choix label{display:inline;font-weight:normal;}
+.formulaire_spip .choix input.radio,
+.formulaire_spip .choix input.checkbox {width:auto;}
+
+
+/* Champs de saisie */
+.formulaire_spip input.text { width: 15em; border: 1px inset; }
+.formulaire_spip textarea { width: 99%; border: 1px inset; }
+.formulaire_spip select { width: 99%; }
+
+/* Boutons */
+.formulaire_spip .boutons { clear: both; margin: 0; padding: 0; text-align: right; }
+.formulaire_spip .boutons input { margin-left: 1em; }
+.formulaire_spip .boutons input, input.submit {}
+
+
+/* Reponses, previsu et erreurs
+----------------------------------------------- */
+
+/* Champs obligatoires */
+.formulaire_spip li.obligatoire {}
+.formulaire_spip li.obligatoire label {}
+
+/* Previsualisation du message */
+.formulaire_spip fieldset.previsu { margin-bottom: 2em; padding: 1em; border: 2px dashed #F57900; }
+.formulaire_spip fieldset.previsu legend { padding: 0 0.50em; font-weight: bold; color: #F57900; }
+.formulaire_spip fieldset.previsu li { padding: 3px; border: none; }
+.formulaire_spip fieldset.previsu p { margin: 1em 0; } 
+
+/* Reponse du formulaire */
+.reponse_formulaire { font-weight: bold; color: #e86519; font-size: 1.20em; }
+fieldset.reponse_formulaire { border-color: #e86519; font-weight: normal; }
+fieldset.reponse_formulaire.reponse_formulaire legend { color: #F57900; } /* Preciser la couleur des legend et du fond pour IE/Win */
+
+/* * Erreurs */
+.formulaire_spip li.erreur .erreur_message { display: block; color: #C30; font-weight: bold; }
+.formulaire_spip li.erreur input.text, .formulaire_spip li.erreur textarea { background-color: #FCC; border-style: solid; border-color: #C30; }
+.reponse_formulaire_erreur { margin: 0; color: #C30; font-weight: bold; }
+
+/* * OK */
+.reponse_formulaire_ok { margin: 0; color: #53AD20; font-weight: bold; }
+
+
+/* Variantes et cas particuliers
+----------------------------------------------- */
+
+/* Barre de raccourcis typographiques */
+table.spip_barre { width: 100%; }
+table.spip_barre a img { background: #FDA; padding: 3px; border: 1px outset #CC9; }
+table.spip_barre a:focus img,
+table.spip_barre a:hover img,
+table.spip_barre a:active img { background: #FFF; border: 1px solid #CC9; }
+table.spip_barre input.barre { width: 99%; background: transparent; border: 0; color:inherit; }
+
+/* Formulaire de forum */
+.formulaire_forum .saisie_titre input.text, .formulaire_forum .saisie_titre textarea { width: 98%; }
+
+/* Selection des langues */
+.formulaire_menu_lang { margin: 0; padding: 0; background: none; }
+
+/* Formulaires de recherche (site / petitions) */
+.formulaire_recherche { margin: 0; padding: 0; background: none; }
+.formulaire_recherche * { display: inline; vertical-align: middle; }
+.formulaire_recherche label {}
+.formulaire_recherche input.text { width: 10em; padding-left: 25px; background: #FFF url(rechercher.gif) no-repeat left center; }
+.formulaire_recherche input.submit {}
+
+.spip_surligne {} /* Cf.: spip_style.css */
+
+/* Choix des mots-clefs */
+ul.choix_mots { display: block; margin: 0; padding: 0; list-style: none; }
+ul.choix_mots li { clear: none; float: left; display: block; width: 30%; padding: 1%; }
+ul.choix_mots li label { display: inline; font-weight: normal; }
+
+.formulaire_spip .bugajaxie { display: none; } /* Bug IE/Win */
+
+/* Formulaire de login dans une page */
+.formulaire_login ul li {clear:left;}
+.formulaire_login .editer_password .details {display:block;}
+.formulaire_login #spip_logo_auteur {float:right;}
diff --git a/www/plugins/zpip_v1/spip_pass.html b/www/plugins/zpip_v1/spip_pass.html
new file mode 100644 (file)
index 0000000..8fbc02c
--- /dev/null
@@ -0,0 +1 @@
+<INCLURE{fond=structure}{env}{type=page}{composition=spip_pass} />
diff --git a/www/plugins/zpip_v1/spip_style.css b/www/plugins/zpip_v1/spip_style.css
new file mode 100644 (file)
index 0000000..db1bc63
--- /dev/null
@@ -0,0 +1,65 @@
+/* SPIP-STYLE                                                           */
+/* Cette feuille contient les styles associes au code genere par SPIP.  */
+/* Ces styles sont indispensables et doivent necessairement etre        */
+/* definis pour le bon fonctionnement de vos squelettes.                */
+
+
+/* Intertitre */
+h3.spip { /* text-align: center; margin-top: 2em; margin-bottom: 1.4em; font-size: 1.15em; font-weight: bold;*/ }
+hr.spip { margin: 2em auto; }
+
+/* Listes SPIP */
+ul.spip {}
+ol.spip { list-style: decimal; }
+
+/* Citations, code et poesie */
+blockquote.spip { margin: 2em 0; padding-left: 1em; border-left: 0.30em solid; }
+blockquote.spip_poesie { margin: 2em 0; padding-left: 1em; border-left: 1px solid; font-family: Garamond, Georgia, Times, serif; font-size:120%; }
+blockquote.spip_poesie div { text-indent: -3em; margin-left: 3em; }
+
+.spip_code, .spip_cadre { font-family: Courier, "Courier New", monospace; color: #009; }
+.spip_cadre {  background-color: #F4F8F8; border: 1px inset; }
+div.spip_code, .spip_cadre { margin-bottom: 1em;  }
+
+.spip_surligne { background: #FF6; }
+
+/* Tableaux */
+table.spip { margin-right: auto; margin-left: auto; margin-bottom: 1em; border-collapse: collapse; border-spacing: 0; line-height: normal; }
+table.spip caption { caption-side: top; /* bottom pas pris en compte par IE */ text-align: center; margin-right: auto; margin-left: auto; font-weight: bold; }
+table.spip tr.row_first { background: #FFC; }
+table.spip tr.row_odd { background: #EEE; }
+table.spip tr.row_even { background: #DDD; }
+table.spip th, table.spip td { padding: 0.20em 0.40em; text-align: left; border: 1px solid; }
+table.spip th { vertical-align: bottom; font-weight: bold; }
+table.spip td { vertical-align: top; }
+
+/* Logos, documents et images */
+img, .spip_logos { margin: 0; padding: 0; border: 0; }
+.spip_documents { text-align: center; line-height: normal; }
+.spip_documents p { margin: 0.10em; padding: 0; }
+.spip_documents_center { display: block;display: table; clear: both; margin: 1em auto; }
+.spip_documents_left { float: left; margin-right: 15px; margin-bottom: 5px; }
+.spip_documents_right { float: right; margin-left: 15px; margin-bottom: 5px; }
+.spip_doc_titre { margin-right: auto; margin-left: auto; font-weight: bold; font-size: 0.90em; }
+.spip_doc_descriptif { clear: both; margin-right: auto; margin-left: auto; font-size: 0.90em; }
+
+/* modeles par defaut */
+.spip_modele { float: right; display: block; padding: 1em; border: 1px solid; width: 180px; }
+
+/* Couleurs des liens de SPIP */
+a.spip_note {} /* liens vers notes de bas de page */
+a.spip_ancre {} /* liens internes a la page */
+a.spip_in { color: #900; } /* liens internes */
+a.spip_out { color: #009;  } /* liens sortants */
+a.spip_url { color: #009; } /* liens url sortants */
+a.spip_glossaire { color: #060;  } /* liens vers encyclopedie */
+a.spip_glossaire:hover { text-decoration: underline overline; }
+.on,.on a,a.on { font-weight: bold; } /* liens exposes */ 
+
+.small {font-size:90%;}
+
+/* Espaceur de blocs */
+.nettoyeur { clear: both; height: 0; margin: 0; padding: 0; border: 0; line-height: 1px; font-size: 1px; }
+
+/* Non visible a l'ecran */
+.invisible { position: absolute; top: -3000em; height: 1%; }
diff --git a/www/plugins/zpip_v1/structure.html b/www/plugins/zpip_v1/structure.html
new file mode 100644 (file)
index 0000000..af1e5ab
--- /dev/null
@@ -0,0 +1,14 @@
+[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="#LANG" lang="#LANG" dir="#LANG_DIR">
+<head>
+<INCLURE{fond=head/#ENV{type},env}>
+<INCLURE{fond=inclure/head}>
+</head>
+<body class="page_#ENV{type,page}[ #ENV{type,page}_(#ENV{composition,''})]">
+<INCLURE{fond=body,env}>
+#SPIP_CRON
+</body>
+</html>
+(#EVAL{#VAL{var_zajax}|_request}|non)][
+<INCLURE{fond=#VAL{var_zajax}|_request|concat{'/',#ENV{type}},env}>
+(#EVAL{#VAL{var_zajax}|_request}|oui)]
diff --git a/www/plugins/zpip_v1/svn.revision b/www/plugins/zpip_v1/svn.revision
new file mode 100644 (file)
index 0000000..da586be
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_squelettes_/zpip-dist/branches/zpip_v1
+Revision: 68933
+Dernier commit: 2013-01-10 19:00:04 +0100 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_squelettes_/zpip-dist/branches/zpip_v1</origine>
+<revision>68933</revision>
+<commit>2013-01-10 19:00:04 +0100 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/tests/z_scaffoldable.php b/www/plugins/zpip_v1/tests/z_scaffoldable.php
new file mode 100644 (file)
index 0000000..0545d09
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Test unitaire de la fonction z_scaffoldable
+ * du fichier ../plugins/zpip/z_pipelines.php
+ *
+ * genere automatiquement par TestBuilder
+ * le 2010-03-04 22:02
+ */
+
+       $test = 'z_scaffoldable';
+       $remonte = "../";
+       while (!is_dir($remonte."ecrire"))
+               $remonte = "../$remonte";
+       require $remonte.'tests/test.inc';
+       find_in_path("../plugins/zpip/z_pipelines.php",'',true);
+
+       //
+       // hop ! on y va
+       //
+       $err = tester_fun('test_z_scaffoldable', essais_z_scaffoldable());
+       
+       // si le tableau $err est pas vide ca va pas
+       if ($err) {
+               die ('<dl>' . join('', $err) . '</dl>');
+       }
+
+       echo "OK";
+
+       function test_z_scaffoldable(){
+               $args = func_get_args();
+               $res = call_user_func_array('z_scaffoldable', $args);
+               return is_array($res)?count($res):false;
+       }
+
+       function essais_z_scaffoldable(){
+               $essais = array (
+  1 => 
+  array (
+    0 => false,
+    1 => 'articles',
+  ),
+  2 => 
+  array (
+    0 => false,
+    1 => 'rubriques',
+  ),
+  3 => 
+  array (
+    0 => false,
+    1 => 'sites',
+  ),
+  4 => 
+  array (
+    0 => 3,
+    1 => 'article',
+  ),
+);
+               return $essais;
+       }
+
+
+
+
+
+
+
+
+
+?>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/z_options.php b/www/plugins/zpip_v1/z_options.php
new file mode 100644 (file)
index 0000000..0a3da6c
--- /dev/null
@@ -0,0 +1,20 @@
+<?php\r
+/*\r
+ * Plugin Zpip\r
+ * (c) 2008-2010 Cedric MORIN Yterium.net\r
+ * Distribue sous licence GPL\r
+ *\r
+ */\r
+if (!defined("_ECRIRE_INC_VERSION")) return;\r
+\r
+if ($z = _request('var_zajax')) {\r
+       if ($z_blocs = isset($GLOBALS['z_blocs'])?$GLOBALS['z_blocs']:array('contenu','navigation','extra','head')\r
+         AND in_array($z,$z_blocs)) {\r
+               $GLOBALS['marqueur'] .= "$z:";\r
+               $GLOBALS['flag_preserver'] = true;\r
+       }\r
+       else\r
+               set_request('var_zajax'); // enlever cette demande incongrue\r
+}\r
+\r
+?>
\ No newline at end of file
diff --git a/www/plugins/zpip_v1/z_pipelines.php b/www/plugins/zpip_v1/z_pipelines.php
new file mode 100644 (file)
index 0000000..784fceb
--- /dev/null
@@ -0,0 +1,323 @@
+<?php
+/*
+ * Plugin Zpip
+ * (c) 2008-2010 Cedric MORIN Yterium.net
+ * Distribue sous licence GPL
+ *
+ */
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+// demander a SPIP de definir 'type' dans le contexte du premier squelette
+define('_DEFINIR_CONTEXTE_TYPE',true);
+// verifier une seule fois que l'on peut utiliser APL si demande
+if (defined('_Z_AJAX_PARALLEL_LOAD')) {
+       if (_request('var_zapl')=='non') {
+               include_spip('inc/cookie');
+               spip_setcookie('no_zapl',$_COOKIE['no_zapl']='no_zapl');
+       }
+       if (!isset($_COOKIE['no_zapl'])
+        AND !_IS_BOT
+        AND !_request('var_zajax')
+        AND _request('var_mode')!=="debug"
+        AND $_SERVER['REQUEST_METHOD'] == 'GET'
+        ) {
+               define('_Z_AJAX_PARALLEL_LOAD_OK',true);
+               $GLOBALS['marqueur'] .= ":Zapl";
+       }
+}
+
+/**
+ * Inutilise mais permet le chargement de ce fichier avant le decodage des urls
+ * et l'utilisation de _DEFINIR_CONTEXTE_TYPE
+ * @param array $flux
+ * @return array
+ */
+function Z_declarer_url_objets($flux){
+       return $flux;
+}
+
+/**
+ * Fonction Page automatique a partir de contenu/page-xx
+ *
+ * @param array $flux
+ * @return array
+ */
+function Z_styliser($flux){
+       $z_blocs = isset($GLOBALS['z_blocs'])?$GLOBALS['z_blocs']:array('contenu','navigation','extra','head');
+       $z_contenu = reset($z_blocs); // contenu par defaut
+
+       $squelette = $flux['data'];
+       $fond = $flux['args']['fond'];
+       $ext = $flux['args']['ext'];
+
+       // Ajax Parallel loading : ne pas calculer le bloc, mais renvoyer un js qui le loadera an ajax
+       if (defined('_Z_AJAX_PARALLEL_LOAD_OK')
+         AND $dir = explode('/',$fond)
+         AND count($dir)==2 // pas un sous repertoire
+         AND $dir = reset($dir)
+         AND in_array($dir,$z_blocs) // verifier deja qu'on est dans un bloc Z
+         AND in_array($dir,explode(',',_Z_AJAX_PARALLEL_LOAD)) // et dans un demande en APL
+         AND $pipe = find_in_path("$dir/z_apl.$ext") // et qui contient le squelette APL
+         ){
+               $flux['data'] = substr($pipe, 0, - strlen(".$ext"));
+               return $flux;
+       }
+
+       // gerer les squelettes non trouves
+       // -> router vers les /dist.html
+       // ou scaffolding ou page automatique les contenus
+       if (!$squelette){
+
+               // Cas de figure où on a déclaré type-composition.html dans un bloc, mais où type.html n'existe pas
+               if (isset($flux['args']['contexte']['composition'])
+                 AND $dir = explode('/',$fond)
+                 AND $dir = reset($dir)
+                 AND in_array($dir,$z_blocs)
+                 AND $f=find_in_path($fond."-".$flux['args']['contexte']['composition'].".$ext")){
+                       $flux['data'] = substr($f,0,-strlen(".$ext"));
+               }
+
+               // si on est sur un ?page=XX non trouve
+               elseif ($flux['args']['contexte'][_SPIP_PAGE] == $fond OR $flux['args']['contexte']['type'] == $fond) {
+                       // si c'est un objet spip, associe a une table, utiliser le fond homonyme
+                       if (z_scaffoldable($fond)){
+                               $flux['data'] = substr(find_in_path("objet.$ext"), 0, - strlen(".$ext"));
+                       }
+                       // sinon, brancher sur contenu/page-xx si elle existe
+                       // si on est sur un ?page=XX non trouve
+                       elseif ($flux['args']['contexte'][_SPIP_PAGE] == $fond) {
+                               $base = "$z_contenu/page-".$fond.".".$ext;
+                               if ($base = find_in_path($base)){
+                                       $flux['data'] = substr(find_in_path("page.$ext"), 0, - strlen(".$ext"));
+                               }
+                       }
+               }
+
+               // scaffolding :
+               // si c'est un fond de contenu d'un objet en base
+               // generer un fond automatique a la volee pour les webmestres
+               elseif (strncmp($fond, "$z_contenu/", strlen($z_contenu)+1)==0
+                 AND include_spip('inc/autoriser')
+                 AND isset($GLOBALS['visiteur_session']['id_auteur']) // performance
+                 AND autoriser('webmestre')){
+                 $type = substr($fond,strlen($z_contenu)+1);
+                       if ($is = z_scaffoldable($type))
+                               $flux['data'] = z_scaffolding($type,$is[0],$is[1],$is[2],$ext);
+               }
+               
+               // sinon, si on demande un fond non trouve dans un des autres blocs
+               // et si il y a bien un contenu correspondant ou scaffoldable
+               // se rabbatre sur le dist.html du bloc concerne
+               else{
+                       if ( $dir = explode('/',$fond)
+                         AND $dir = reset($dir)
+                         AND $dir !== $z_contenu
+                         AND in_array($dir,$z_blocs)){
+                               $type = substr($fond,strlen("$dir/"));
+                               if (find_in_path("$z_contenu/$type.$ext") OR z_scaffoldable($type))
+                                       $flux['data'] = substr(find_in_path("$dir/dist.$ext"), 0, - strlen(".$ext"));
+                       }
+               }
+               $squelette = $flux['data'];
+       }
+       if ($fond=='body' AND substr($squelette,-strlen($fond))==$fond){
+               if (isset($flux['args']['contexte']['type'])
+                 AND (
+                       (isset($flux['args']['contexte']['composition'])
+                       AND file_exists(($f=$squelette."-".$flux['args']['contexte']['type']."-".$flux['args']['contexte']['composition']).".$ext"))
+                       OR
+                       file_exists(($f=$squelette."-".$flux['args']['contexte']['type']).".$ext")
+                 ))
+                       $flux['data'] = $f;
+       }
+       // chercher le fond correspondant a la composition
+       elseif (isset($flux['args']['contexte']['composition'])
+         AND substr($squelette,-strlen($fond))==$fond
+         AND $dir = explode('/',$fond)
+         AND $dir = reset($dir)
+         AND in_array($dir,$z_blocs)
+         AND $f=find_in_path($fond."-".$flux['args']['contexte']['composition'].".$ext")){
+               $flux['data'] = substr($f,0,-strlen(".$ext"));
+       }
+       return $flux;
+}
+
+
+/**
+ * Tester si un type est scaffoldable
+ * cad si il correspond bien a un objet en base
+ * 
+ * @staticvar array $scaffoldable
+ * @param string $type
+ * @return bool
+ */
+function z_scaffoldable($type){
+       static $scaffoldable = array();
+       if (isset($scaffoldable[$type]))
+               return $scaffoldable[$type];
+       if (preg_match(',[^\w],',$type))
+               return $scaffoldable[$type] = false;
+       if ($table = table_objet($type)
+         AND $type == objet_type($table)
+         AND $trouver_table = charger_fonction('trouver_table','base')
+         AND
+               ($desc = $trouver_table($table)
+               OR $desc = $trouver_table($table_sql = $GLOBALS['table_prefix']."_$table"))
+               )
+               return $scaffoldable[$type] = array($table,$desc['table'],$desc);
+       else
+               return $scaffoldable[$type] = false;
+}
+
+
+/**
+ * Generer a la volee un fond a partir d'une table de contenu
+ *
+ * @param string $type
+ * @param string $table
+ * @param string $table_sql
+ * @param array $desc
+ * @param string $ext
+ * @return string
+ */
+function z_scaffolding($type,$table,$table_sql,$desc,$ext){
+       include_spip('public/interfaces');
+       $primary = id_table_objet($type);
+       if (!$primary AND isset($desc['key']["PRIMARY KEY"])){
+               $primary = $desc['key']["PRIMARY KEY"];
+       }
+
+       // reperer un titre
+       $titre = 'titre';
+       if (isset($GLOBALS['table_titre'][$table])){
+               $titre = explode(' ',$GLOBALS['table_titre'][$table]);
+               $titre = explode(',',reset($titre));
+               $titre = reset($titre);
+       }
+       if (isset($desc['field'][$titre])){
+               unset($desc['field'][$titre]);
+               $titre="<h1 class='h1 #EDIT{titre}'>#".strtoupper($titre)."</h1>";
+       }
+       else $titre="";
+
+       // reperer une date
+       $date = "date";
+       if (isset($GLOBALS['table_date'][$table]))
+               $date = $GLOBALS['table_date'][$table];
+       if (isset($desc['field'][$date])){
+               unset($desc['field'][$date]);
+               $date = strtoupper($date);
+               $date="<p class='info-publi'>[(#$date|nom_jour) ][(#$date|affdate)][, <span class='auteurs'><:par_auteur:> (#LESAUTEURS)</span>]</p>";
+       }
+       else $date = "";
+
+       $content = array();
+       foreach($desc['field'] as $champ=>$z){
+               if (!in_array($champ,array('maj','statut','idx',$primary))){
+                       $content[] = "[<div><strong>$champ</strong><div class='#EDIT{".$champ."} $champ'>(#".strtoupper($champ)."|image_reduire{500,0})</div></div>]";
+               }
+       }
+       $content = implode("\n\t",$content);
+
+       $scaffold = "#CACHE{0}
+<BOUCLE_contenu($table_sql){".$primary."}>
+[(#REM) Fil d'Ariane ]
+<p id='hierarchie'><a href='#URL_SITE_SPIP/'><:accueil_site:></a>[ &gt; <strong class='on'>(#TITRE|couper{80})</strong>]</p>
+
+<div class='contenu-principal'>
+       <div class='cartouche'>
+               $titre
+               $date
+       </div>
+
+       $content
+
+</div>
+
+[<div class='notes surlignable'><h2 class='h2 pas_surlignable'><:info_notes:></h2>(#NOTES)</div>]
+</BOUCLE_contenu>";
+
+       $dir = sous_repertoire(_DIR_CACHE,"scaffold",false);
+       $dir = sous_repertoire($dir,"contenu",false);
+       $f = $dir."$type";
+       ecrire_fichier("$f.$ext",$scaffold);
+       return $f;
+}
+
+
+
+/**
+ * Surcharger les intertires avant que le core ne les utilise
+ * pour y mettre la class h3
+ * une seule fois suffit !
+ *
+ * @param string $flux
+ * @return string
+ */
+function Z_pre_propre($flux){
+       static $init = false;
+       if (!$init){
+               if (isset($GLOBALS['debut_intertitre']) and $GLOBALS['debut_intertitre']){
+                       $intertitre = $GLOBALS['debut_intertitre'];
+                       $class = extraire_attribut($GLOBALS['debut_intertitre'],'class');
+                       $class = ($class ? " $class":"");
+                       $GLOBALS['debut_intertitre'] = inserer_attribut($GLOBALS['debut_intertitre'], 'class', "h3$class");
+                       foreach($GLOBALS['spip_raccourcis_typo'] as $k=>$v){
+                               $GLOBALS['spip_raccourcis_typo'][$k] = str_replace($intertitre,$GLOBALS['debut_intertitre'],$GLOBALS['spip_raccourcis_typo'][$k]);
+                       }
+               }
+               else {
+                       $GLOBALS['debut_intertitre'] = '<h3 class="h3 spip">';
+                       $GLOBALS['fin_intertitre'] = '</h3>';
+               }
+               $init = true;
+       }
+       return $flux;
+}
+
+/**
+ * Ajouter le inc-insert-head du theme si il existe
+ *
+ * @param string $flux
+ * @return string
+ */
+function Z_insert_head($flux){
+       if (find_in_path('inc-insert-head.html')){
+               $flux .= recuperer_fond('inc-insert-head',array());
+       }
+       return $flux;
+}
+
+//
+// fonction standard de calcul de la balise #INTRODUCTION
+// mais retourne toujours dans un <p> comme propre
+//
+// http://doc.spip.org/@filtre_introduction_dist
+if (!function_exists('filtre_introduction')){ // securite
+function filtre_introduction($descriptif, $texte, $longueur, $connect) {
+       include_spip('public/composer');
+       $texte = filtre_introduction_dist($descriptif, $texte, $longueur, $connect);
+
+       if ($GLOBALS['toujours_paragrapher'] AND strpos($texte,"</p>")===FALSE)
+               // Fermer les paragraphes ; mais ne pas en creer si un seul
+               $texte = paragrapher($texte, $GLOBALS['toujours_paragrapher']);
+
+       return $texte;
+}
+}
+
+/**
+ * Tester la presence sur une page
+ * @param object $p
+ * @return object
+ */
+if (!function_exists('balise_SI_PAGE_dist')){
+function balise_SI_PAGE_dist($p) {
+       $_page = interprete_argument_balise(1,$p);
+       $p->code = "(((\$Pile[0][_SPIP_PAGE]==(\$zp=$_page)) OR (\$Pile[0]['composition']==\$zp AND \$Pile[0]['type']=='page'))?' ':'')";
+       $p->interdire_scripts = false;
+       return $p;
+}
+}
+?>
diff --git a/www/themes/theme_Outdoor1-0/body.html b/www/themes/theme_Outdoor1-0/body.html
new file mode 100644 (file)
index 0000000..e9b8685
--- /dev/null
@@ -0,0 +1,49 @@
+<!-- wrap starts here -->
+<div id="wrap">
+       
+               [(#REM) Entete de la page + titre du site ]
+       <!--header -->
+       <div id="header-wrap">
+               <div id="header">
+                       [(#REM) HEADER / ENTETE ]
+                       <INCLURE{fond=inclure/entete,env}>
+               </div>
+       </div>
+       <!--header ends-->                                      
+       <div id="nav">
+               [(#REM) MAIN NAVIGATION / NAVIGATION PRINCIPALE ]
+               <INCLURE{fond=inclure/barre-nav,env}>
+       </div>
+       
+       <!-- content-wrap starts -->
+       <div id="content-wrap">
+                               
+               <div id="main"> 
+                       [(#REM) CONTENT / CONTENU ]
+                       <INCLURE{fond=contenu/#ENV{type},env}>
+               <!-- main ends -->      
+               </div>
+               
+               <!-- sidebar starts -->
+               <div id="sidebar">
+                       [(#REM) SECONDARY NAVIGATION SIDEBAR / Navigation laterale secondaire ]
+                       <INCLURE{fond=navigation/#ENV{type},env}>
+           
+                       [(#REM) EXTRA INFORMATIONS / Informations complementaires]
+                       <INCLURE{fond=extra/#ENV{type},env}>
+       
+               <!-- sidebar ends -->           
+               </div>
+               
+       <!-- content-wrap ends-->       
+       </div>
+               
+       <!-- footer starts here -->     
+       <div id="footer-wrap"><div id="footer-content">
+               [(#REM) FOOTER / Pied de page ]
+               <INCLURE{fond=inclure/pied,env}>
+               <INCLURE{fond=inc-theme-copyleft}>
+       </div></div>
+       <!-- footer ends here -->
+<!-- wrap ends here -->
+</div>
\ No newline at end of file
diff --git a/www/themes/theme_Outdoor1-0/habillage.css b/www/themes/theme_Outdoor1-0/habillage.css
new file mode 100644 (file)
index 0000000..0c4f209
--- /dev/null
@@ -0,0 +1,671 @@
+/* --------------------------------------------------------- */
+/* Feuille de style des squelettes par defaut pour SPIP 2.0  */
+/* --------------------------------------------------------- */
+/* ----------------------------------------------
+       Adaptation pour Spip-zen : Cedric Morin http://www.yterium.com
+ ------------------------------------------------ */
+
+/* Specificites SPIP */
+h3.spip {text-align:left;}
+
+#hierarchie { clear: both; margin-bottom: 2em; font-size: 0.90em; }
+#hierarchie, #hierarchie a { color: #666; }
+
+.cartouche { margin-bottom: 2em; }
+.cartouche .spip_logos { float: right; margin-left: 16px; margin-bottom: 4px; }
+.cartouche p { margin: 0; padding: 0; clear: left; }
+.surtitre, .soustitre { font-size: 0.90em; color: #666; text-transform: uppercase; letter-spacing: 0.10em; }
+.cartouche .surtitre { margin-bottom: 0.30em; }
+.cartouche .soustitre { margin-top: 0.50em; margin-bottom: 0.30em; }
+.cartouche .traductions { font-size: 0.90em; }
+
+.chapo { margin-bottom: 1.50em; line-height: 1.40em; font-weight: bold; color: #669; }
+.texte { line-height: 1.60em; }
+.hyperlien { display: block; background: #EEE; padding: 0.50em 1em; font-weight: bold; }
+.ps, .notes { margin-bottom: 2em; line-height: 1.40em; }
+.notes { clear: both; font-size: 0.90em; }
+
+abbr.published { border: 0; }
+
+/* Portfolio */
+.documents_portfolio { clear: both; margin: 2em auto; text-align: center; }
+.documents_portfolio .spip_logos { margin: 6px 3px 0 3px; padding: 4px; border: 1px solid #DDD; }
+.documents_portfolio a:hover .spip_logos { border-color: #F57900; }
+.documents_portfolio a.on .spip_logos { border-color: #8B6F92; }
+#document_actif { margin: 1em auto; }
+#document_actif img { padding: 4px; border: 1px solid #DDD; }
+
+/* Pagination */
+.pagination { clear: both; text-align: right; font-size: 0.95em; color: #666; }
+.pagination .on { font-weight: bold; color: #666; }
+
+.menu-liste, .liste-items  {list-style:none;}
+
+.liste-items {border-bottom:1px solid #EBEBEB;}
+.liste-items .item {padding:5px;clear:both;overflow:hidden;border-top:1px solid #EBEBEB;}
+.liste-items + .pagination {margin-top:0;padding-top:0;}
+
+.menu-liste {
+       text-align: left;
+       margin: 7px 0px 8px;
+       padding: 0;
+       border-top: 1px solid #EBEBEB;
+}
+.menu-liste .menu-entree {
+       list-style: none;
+       border-bottom: 1px solid #EBEBEB;
+       padding: 5px;
+       margin: 0 2px;
+}
+* html body .menu-liste .menu-entree {
+       height: 1%;
+}
+.menu-liste .menu-entree a {
+       text-decoration: none;
+       background-image: none;
+       color: #895F30;
+}
+.menu-liste .menu-entree a:hover {
+       color: #1773BC;
+}
+.menu-liste .menu-liste { margin-left: 5px; padding: 0; }
+.menu-liste .menu-liste .menu-entree { border: none; }
+
+.formulaire_recherche { margin-bottom: 2em; } /*Cf.: spip_formulaires.css*/
+
+
+/* Habillage des forums
+---------------------------------------------- */
+.repondre { clear: both; margin-top: 0em; margin-right: 1em; text-align: right; font-weight: bold; }
+
+/* * Habillage des forums */
+ul.forum { display: block; clear: both; margin: 0; padding: 0; }
+ul.forum, ul.forum ul { list-style: none; }
+
+
+/* comments list */
+ul.forum,ul.forum ul {
+       margin: 12px 10px;
+       padding: 0;
+       border-style: solid;    
+       border-color: #F0F0F0;  
+       border-width: 1px 1px 0 1px;
+}
+ul.forum ul.spip {border:0;}
+
+ul.forum ul { margin:0; }
+.forum li {
+       margin: 0;
+       padding: 10px;
+       list-style: none;
+       border-bottom: 1px solid #F0F0F0; 
+}
+.forum ul.spip li {border:0;padding:0;}
+.forum li cite {
+       display: block;
+       font-style: normal;
+       font-weight: bold;
+       padding: 7px;   
+}
+.forum li cite img {
+       float: left;
+       margin-right: 10px;     
+}
+.forum li cite .forum-chapo {
+       font-size: .8em;
+       font-weight: normal;
+}
+.forum li .forum-texte {
+       clear: both;
+       margin: 0; padding: 0;
+}
+.forum li.alt {
+       background: #f8f8f8 
+}
+
+/* tables */
+tables.spip tr,tables.spip tr.row_odd,tables.spip tr.row_even {background:transparent;}
+/* ----------------- */
+/********************************************
+   AUTHOR:                     Erwin Aligam 
+   WEBSITE:                    http://www.styleshout.com/
+       TEMPLATE NAME:          Outdoor
+   TEMPLATE CODE:      S-0020
+   VERSION:          1.0               
+ *******************************************/
+/********************************************
+   HTML ELEMENTS
+********************************************/ 
+
+/* Top Elements */
+* { margin: 0; padding: 0; outline: 0 }
+
+body {
+       background: #f7f0e3 url(img/bg.jpg) repeat-x;
+       font: 70%/1.6em Verdana, Tahoma, Arial, Geneva, sans-serif;
+       color: #666666; 
+       text-align: center;
+       margin: 0 0 50px 0;
+}
+
+/* links */
+a, a:visited { 
+       color: #5A93C9;
+       background: inherit;
+       text-decoration: none;  
+}
+a:hover {
+       color: #88ac0b;
+       background: inherit;
+       text-decoration: underline;     
+}
+
+/* headers */
+h1,.h1, h2,.h2, h3,.h3, h3.spip {
+       font-family: 'Trebuchet MS', Tahoma, Sans-serif;
+       color: #444;
+
+line-height:100%;}
+h1,.h1 {
+       font-size: 230%;        
+       font-weight: normal;
+       letter-spacing: -1px;
+}
+h2,.h2 {
+       font-size: 180%;
+       color: #88ac0b;
+}
+h3,.h3, h3.spip {
+       font-size: 150%;        
+       font-weight: normal;
+       line-height:100%;
+}
+
+h1,.h1, h2,.h2, h3,.h3, h3.spip, p {
+       padding: 10px 0;
+       margin: 0;
+}
+ul.spip, ol.spip, ul.forum ul.spip {
+       margin: 5px 10px;
+       padding: 0 20px;
+}
+ul {
+       list-style: none;
+}
+
+/* images */
+.spip_documents img, .spip_logos img {
+       background: #fafafa;
+  border: 1px solid #dcdcdc;
+       padding: 5px;
+}
+.spip_documents_right {
+  margin: 5px 10px 10px;
+  margin-left: 10px;
+}
+.spip_documents_left {
+  margin: 5px 0px 10px;
+  margin-right: 20px;
+}
+
+.spip_code,code {font: 500 1em/1.5em 'Lucida Console', 'courier new', monospace ;}
+.spip_cadre {
+       margin: 5px 0;
+       padding: 10px;
+       text-align: left;
+       display: block;
+       overflow: auto;
+       font: 500 1em/1.5em 'Lucida Console', 'courier new', monospace ;
+       /* white-space: pre; */
+       border: 1px solid #F4F3EC;
+       background: #FAFAE7;
+       width:90%;
+}
+acronym,abbr {
+  cursor: help;
+  border-bottom: 1px dashed #777;
+}
+blockquote.spip {
+       margin: 10px 0;
+       padding: 0;
+       padding-left: 45px;
+       border: 1px solid #F4F3EC;
+       background: #FAFAE7 url(img/quote.jpg) no-repeat 7px 10px;
+       font: bold 1.3em/1.5em 'Trebuchet MS', Tahoma, Sans-serif;
+       color: #976957;
+}
+
+/* start - table */
+table.spip {
+       border-collapse: collapse;
+       margin: 10px 0;
+}
+table.spip caption {text-align:left;}
+table.spip th strong {
+       color: #fff;
+}
+table.spip th {
+       background: #93BC0C url(img/nav.jpg) repeat-x;
+       height: 35px;
+       padding-left: 12px;
+       padding-right: 12px;
+       color: #fff;
+       text-align: left;
+       border:0;
+       border-left: 1px solid #B6D59A;
+       border-bottom: solid 2px #fff;
+}
+table.spip tr {
+       height: 32px;
+}
+table.spip td {
+       padding-left: 11px;
+       padding-right: 11px;
+       border:0;
+       border-left: 1px solid #fff;
+       border-bottom: 1px solid #fff;
+}
+td.first,th.first {
+       border-left: 0px;
+}
+table.spip tr.row_even {
+       background: #F8F8F8;
+}
+table.spip tr.row-odd {
+       background: #EFEFEF;            
+}
+/* end - table */
+
+/* form elements */
+.formulaire_spip {
+       margin:10px 0; padding: 10px;
+       border: 1px solid #f1f1f1; 
+       background-color: #f5f5f5;      
+}
+.formulaire_spip fieldset legend {background-color: #f5f5f5;}
+.formulaire_spip label {
+       display:block;
+       font-weight:bold;
+       margin:5px 0;
+}
+.formulaire_spip input.text,input.password {
+       padding:2px;
+       border:1px solid #eee;
+       font: normal 1em Verdana, sans-serif;
+       color:#777;
+}
+.formulaire_spip textarea {
+       padding:2px;
+       font: normal 1em Verdana, sans-serif;
+       border:1px solid #eee;
+       height:100px;
+       display:block;
+       color:#777;
+}
+#contenu .formulaire_spip textarea {   width:400px;}
+
+.formulaire_spip .boutons input { 
+       font: bold 12px Arial, Sans-serif; 
+       height: 24px;
+       margin: 0;
+       padding: 2px 3px; 
+       color: #FFF;
+       background: #8EB50C url(img/nav.jpg) repeat-x 0 0;
+       border: 1px solid #88AD0C;
+}
+
+/* search form */
+.formulaire_recherche {
+       background-color: transparent;
+       border: none;   
+       margin: 0; padding: 5px 0 15px 0;       
+               
+}
+#formulaire_recherche {width: 250px;}
+
+.formulaire_recherche p { margin: 0; padding: 0; }
+.formulaire_recherche input.text { 
+       color: #777; 
+       height: 18px;
+       padding: 2px;   
+       border: 1px solid #E5E5E5;
+       vertical-align: top;
+       background-image:none;
+}
+#formulaire_recherche input.text {width: 170px;}
+
+.formulaire_recherche input.submit {
+       width: 60px;
+       height: 24px;
+       padding: 2px 5px;
+       vertical-align: top;
+}
+
+/********************************************
+   LAYOUT
+********************************************/ 
+#wrap {
+       position: relative;
+       background: #fff url(img/wrap-bg.jpg) repeat-y;
+       width: 900px;   
+       margin: 50px auto 0 auto;
+       text-align: left;
+}
+#content-wrap {
+       position: relative;
+       background: #fff url(img/content-bg.jpg) repeat-x;
+       clear: both;
+       float: left;    
+       width: 870px;   
+       padding: 0;                     
+       margin-left: 15px;      
+       display: inline;
+       border-top: 5px solid #fff;
+       border-bottom: 1px solid #e5e5e5;
+       border-left: 1px solid #fff;
+       border-right: 1px solid #fff;
+}
+#header-wrap {
+       position: relative;
+       background: #fff url(img/header-bg.jpg) repeat-x;
+       padding: 0;     
+       margin: 0px auto;
+       width: 870px;   
+       height: 311px;
+}
+#header {
+       background: url(img/header-photo.jpg) no-repeat bottom left;
+       width: 870px;   
+       height: 311px;
+}
+#header #nom_site_spip {
+       position: absolute;
+       margin: 0; padding: 0;
+       font: normal 42px Georgia, "Times New Roman", Times, serif;
+       letter-spacing: -1.5px;
+       color: #111;
+       text-transform: none;
+       text-decoration: none;
+       
+       /* change the values of top and left to adjust the position of the logo*/
+       top: 22px; left: 20px;  
+}
+#header .accueil img.spip_logos {
+       position: absolute;
+       /* change the values of top and left to adjust the position of the logo*/
+       top: 0px; right: 0px;   
+}
+
+#header #slogan_site_spip {
+       position: absolute;
+       margin: 0; padding: 0;
+       font: normal 12px Georgia, "Times New Roman", Times, serif;
+       text-transform: none;
+       color: #5b4a29;
+       
+       /* change the values of top and left to adjust the position of the slogan*/
+       top: 67px; left: 25px;          
+}
+#descriptif_site_spip {
+       font: normal 12px Georgia, "Times New Roman", Times, serif;
+       text-transform: none;
+       color: #5b4a29;
+}
+
+#header .formulaire_menu_lang { position: absolute; right: 0; top: 250px; display: block; margin:0;width: 235px;padding:0;background:none;border:0; } /*Cf.: spip_formulaires.css*/
+
+/* header links */
+#header #header-links {
+       position: absolute;
+       top: 25px; right: 10px; 
+       color: #5b4a29;
+       font: normal 11px Georgia, "Times New Roman", Times, serif;
+       text-transform: uppercase;              
+}
+#header #header-links a {      
+       color: #5b4a29;
+       text-decoration: none;  
+       padding: 0 2px;
+       font-weight: bold;
+}
+#header #header-links a:hover {
+       color: #111;            
+}
+
+/* header-photo */
+#header-photo {
+       clear: both;
+       background: #fff;
+       margin: 5px auto;
+       padding: 0;             
+       height:206px; 
+       width: 870px;
+}
+#header-photo img {
+       border: none;
+       margin: 0; padding: 0;
+} 
+
+/* Navigation */
+#nav {
+       clear: both;    
+       margin: 0; padding: 0;          
+       height: 45px;   
+}
+#nav .menu-liste {
+       float: left;
+       list-style: none;
+       background: url(img/nav.jpg) repeat-x;
+       width: 870px;           
+       height: 45px;
+       text-transform: uppercase;
+       margin: 0 0 0 15px;
+       padding: 0;     
+       display: inline;
+}
+#nav .menu-liste .menu-entree {
+       display: inline;
+       margin: 0; padding: 0;
+}
+#nav .menu-liste .menu-entree a {
+       display: block;
+       float: left;
+       width: auto;
+       margin: 0;
+       padding: 0 14px;
+       border-right: 1px solid #899D00;
+       border-left: 1px solid #A7D101;
+       font: bold 14px/45px "Century Gothic", "Trebuchet MS", Helvetica, Arial, Geneva, sans-serif;
+       text-transform: uppercase;
+       text-decoration: none;  
+       letter-spacing: 1px;
+       color: #fff;
+}
+#nav .menu-liste .menu-entree a:hover,
+#nav .menu-liste .menu-entree a:active {
+       background: url(img/nav-hover.jpg) repeat-x;
+}
+#nav .menu-liste .menu-entree.on a {
+       background: url(img/nav-current.jpg) repeat-x;
+}
+
+/* sub-menus */
+
+#nav .menu-liste li.menu-entree {
+       display: inline;
+       float: left;
+       position: relative;
+}
+#nav li .menu-liste {
+  background-color: #e5e5e5;
+  background-image: none;
+       position: absolute;
+  display: none;
+  width:255px;
+  top: 36px;
+  left: 0;
+  line-height: 100%;
+  z-index: 5;
+  border: 1px solid #fff;
+  height:auto;
+}
+#nav li .menu-liste .menu-entree {
+       background: url(img/nav.jpg) repeat-x;
+       border-right: none;
+       width: 255px;
+}
+#nav li .menu-liste .menu-entree a {
+       display: block;
+       width: 226px;
+}
+#nav li:hover ul,#nav li.hover ul{display:block;}
+#nav li:hover li ul,#nav li.hover li ul{display:none;}
+#nav li:hover li:hover ul,#nav li.hover li.hover ul{display:block;}
+#nav li:hover li:hover li ul,#nav li.hover li.hover li ul{display:none;}
+#nav li:hover li:hover li:hover ul,#nav li.hover li.hover li.hover ul{display:block;}
+#nav li:hover li:hover li:hover li ul,#nav li.hover li.hover li.hover li ul{display:none;}
+#nav li:hover li:hover li:hover li:hover ul,#nav li.hover li.hover li.hover li.hover ul{display:block;}
+#nav li ul ul{}
+
+
+/* Main Column */
+#main {
+       float: left;
+       width: 550px;
+       padding: 15px 0 0 0; margin: 0 0 0 10px;
+       display: inline;        
+}
+#main .h2 {
+       margin-top: 10px;
+       padding-bottom: 3px;
+       font: normal 2.3em 'Trebuchet MS', Tahoma, Sans-serif;
+       color: #895F30; 
+       letter-spacing: -1px;   
+       text-transform: none;
+}
+#main .h2 a {
+       color: #895F30; 
+       text-decoration: none;  
+}
+#main ul.spip li {
+       list-style-image: url(img/bullet.gif);
+}
+
+/* Sidebar */  
+#sidebar {
+       float: right;
+       width: 280px;
+       padding: 25px 0 0 0; margin: 0;         
+}      
+#sidebar .h2,
+#sidebar .formulaire_recherche label {
+       margin-top: 10px;
+       padding: 5px 5px;
+       font: normal 1.6em 'Trebuchet MS', Tahoma, Sans-serif;
+       color: #899B0D;
+       line-height:100%;
+}
+
+#sidebar .menu ul {
+}
+#sidebar .menu ul li {
+}
+#sidebar .menu ul li a {
+}
+#sidebar .menu ul li a:hover { 
+}
+
+/* footer */
+#footer-wrap {
+       clear: both;
+       width: 900px;
+       font-size: 95%; 
+       text-align: left;
+       padding: 15px 0;                
+       border-bottom: 15px solid #fff;
+       border-top: 1px solid #fff;
+}
+#footer-wrap a:hover {
+       color: #000;    
+}
+#footer-wrap .h3 {
+       color: #976834;  
+       margin: 0;
+       padding: 0 10px; 
+       text-transform: uppercase;
+       font-weight: bold;
+
+line-height:100%;}
+
+#footer-content {
+       color: #888;
+       margin: 0 auto; 
+       padding: 0;     
+       width: 840px;                   
+}
+#footer-content a {
+       text-decoration: none;
+       font-weight: bold;
+       color: #666666;
+}
+/*
+#footer-content ul {
+       list-style: none;
+       margin: 10px 0 0 0; 
+       padding: 0;     
+       border-top: 1px solid #e5e5e5;
+}
+#footer-content li {
+       border-bottom: 1px solid #e5e5e5;       
+}
+#footer-content li a {
+       display: block;
+       font-weight: normal;
+       padding: 5px 0 5px 10px;
+       width: 96%;
+}
+#footer-content .col3, .col3-center {
+       float: left;
+       width: 32%;
+}
+#footer-content .col3-center { 
+       margin: 0 15px; 
+}
+*/
+/* bottom */
+#footer-bottom {
+       clear: both;
+       color: #666;    
+       margin: 0 auto; 
+       width: 870px;
+       padding: 15px 0 0 0;
+       text-align: center;     
+}
+#footer-bottom  a {
+       color: #976834;
+}
+
+
+/* Listes d'articles et extraits introductifs */
+.articles ul li { clear: both; padding: 0.40em 0.20em; }
+.articles ul li h3 { margin: 0.30em 0; }
+.articles .spip_logos { float: right; clear: right; margin: 0 0 4px 16px; }
+.articles ul li .enclosures { float: right; text-align: right; max-width: 60%; margin: 0; }
+.articles ul li .introduction { margin-top: 0.30em; line-height: 1.40em; }
+
+/* postmeta */
+.meta-publi {
+       padding: 5px; margin: 20px 0 15px;
+       font-size: 95%;
+       color: #99997D;
+       border: 1px solid #EAE7DB;
+       background: #FAFAE7;
+       clear:both;
+}
+.meta-publi .date-redac { margin: 0 10px 0 5px;        }
+.meta-publi .nb_commentaires { margin: 0 10px 0 5px;   }
+.meta-publi .lire-la-suite { margin: 0 10px 0 5px;     }
+
+.info-publi { font-size: .95em;        padding-top: 0; margin-left: 1px;       }
+.h3+.info-publi {margin-top:-10px;}
diff --git a/www/themes/theme_Outdoor1-0/img/Outdoor.css b/www/themes/theme_Outdoor1-0/img/Outdoor.css
new file mode 100644 (file)
index 0000000..73f67bf
--- /dev/null
@@ -0,0 +1,483 @@
+/********************************************\r
+   AUTHOR:                     Erwin Aligam \r
+   WEBSITE:                    http://www.styleshout.com/\r
+       TEMPLATE NAME:          Outdoor\r
+   TEMPLATE CODE:      S-0020\r
+   VERSION:          1.0               \r
+ *******************************************/\r
\r
+/********************************************\r
+   HTML ELEMENTS\r
+********************************************/ \r
+\r
+/* Top Elements */\r
+* { margin: 0; padding: 0; outline: 0 }\r
+\r
+body {\r
+       background: #f7f0e3 url(bg.jpg) repeat-x;\r
+       font: 70%/1.6em Verdana, Tahoma, Arial, Geneva, sans-serif;\r
+       color: #666666; \r
+       text-align: center;\r
+       margin: 0 0 50px 0;\r
+}\r
+\r
+/* links */\r
+a, a:visited { \r
+       color: #5A93C9;\r
+       background: inherit;\r
+       text-decoration: none;  \r
+}\r
+a:hover {\r
+       color: #88ac0b;\r
+       background: inherit;\r
+       text-decoration: underline;     \r
+}\r
+\r
+/* headers */\r
+h1, h2, h3 {\r
+       font-family: 'Trebuchet MS', Tahoma, Sans-serif;\r
+       color: #444;\r
+}\r
+h1 {\r
+       font-size: 230%;        \r
+       font-weight: normal;\r
+       letter-spacing: -1px;\r
+}\r
+h2 {\r
+       font-size: 180%;\r
+       color: #88ac0b;\r
+}\r
+h3 {\r
+       font-size: 150%;        \r
+       font-weight: normal;    \r
+}\r
+\r
+h1, h2, h3, p {\r
+       padding: 10px;          \r
+       margin: 0;\r
+}\r
+ul, ol {\r
+       margin: 5px 20px;\r
+       padding: 0 20px;\r
+}\r
+ul {\r
+       list-style: none;\r
+}\r
+\r
+/* images */\r
+img {\r
+       background: #fafafa;\r
+   border: 1px solid #dcdcdc;\r
+       padding: 5px;\r
+}\r
+img.float-right {\r
+       margin: 5px 0px 10px 10px;  \r
+}\r
+img.float-left {\r
+       margin: 5px 10px 10px 0px;\r
+}\r
+\r
+code {\r
+       margin: 5px 0;\r
+       padding: 10px;\r
+       text-align: left;\r
+       display: block;\r
+       overflow: auto;  \r
+       font: 500 1em/1.5em 'Lucida Console', 'courier new', monospace ;\r
+       /* white-space: pre; */\r
+       border: 1px solid #F4F3EC; \r
+       background: #FAFAE7;  \r
+}\r
+acronym {\r
+  cursor: help;\r
+  border-bottom: 1px dashed #777;\r
+}\r
+blockquote {\r
+       margin: 10px;\r
+       padding: 0 0 0 35px;  \r
+   border: 1px solid #F4F3EC; \r
+       background: #FAFAE7 url(quote.jpg) no-repeat 7px 10px; \r
+       font: bold 1.3em/1.5em 'Trebuchet MS', Tahoma, Sans-serif;\r
+       color: #976957;\r
+}\r
+\r
+/* start - table */\r
+table {\r
+       border-collapse: collapse;\r
+       margin: 10px;   \r
+}\r
+th strong {\r
+       color: #fff;\r
+}\r
+th {\r
+       background: #93BC0C url(nav.jpg) repeat-x;\r
+       height: 35px;\r
+       padding-left: 12px;\r
+       padding-right: 12px;\r
+       color: #fff;\r
+       text-align: left;\r
+       border-left: 1px solid #B6D59A;\r
+       border-bottom: solid 2px #fff;\r
+}\r
+tr {\r
+       height: 32px;\r
+}\r
+td {\r
+       padding-left: 11px;\r
+       padding-right: 11px;\r
+       border-left: 1px solid #fff;\r
+       border-bottom: 1px solid #fff;\r
+}\r
+td.first,th.first {\r
+       border-left: 0px;\r
+}\r
+tr.row-a {\r
+       background: #F8F8F8;\r
+}\r
+tr.row-b {\r
+       background: #EFEFEF;            \r
+}\r
+/* end - table */\r
+\r
+/* form elements */\r
+form {\r
+       margin:10px; padding: 0 5px;\r
+       border: 1px solid #f1f1f1; \r
+       background-color: #f5f5f5;      \r
+}\r
+label {\r
+       display:block;\r
+       font-weight:bold;\r
+       margin:5px 0;\r
+}\r
+input {\r
+       padding:2px;\r
+       border:1px solid #eee;\r
+       font: normal 1em Verdana, sans-serif;\r
+       color:#777;\r
+}\r
+textarea {\r
+       width:400px;\r
+       padding:2px;\r
+       font: normal 1em Verdana, sans-serif;\r
+       border:1px solid #eee;\r
+       height:100px;\r
+       display:block;\r
+       color:#777;\r
+}\r
+input.button { \r
+       font: bold 12px Arial, Sans-serif; \r
+       height: 24px;\r
+       margin: 0;\r
+       padding: 2px 3px; \r
+       color: #FFF;\r
+       background: #8EB50C url(nav.jpg) repeat-x 0 0;\r
+       border: 1px solid #88AD0C;\r
+}\r
+\r
+/* search form */\r
+.searchform {\r
+       background-color: transparent;\r
+       border: none;   \r
+       margin: 0; padding: 5px 0 15px 0;       \r
+       width: 250px;   \r
+}\r
+.searchform p { margin: 0; padding: 0; }\r
+.searchform input.textbox { \r
+       width: 170px;\r
+       color: #777; \r
+       height: 18px;\r
+       padding: 2px;   \r
+       border: 1px solid #E5E5E5;\r
+       vertical-align: top;\r
+}\r
+.searchform input.button { \r
+       width: 60px;\r
+       height: 24px;\r
+       padding: 2px 5px;\r
+       vertical-align: top;\r
+}\r
+\r
+/********************************************\r
+   LAYOUT\r
+********************************************/ \r
+#wrap {\r
+       position: relative;\r
+       background: #fff url(wrap-bg.jpg) repeat-y;\r
+       width: 900px;   \r
+       margin: 50px auto 0 auto;\r
+       text-align: left;\r
+}\r
+#content-wrap {\r
+       position: relative;\r
+       background: #fff url(content-bg.jpg) repeat-x;\r
+       clear: both;\r
+       float: left;    \r
+       width: 870px;   \r
+       padding: 0;                     \r
+       margin-left: 15px;      \r
+       display: inline;\r
+       border-top: 5px solid #fff;\r
+       border-bottom: 1px solid #e5e5e5;\r
+       border-left: 1px solid #fff;\r
+       border-right: 1px solid #fff;\r
+}\r
+#header {\r
+       position: relative;\r
+       background: #fff url(header-bg.jpg) repeat-x;\r
+       width: 870px;   \r
+       height: 100px;  \r
+       padding: 0;     \r
+       margin: 0px auto;\r
+}\r
+#header h1#logo-text a {\r
+       position: absolute;\r
+       margin: 0; padding: 0;\r
+       font: normal 42px Georgia, "Times New Roman", Times, serif;\r
+       letter-spacing: -1.5px;\r
+       color: #111;\r
+       text-transform: none;\r
+       text-decoration: none;\r
+       \r
+       /* change the values of top and left to adjust the position of the logo*/\r
+       top: 22px; left: 20px;  \r
+}\r
+#header p#slogan {\r
+       position: absolute;\r
+       margin: 0; padding: 0;\r
+       font: normal 12px Georgia, "Times New Roman", Times, serif;\r
+       text-transform: none;\r
+       color: #5b4a29;\r
+       \r
+       /* change the values of top and left to adjust the position of the slogan*/\r
+       top: 67px; left: 25px;          \r
+}\r
+\r
+/* header links */\r
+#header #header-links {\r
+       position: absolute;\r
+       top: 25px; right: 10px; \r
+       color: #5b4a29;\r
+       font: normal 11px Georgia, "Times New Roman", Times, serif;\r
+       text-transform: uppercase;              \r
+}\r
+#header #header-links a {      \r
+       color: #5b4a29;\r
+       text-decoration: none;  \r
+       padding: 0 2px;\r
+       font-weight: bold;\r
+}\r
+#header #header-links a:hover {\r
+       color: #111;            \r
+}\r
+\r
+/* header-photo */\r
+#header-photo {\r
+       clear: both;\r
+       background: #fff;\r
+       margin: 5px auto;\r
+       padding: 0;             \r
+       height:206px; \r
+       width: 870px;\r
+}\r
+#header-photo img {\r
+       border: none;\r
+       margin: 0; padding: 0;\r
+} \r
+\r
+/* Navigation */\r
+#nav {\r
+       clear: both;    \r
+       margin: 0; padding: 0;          \r
+       height: 45px;   \r
+}\r
+#nav ul {\r
+       float: left;\r
+       list-style: none;\r
+       background: url(nav.jpg) repeat-x;      \r
+       width: 870px;           \r
+       height: 45px;\r
+       text-transform: uppercase;\r
+       margin: 0 0 0 15px;\r
+       padding: 0;     \r
+       display: inline;\r
+}\r
+#nav ul li {\r
+       display: inline;\r
+       margin: 0; padding: 0;\r
+}\r
+#nav ul li a {\r
+       display: block;\r
+       float: left;\r
+       width: auto;\r
+       margin: 0;\r
+       padding: 0 14px;\r
+       border-right: 1px solid #899D00;\r
+       border-left: 1px solid #A7D101;\r
+       font: bold 14px/45px "Century Gothic", "Trebuchet MS", Helvetica, Arial, Geneva, sans-serif;\r
+       text-transform: uppercase;\r
+       text-decoration: none;  \r
+       letter-spacing: 1px;\r
+       color: #fff;\r
+}\r
+#nav ul li a:hover, \r
+#nav ul li a:active {\r
+       background: url(nav-hover.jpg) repeat-x;        \r
+}\r
+#nav ul li#current a { \r
+       background: url(nav-current.jpg) repeat-x;      \r
+}\r
+\r
+/* Main Column */\r
+#main {\r
+       float: left;\r
+       width: 550px;\r
+       padding: 15px 0 0 0; margin: 0 0 0 10px;\r
+       display: inline;        \r
+}\r
+#main h2 {\r
+       margin-top: 10px;\r
+       padding-bottom: 3px;\r
+       font: normal 2.3em 'Trebuchet MS', Tahoma, Sans-serif;\r
+       color: #895F30; \r
+       letter-spacing: -1px;   \r
+       text-transform: none;\r
+}\r
+#main h2 a {\r
+       color: #895F30; \r
+       text-decoration: none;  \r
+}\r
+#main ul li {\r
+       list-style-image: url(bullet.gif);\r
+}\r
+\r
+/* Sidebar */  \r
+#sidebar {\r
+       float: right;\r
+       width: 280px;\r
+       padding: 25px 0 0 0; margin: 0;         \r
+}      \r
+#sidebar h3 {\r
+       margin-top: 10px;\r
+       padding: 5px 5px; \r
+       font: normal 1.6em 'Trebuchet MS', Tahoma, Sans-serif;  \r
+       color: #899B0D;                         \r
+}\r
+#sidebar ul.sidemenu {\r
+       text-align: left;\r
+       margin: 7px 10px 8px 0px; padding: 0;\r
+       text-decoration: none;          \r
+       border-top: 1px solid #EBEBEB;\r
+}\r
+#sidebar ul.sidemenu li {\r
+       list-style: none;\r
+       border-bottom: 1px solid #EBEBEB;\r
+       padding: 5px 0 5px 5px;\r
+       margin: 0 2px;          \r
+}\r
+* html body #sidebar ul.sidemenu li {\r
+       height: 1%;\r
+}\r
+#sidebar ul.sidemenu li a {\r
+       text-decoration: none;  \r
+       background-image: none; \r
+       color: #895F30;                 \r
+}\r
+#sidebar ul.sidemenu li a:hover {      \r
+       color: #1773BC; \r
+}\r
+#sidebar ul.sidemenu ul { margin: 0 0 0 5px; padding: 0; }\r
+#sidebar ul.sidemenu ul li { border: none; }\r
+\r
+/* footer */\r
+#footer-wrap {\r
+       clear: both;\r
+       width: 900px;\r
+       font-size: 95%; \r
+       text-align: left;\r
+       padding: 15px 0;                \r
+       border-bottom: 15px solid #fff;\r
+       border-top: 1px solid #fff;\r
+}\r
+#footer-wrap a:hover {\r
+       color: #000;    \r
+}\r
+#footer-wrap h3 {\r
+       color: #976834;  \r
+       margin: 0;\r
+       padding: 0 10px; \r
+       text-transform: uppercase;\r
+       font-weight: bold;\r
+}\r
+\r
+#footer-columns {\r
+       color: #888;\r
+       margin: 0 auto; \r
+       padding: 0;     \r
+       width: 840px;                   \r
+}\r
+#footer-columns a {\r
+       text-decoration: none;\r
+       font-weight: bold;\r
+       color: #666666;\r
+}\r
+#footer-columns ul {\r
+       list-style: none;\r
+       margin: 10px 0 0 0; \r
+       padding: 0;     \r
+       border-top: 1px solid #e5e5e5;\r
+}\r
+#footer-columns li {\r
+       border-bottom: 1px solid #e5e5e5;       \r
+}\r
+#footer-columns li a {\r
+       display: block;\r
+       font-weight: normal;\r
+       padding: 5px 0 5px 10px;\r
+       width: 96%;\r
+}\r
+#footer-columns .col3, .col3-center {\r
+       float: left;\r
+       width: 32%;\r
+}\r
+#footer-columns .col3-center { \r
+       margin: 0 15px; \r
+}\r
+\r
+/* bottom */\r
+#footer-bottom {\r
+       clear: both;\r
+       color: #666;    \r
+       margin: 0 auto; \r
+       width: 870px;\r
+       padding: 15px 0 0 0;\r
+       text-align: center;     \r
+}\r
+#footer-bottom  a {\r
+       color: #976834;\r
+}\r
+\r
+/* postmeta */\r
+.postmeta {    \r
+       padding: 5px; margin: 20px 10px 15px 10px;      \r
+       font-size: 95%; \r
+       color: #99997D;\r
+       border: 1px solid #EAE7DB;\r
+       background: #FAFAE7;\r
+}\r
+.postmeta .date{ margin: 0 10px 0 5px; }\r
+.postmeta a.comments { margin: 0 10px 0 5px;   }\r
+.postmeta a.readmore { margin: 0 10px 0 5px;   }\r
+\r
+.post-info { font-size: .95em; padding-top: 0; margin-left: 5px;       }\r
+\r
+/* alignment classes */\r
+.float-left  { float: left; }\r
+.float-right { float: right; }\r
+.align-left  { text-align: left; }\r
+.align-right { text-align: right; }\r
+\r
+/* display and additional classes */\r
+.clear { clear: both; }\r
+\r
+\r
diff --git a/www/themes/theme_Outdoor1-0/img/bg.jpg b/www/themes/theme_Outdoor1-0/img/bg.jpg
new file mode 100644 (file)
index 0000000..952a2f2
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/bg.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/bullet.gif b/www/themes/theme_Outdoor1-0/img/bullet.gif
new file mode 100644 (file)
index 0000000..0ba2421
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/bullet.gif differ
diff --git a/www/themes/theme_Outdoor1-0/img/content-bg.jpg b/www/themes/theme_Outdoor1-0/img/content-bg.jpg
new file mode 100644 (file)
index 0000000..823ae30
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/content-bg.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/header-bg.jpg b/www/themes/theme_Outdoor1-0/img/header-bg.jpg
new file mode 100644 (file)
index 0000000..b78629d
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/header-bg.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/header-photo.jpg b/www/themes/theme_Outdoor1-0/img/header-photo.jpg
new file mode 100644 (file)
index 0000000..55dffc4
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/header-photo.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/image-sample.jpg b/www/themes/theme_Outdoor1-0/img/image-sample.jpg
new file mode 100644 (file)
index 0000000..5d179bc
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/image-sample.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/nav-current.jpg b/www/themes/theme_Outdoor1-0/img/nav-current.jpg
new file mode 100644 (file)
index 0000000..88b689b
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/nav-current.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/nav-hover.jpg b/www/themes/theme_Outdoor1-0/img/nav-hover.jpg
new file mode 100644 (file)
index 0000000..02f71ca
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/nav-hover.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/nav.jpg b/www/themes/theme_Outdoor1-0/img/nav.jpg
new file mode 100644 (file)
index 0000000..467fe98
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/nav.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/quote.jpg b/www/themes/theme_Outdoor1-0/img/quote.jpg
new file mode 100644 (file)
index 0000000..25f10d7
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/quote.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/img/wrap-bg.jpg b/www/themes/theme_Outdoor1-0/img/wrap-bg.jpg
new file mode 100644 (file)
index 0000000..36e50f9
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/img/wrap-bg.jpg differ
diff --git a/www/themes/theme_Outdoor1-0/inc-theme-copyleft.html b/www/themes/theme_Outdoor1-0/inc-theme-copyleft.html
new file mode 100644 (file)
index 0000000..d015646
--- /dev/null
@@ -0,0 +1,3 @@
+<div id="copyleft">
+       <:zpip:conception_graphique_par:> <a href='http://www.styleshout.com/'>styleshout</a> <:zpip:sous_licence:> <a href='http://creativecommons.org/licenses/by/2.5/'>Creative Commons Attribution 2.5 License</a>
+</div>
\ No newline at end of file
diff --git a/www/themes/theme_Outdoor1-0/plugin.xml b/www/themes/theme_Outdoor1-0/plugin.xml
new file mode 100644 (file)
index 0000000..c973a34
--- /dev/null
@@ -0,0 +1,22 @@
+<plugin>\r
+   <nom>Outdoor</nom>\r
+       <auteur>[styleshout->www.styleshout.com], [adapt&#233; pour Zpip par C&#233;dric Morin (yterium.com)->http://www.yterium.com]</auteur>\r
+   <version>1.1.0</version>\r
+       <licence>Creative Commons Attribution 2.5</licence>\r
+       <slogan><multi>\r
+               [en]Rural with header photo Z template\r
+               [fr]Th&#232;me Z champ&#234;tre avec bandeau photo\r
+       </multi></slogan>\r
+       <description><multi>\r
+               [en]A nature based theme design. Has a fixed width, 2 columns layout with a header photo that can be easily changed by one of your own.\r
+               [fr]Un th&#232;me champ&#234;tre. En largeur fixe et 2 colonnes avec un bandeau photo facilement modifiable.\r
+       </multi></description>\r
+       <lien>http://www.spip-contrib.net/OutDoor-1-0</lien>\r
+       <icon>vignette.jpg</icon>\r
+   <etat>stable</etat>\r
+   <prefix>theme_outdoor</prefix>\r
+       <necessite id="SPIP" version="[2.0.10;3.0.99]" />\r
+       <utilise id="Z" version="[1.2.0;]" />\r
+       <bandeau>img/header-photo.jpg</bandeau>\r
+       <categorie>theme</categorie>\r
+</plugin>\r
diff --git a/www/themes/theme_Outdoor1-0/svn.revision b/www/themes/theme_Outdoor1-0/svn.revision
new file mode 100644 (file)
index 0000000..3572c07
--- /dev/null
@@ -0,0 +1,10 @@
+<svn_revision>
+<text_version>
+Origine: file:///home/svn/repository/spip-zone/_themes_/zpip-1/Outdoor1-0
+Revision: 63371
+Dernier commit: 2012-07-10 17:00:33 +0200 
+</text_version>
+<origine>file:///home/svn/repository/spip-zone/_themes_/zpip-1/Outdoor1-0</origine>
+<revision>63371</revision>
+<commit>2012-07-10 17:00:33 +0200 </commit>
+</svn_revision>
\ No newline at end of file
diff --git a/www/themes/theme_Outdoor1-0/vignette.jpg b/www/themes/theme_Outdoor1-0/vignette.jpg
new file mode 100644 (file)
index 0000000..9cc482e
Binary files /dev/null and b/www/themes/theme_Outdoor1-0/vignette.jpg differ