From 3fdad57c33d0cb2f4ced0b933f50451b03908974 Mon Sep 17 00:00:00 2001 From: "ben.spip@gmail.com" <> Date: Sat, 30 May 2009 14:38:35 +0000 Subject: [PATCH] _plugins_/_core_ vers _core_/plugins --- .gitattributes | 38 ++ barre_outils/edition.php | 408 +++++++++++++ barre_outils/forum.php | 33 + barre_outils_icones.css.html | 7 + css/barre_outils.css | 141 +++++ css/images/handle.png | Bin 0 -> 258 bytes css/images/menu.png | Bin 0 -> 27151 bytes css/images/submenu.png | Bin 0 -> 240 bytes icones_barre/clean.png | Bin 0 -> 667 bytes icones_barre/eye.png | Bin 0 -> 750 bytes icones_barre/keyboard.png | Bin 0 -> 570 bytes icones_barre/text_bold.png | Bin 0 -> 304 bytes icones_barre/text_indent.png | Bin 0 -> 353 bytes icones_barre/text_indent_remove.png | Bin 0 -> 351 bytes icones_barre/text_italic.png | Bin 0 -> 223 bytes icones_barre/text_list_bullets.png | Bin 0 -> 344 bytes icones_barre/text_list_numbers.png | Bin 0 -> 357 bytes icones_barre/text_strikethrough.png | Bin 0 -> 269 bytes inc/barre.php | 42 ++ inc/barre_outils.php | 546 +++++++++++++++++ javascript/jquery.markitup.js | 553 +++++++++++++++++ javascript/jquery.markitup_pour_spip.js | 776 ++++++++++++++++++++++++ javascript/jquery.previsu_spip.js | 77 +++ lang/barre_outils_ar.php | 89 +++ lang/barre_outils_en.php | 89 +++ lang/barre_outils_fr.php | 90 +++ markitup/readme.txt | 55 ++ markitup/templates/preview.css | 5 + markitup/templates/preview.html | 11 + plugin.xml | 29 + porte_plume.js.html | 4 + porte_plume.js_fonctions.php | 61 ++ porte_plume_options.php | 20 + porte_plume_pipelines.php | 55 ++ preview.html | 6 + tests/all_tests.php | 12 + tests/barre_outil_markitup.php | 359 +++++++++++ tests/lanceur_spip.php | 36 ++ 38 files changed, 3542 insertions(+) create mode 100644 .gitattributes create mode 100644 barre_outils/edition.php create mode 100644 barre_outils/forum.php create mode 100644 barre_outils_icones.css.html create mode 100644 css/barre_outils.css create mode 100644 css/images/handle.png create mode 100644 css/images/menu.png create mode 100644 css/images/submenu.png create mode 100644 icones_barre/clean.png create mode 100644 icones_barre/eye.png create mode 100644 icones_barre/keyboard.png create mode 100644 icones_barre/text_bold.png create mode 100644 icones_barre/text_indent.png create mode 100644 icones_barre/text_indent_remove.png create mode 100644 icones_barre/text_italic.png create mode 100644 icones_barre/text_list_bullets.png create mode 100644 icones_barre/text_list_numbers.png create mode 100644 icones_barre/text_strikethrough.png create mode 100644 inc/barre.php create mode 100644 inc/barre_outils.php create mode 100644 javascript/jquery.markitup.js create mode 100644 javascript/jquery.markitup_pour_spip.js create mode 100644 javascript/jquery.previsu_spip.js create mode 100644 lang/barre_outils_ar.php create mode 100644 lang/barre_outils_en.php create mode 100644 lang/barre_outils_fr.php create mode 100644 markitup/readme.txt create mode 100644 markitup/templates/preview.css create mode 100644 markitup/templates/preview.html create mode 100644 plugin.xml create mode 100644 porte_plume.js.html create mode 100644 porte_plume.js_fonctions.php create mode 100644 porte_plume_options.php create mode 100644 porte_plume_pipelines.php create mode 100644 preview.html create mode 100644 tests/all_tests.php create mode 100644 tests/barre_outil_markitup.php create mode 100644 tests/lanceur_spip.php diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9587a51 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,38 @@ +* text=auto !eol +barre_outils/edition.php -text +barre_outils/forum.php -text +/barre_outils_icones.css.html -text +css/barre_outils.css -text +css/images/handle.png -text +css/images/menu.png -text +css/images/submenu.png -text +icones_barre/clean.png -text +icones_barre/eye.png -text +icones_barre/keyboard.png -text +icones_barre/text_bold.png -text +icones_barre/text_indent.png -text +icones_barre/text_indent_remove.png -text +icones_barre/text_italic.png -text +icones_barre/text_list_bullets.png -text +icones_barre/text_list_numbers.png -text +icones_barre/text_strikethrough.png -text +inc/barre.php -text +inc/barre_outils.php -text +javascript/jquery.markitup.js -text +javascript/jquery.markitup_pour_spip.js -text +javascript/jquery.previsu_spip.js -text +lang/barre_outils_ar.php -text +lang/barre_outils_en.php -text +lang/barre_outils_fr.php -text +markitup/readme.txt -text +markitup/templates/preview.css -text +markitup/templates/preview.html -text +/plugin.xml -text +/porte_plume.js.html -text +/porte_plume.js_fonctions.php -text +/porte_plume_options.php -text +/porte_plume_pipelines.php -text +/preview.html -text +tests/all_tests.php -text +tests/barre_outil_markitup.php -text +tests/lanceur_spip.php -text diff --git a/barre_outils/edition.php b/barre_outils/edition.php new file mode 100644 index 0000000..89c3c2e --- /dev/null +++ b/barre_outils/edition.php @@ -0,0 +1,408 @@ + 'edition', + #'previewAutoRefresh'=> true, + #'previewParserPath' => url_absolue(generer_url_public('preview')), + 'onShiftEnter' => array('keepDefault'=>false, 'replaceWith'=>"\n_ "), + 'onCtrlEnter' => array('keepDefault'=>false, 'replaceWith'=>"\n\n"), + // garder les listes si on appuie sur entree + 'onEnter' => array('keepDefault'=>false, 'selectionType'=>'return', 'replaceWith'=>"\n"), + 'onTab' => array('keepDefault'=>false, 'replaceWith'=>"\t"), + 'markupSet' => array( + // H1 - {{{ + array( + "id" => 'header1', + "name" => _T('barre_outils:barre_intertitre'), + "key" => "H", + "className" => "outil_header1", + "openWith" => "\n{{{", + "closeWith" => "}}}\n", + "display" => true, + "selectionType" => "line", + ), + // Bold - {{ + array( + "id" => 'bold', + "name" => _T('barre_outils:barre_gras'), + "key" => "B", + "className" => "outil_bold", + "openWith" => "{{", + "closeWith" => "}}", + "display" => true, + "selectionType" => "word", + ), + // Italic - { + array( + "id" => 'italic', + "name" => _T('barre_outils:barre_italic'), + "key" => "I", + "className" => "outil_italic", + "openWith" => "{", + "closeWith" => "}", + "display" => true, + "selectionType" => "word", + ), + + // montrer une suppression + array( + "id" => 'stroke_through', + "name" => _T('barre_outils:barre_barre'), // :-) + "className" => "outil_stroke_through", + "openWith" => "", + "closeWith" => "", + "display" => true, + "selectionType" => "word", + ), + + // listes -* + array( + "id" => 'liste_ul', + "name" => _T('barre_outils:barre_liste_ul'), + "className" => "outil_liste_ul", + "replaceWith" => "function(h){ return outil_liste(h, '*');}", + "display" => true, + "selectionType" => "line", + "forceMultiline" => true, + "dropMenu" => array( + // liste -# + array( + "id" => 'liste_ol', + "name" => _T('barre_outils:barre_liste_ol'), + "className" => "outil_liste_ol", + "replaceWith" => "function(h){ return outil_liste(h, '#');}", + "display" => true, + "selectionType" => "line", + "forceMultiline" => true, + ), + // indenter + array( + "id" => 'indenter', + "name" => _T('barre_outils:barre_indenter'), + "className" => "outil_indenter", + "replaceWith" => "function(h){return outil_indenter(h);}", + "display" => true, + "selectionType" => "line", + "forceMultiline" => true, + ), + // desindenter + array( + "id" => 'desindenter', + "name" => _T('barre_outils:barre_desindenter'), + "className" => "outil_desindenter", + "replaceWith" => "function(h){return outil_desindenter(h);}", + "display" => true, + "selectionType" => "line", + "forceMultiline" => true, + ), + ), + ), + + + + // separation + array( + "id" => "sepLink", // trouver un nom correct ! + "separator" => "---------------", + "display" => true, + ), + // lien spip + array( + "id" => 'link', + "name" => _T('barre_outils:barre_lien'), + "key" => "L", + "className" => "outil_link", + "openWith" => "[", + "closeWith" => "->[!["._T('barre_outils:barre_lien_input')."]!]]", + "display" => true, + ), + // note en bas de page spip + array( + "id" => 'notes', + "name" => _T('barre_outils:barre_note'), + "className" => "outil_notes", + "openWith" => "[[", + "closeWith" => "]]", + "display" => true, + "selectionType" => "word", + ), + + // separation + // (affichee dans forum) + array( + "id" => "sepCitations", // trouver un nom correct ! + "separator" => "---------------", + "display" => false, + ), + // quote spip + // (affichee dans forum) + array( + "id" => 'quote', + "name" => _T('barre_outils:barre_quote'), + "key" => "Q", + "className" => "outil_quote", + "openWith" => "\n", + "closeWith" => "\n", + "display" => false, + "selectionType" => "word", + ), + + // separation + array( + "id" => "sepGuillemets", + "separator" => "---------------", + "display" => true, + ), + // guillemets + array( + "id" => 'guillemets', + "name" => _T('barre_outils:barre_guillemets'), + "className" => "outil_guillemets", + "openWith" => "«", + "closeWith" => "»", + "display" => true, + "lang" => array('fr','eo','cpf','ar','es'), + "selectionType" => "word", + ), + // guillemets internes + array( + "id" => 'guillemets_simples', + "name" => _T('barre_outils:barre_guillemets_simples'), + "className" => "outil_guillemets_simples", + "openWith" => "“", + "closeWith" => "”", + "display" => true, + "lang" => array('fr','eo','cpf','ar','es'), + "selectionType" => "word", + ), + // guillemets de + array( + "id" => 'guillemets_de', + "name" => _T('barre_outils:barre_guillemets'), + "className" => "outil_guillemets_de", + "openWith" => "„", + "closeWith" => "“", + "display" => true, + "lang" => array('bg','de','pl','hr','src'), + "selectionType" => "word", + ), + // guillemets de, simples + array( + "id" => 'guillemets_de_simples', + "name" => _T('barre_outils:barre_guillemets_simples'), + "className" => "outil_guillemets_de_simples", + "openWith" => "‚", + "closeWith" => "‘", + "display" => true, + "lang" => array('bg','de','pl','hr','src'), + "selectionType" => "word", + ), + // guillemets autres langues + array( + "id" => 'guillemets_autres', + "name" => _T('barre_outils:barre_guillemets'), + "className" => "outil_guillemets_simples", + "openWith" => "“", + "closeWith" => "”", + "display" => true, + "lang_not" => array('fr','eo','cpf','ar','es','bg','de','pl','hr','src'), + "selectionType" => "word", + ), + // guillemets simples, autres langues + array( + "id" => 'guillemets_autres_simples', + "name" => _T('barre_outils:barre_guillemets_simples'), + "className" => "outil_guillemets_uniques", + "openWith" => "‘", + "closeWith" => "’", + "display" => true, + "lang_not" => array('fr','eo','cpf','ar','es','bg','de','pl','hr','src'), + "selectionType" => "word", + ), + + // separation + array( + "id" => "sepCaracteres", + "separator" => "---------------", + "display" => true, + ), + // icones clavier + array( + "id" => 'grpCaracteres', + "name" => _T('barre_outils:barre_inserer_caracteres'), + "className" => 'outil_caracteres', + "display" => true, + + "dropMenu" => array( + // A majuscule accent grave + array( + "id" => 'A_grave', + "name" => _T('barre_outils:barre_a_accent_grave'), + "className" => "outil_a_maj_grave", + "replaceWith" => "À", + "display" => true, + "lang" => array('fr','eo','cpf'), + ), + // E majuscule accent aigu + array( + "id" => 'E_aigu', + "name" => _T('barre_outils:barre_e_accent_aigu'), + "className" => "outil_e_maj_aigu", + "replaceWith" => "É", + "display" => true, + "lang" => array('fr','eo','cpf'), + ), + // oe + array( + "id" => 'oe', + "name" => _T('barre_outils:barre_eo'), + "className" => "outil_oe", + "replaceWith" => "œ", + "display" => true, + "lang" => array('fr'), + ), + // OE + array( + "id" => 'OE', + "name" => _T('barre_outils:barre_eo_maj'), + "className" => "outil_oe_maj", + "replaceWith" => "Œ", + "display" => true, + "lang" => array('fr'), + ), + ), + ), + + + // separation + array( + "id" => "sepPreview", // trouver un nom correct ! + "separator" => "---------------", + "display" => true, + ), + // clean + array( + "id" => 'clean', + "name" => _T('barre_outils:barre_clean'), + "className" => "outil_clean", + "replaceWith" => 'function(markitup) { return markitup.selection.replace(/<(.*?)>/g, "") }', + "display" => true, + ), + // preview + array( + "id" => 'preview', + "name" => _T('barre_outils:barre_preview'), + "className" => "outil_preview", + "call" => "preview", + "display" => true, + ), + + + ), + + 'functions' => " + // remplace ou cree -* ou -** ou -# ou -## + function outil_liste(h, c) { + if ((s = h.selection) && (r = s.match(/^-([*#]+) (.*)\$/))) { + r[1] = r[1].replace(/[#*]/g, c); + s = '-'+r[1]+' '+r[2]; + } else { + s = '-' + c + ' '+s; + } + return s; + } + + // indente des -* ou -# + function outil_indenter(h) { + if (s = h.selection) { + if (s.substr(0,2)=='-*') { + s = '-**' + s.substr(2); + } else if (s.substr(0,2)=='-#') { + s = '-##' + s.substr(2); + } else { + s = '-* ' + s; + } + } + return s; + } + + // desindente des -* ou -** ou -# ou -## + function outil_desindenter(h){ + if (s = h.selection) { + if (s.substr(0,3)=='-**') { + s = '-*' + s.substr(3); + } else if (s.substr(0,3)=='-* ') { + s = s.substr(3); + } else if (s.substr(0,3)=='-##') { + s = '-#' + s.substr(3); + } else if (s.substr(0,3)=='-# ') { + s = s.substr(3); + } + } + return s; + } + ", + )); + + $set->cacher(array( + 'stroke_through', + 'clean', 'preview', + )); + + return $set; +} + + + +/** + * Definitions des liens entre css et icones + */ +function barre_outils_edition_icones(){ + return array( + //'outil_header1' => 'text_heading_1.png', + 'outil_header1' => 'intertitre.png', + 'outil_bold' => 'text_bold.png', + 'outil_italic' => 'text_italic.png', + + 'outil_stroke_through' => 'text_strikethrough.png', + + 'outil_liste_ul' => 'text_list_bullets.png', + 'outil_liste_ol' => 'text_list_numbers.png', + 'outil_indenter' => 'text_indent.png', + 'outil_desindenter' => 'text_indent_remove.png', + + //'outil_quote' => 'text_indent.png', + 'outil_quote' => 'quote.png', + + //'outil_link' => 'world_link.png', + 'outil_link' => 'lien.png', + 'outil_notes' => 'notes.png', + + 'outil_guillemets' => 'guillemets.png', + 'outil_guillemets_simples' => 'guillemets-simples.png', + 'outil_guillemets_de' => 'guillemets-de.png', + 'outil_guillemets_de_simples' => 'guillemets-uniques-de.png', + 'outil_guillemets_uniques' => 'guillemets-uniques.png', + + 'outil_caracteres' => 'keyboard.png', + 'outil_a_maj_grave' => 'agrave-maj.png', + 'outil_e_maj_aigu' => 'eacute-maj.png', + 'outil_oe' => 'oelig.png', + 'outil_oe_maj' => 'oelig-maj.png', + + 'outil_clean' => 'clean.png', + 'outil_preview' => 'eye.png', + ); +} +?> diff --git a/barre_outils/forum.php b/barre_outils/forum.php new file mode 100644 index 0000000..4168dc0 --- /dev/null +++ b/barre_outils/forum.php @@ -0,0 +1,33 @@ +nameSpace = 'forum'; + $barre->cacherTout(); + $barre->afficher(array( + 'bold','italic', + 'sepLink','link', + 'sepCitations', 'quote', + 'sepCaracteres','guillemets', 'guillemets_simples', + 'guillemets_de', 'guillemets_de_simples', + 'guillemets_autres', 'guillemets_autres_simples', + 'A_grave', 'E_aigu', 'oe', 'OE', + )); + return $barre; +} + + +?> diff --git a/barre_outils_icones.css.html b/barre_outils_icones.css.html new file mode 100644 index 0000000..122a67c --- /dev/null +++ b/barre_outils_icones.css.html @@ -0,0 +1,7 @@ +#CACHE{7*24*3600} +#HTTP_HEADER{Content-Type: text/css; charset=utf-8} +#HTTP_HEADER{Vary: Accept-Encoding} +[(#VAL|barre_outils_css_icones)] + +/* roue ajax */ +.ajaxLoad{background:white url('[(#CHEMIN{images/searching.gif}|url_absolue)]') top left no-repeat;} diff --git a/css/barre_outils.css b/css/barre_outils.css new file mode 100644 index 0000000..a7aa1e0 --- /dev/null +++ b/css/barre_outils.css @@ -0,0 +1,141 @@ +.formulaire_spip textarea.markItUpEditor { +width:96%; /* reduire la taille par defaut des formulaires spip */ +} + + +/* ------------------------------------------------------------------- +// markItUp! Universal MarkUp Engine, JQuery plugin +// By Jay Salvat - http://markitup.jaysalvat.com/ +// ------------------------------------------------------------------*/ + +.markItUp .markItUpHeader a, +.markItUp .markItUpTabs a, +.markItUp .markItUpFooter a { + color:#000; + text-decoration:none; +} +.markItUp { + margin:5px 0 5px 0; + clear:both; +} +.markItUp .markItUpContainer { + margin:0px; padding:0px; +} +.markItUp .markItUpEditor { + padding:5px; + height:320px; /* la hauteur est calculee par SPIP */ + clear:both; display:block; + overflow:auto; +} +.markItUp .markItUpPreviewFrame {} +.markItUp .markItUpFooter { + margin:0px; padding:0px; + width:100%; +} +.markItUp .markItUpResizeHandle { + overflow:hidden; + width:22px; height:5px; + margin-left:auto; + margin-right:auto; + background-image:url(images/handle.png); + cursor:ns-resize; +} + +/***************************/ +/* tabs */ +.markItUp .markItUpTabs { + text-align:right; margin-bottom:3px; padding:1px 1px 0; + border-bottom:1px solid #888; overflow:hidden; + width:auto; float:right; clear:both;} +.markItUp .markItUpTabs a { + display:block; float:right; border:1px solid #888; margin:0px 1px; border-bottom:none; + padding:3px 4px 2px 4px; background:#f0f0f0; + -moz-border-radius:5px 5px 0 0;-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;} +.markItUp .markItUpTabs a.on {background:#fff; } +.markItUp .markItUpTabs a:hover {background:#fff;} + +/***************************/ +/* previsu */ +.markItUp .markItUpPreview { + clear:both; + border:1px solid #888; + background:#fff; + overflow:auto; + padding:1em; +} + +/* correction des styles spip_formulaires appliques par defaut (grr) */ +.markItUp .preview p {margin-bottom:1em;} +.markItUp .preview ul {margin-bottom:1em; margin-top:0.5em;} +.markItUp .preview li {border:none; padding:1px;} +/* coloration code */ +.markItUp .preview .cadre ol, +.markItUp .preview .cadre ul {padding:0.5em;} + + +/***************************************************************************************/ +/* first row of buttons */ +.markItUp .markItUpHeader { margin:0px; padding:0px;} +.markItUp .markItUpHeader ul li { + list-style:none; + float:left; + position:relative; + clear:none; + border:0; + margin:0; + padding:0; + overflow:visible; +} +.markItUp .markItUpHeader ul li:first-child { /* annuler un reglage des forms prive */ + padding-top:0; +} + +.markItUp .markItUpHeader ul .markItUpDropMenu { + /*background:inherit url(images/menu.png) no-repeat 100% 80%; + padding-right:10px;*/ +} +.markItUp .markItUpHeader ul .markItUpDropMenu li { + margin-right:0px; + background-color: #eee; + padding:2px 1px 2px 0; +} +.markItUp .markItUpHeader ul .markItUpDropMenu li:first-child{padding-left:2px;} + +/* next rows of buttons */ +.markItUp .markItUpHeader ul ul { + display:none; + position:absolute; + top:24px; left:-2px; + width:150px; +} +.markItUp .markItUpHeader ul ul li { + float:left; +} +.markItUp .markItUpHeader ul ul .markItUpDropMenu { + background:#F5F5F5 url(images/submenu.png) no-repeat 50% 50%; +} +.markItUp .markItUpHeader ul .markItUpSeparator { + margin:0 6px; + width:0px; + height:16px; + overflow:hidden; +} +.markItUp .markItUpHeader ul ul .markItUpSeparator { + width:auto; height:1px; + margin:0px; +} + +.markItUp .markItUpHeader ul a { + display:block; + width:16px; height:16px; + text-indent:-10000px; + background-repeat:no-repeat; + background-position:50% 50%; + background-color:#f5f5f5; + border:1px solid #ccc; + padding:3px; + margin-right:1px; +} +.markItUp .markItUpHeader ul a:hover{border:1px solid #888; background-color:#fff;} + + diff --git a/css/images/handle.png b/css/images/handle.png new file mode 100644 index 0000000000000000000000000000000000000000..3993b20337e33a36c9125d139f1f53a279a4c128 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^qCm{X#0(?@t!)i}6mzkYX9x!e$L)vy4}e^r0G|-o z4LkP#|NsB{_wSo_?oZ!X{TC?CQWE4B{GZ|f|H~VSrU3bz1s;*b3=G^tAk28_ZrvZC zpje4(M2T}zYGO%dex5=|W^O8jfw{hsp}v86ds2l5P=!25MR0yvNqJ&XDuZuga#4P6 zYD#9Jf?H-$YI%N9cCmuR){ILPK&1wrE{-7_Gm{H=1WS1m6Eb=Pa(faIBBVrjnVf1= soMNglKFuA6ghUcX`bbD&-ZPgg&ebxsLQ0Hz~TmH+?% literal 0 HcmV?d00001 diff --git a/css/images/menu.png b/css/images/menu.png new file mode 100644 index 0000000000000000000000000000000000000000..44a07afd30f499cdba30847094a1e92f13e1320e GIT binary patch literal 27151 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

+35?Hj$O) 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 literal 0 HcmV?d00001 diff --git a/icones_barre/clean.png b/icones_barre/clean.png new file mode 100644 index 0000000000000000000000000000000000000000..7e7cefb8e174c738a84f8f3a6bf15d8e8f2c66d1 GIT binary patch literal 667 zcmV;M0%ZM(P)LlS^n5Q5c2KWM*m}YV3eAws|yDY&wl?DsIf8f*>k% z<*Hc~7ec_5rHi-`yO3f)SBkFeMi8|t(GpA*#H3ciSWBp+c{r^&PVFO&3C&}i$+#MA zZCZ-`mgm3cyWAfxp=la+gJD~$f3lF*v;Jqx`Q8T$Z@WYD zo5ULg-eG}Z89L0f4Zd=*mecc6xt8;=w2x)zu;*%)sVnHZF8Gfgv50&V?aO?Vg=C`G zqt8;QwVsqD3w#sp>uk4(?#r`&eMV@ShR&fc4IOUt64yxY7gl5?KAAs}zQf1Y-^2&g z$Gu&9-`V$(R7R2uQ}2HsoE!1T1^`G5aq_1Rg+NBCRv6kqwQ}ZBXMdtuFS`d*&78wH z%FqTXD^)8WCsqSp-l}5wzGHH~3TMv4``ZJRQO3=(w6oCI`;E z`gMDg;9p*xrm`moLYyi48W1M{s};+X6Y)q)IQvrJsBPN-$Qt1?9(Dn}gMTvW8Vj;U zv~1YHR;Z*VmZrvRmZz6cE&o6XK(RnVCGj2D!Cx>lhwjfzzEPx#2?dhIYK}l!BvcK! z3)ER+Jz{WW=I5Rl}zuENrQ28Pt;CX(qKOcDU|M8F&Z%jVGSZA7t& zSX&s1bi|{*v*DgAz3ST9+K6Us3~0Q9*~BWe6PID=&0x|wWdf!IWgI(}6lv9v-FpSS zw1U9OL{Ex%ACuJL>=wxTZg0 zEf8`!jsrze5UvA~SqG-HeEY!{P)iC{?3#nq?S616TB~hnMW{0-6j9tLvf?&u+XiC{ z?O_E0jiYQZlqIojGL$5a1qk9N)mlxpmZq1W6gHT`ec`8K>j$jl3}`WfukS z{=!u2#P1a^U!H8Xl5T`7??NT1t zUc_pqB=&-xQ}oxwg~5^6HaUDuDLGXE;y3!@QP_pOFSc-kKKIu gX8xa5{%_a#2W_ovs9z>%07*qoM6N<$f|edvg8%>k literal 0 HcmV?d00001 diff --git a/icones_barre/keyboard.png b/icones_barre/keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..898d402d70c5bd88c168e548e2c2fdad009e1796 GIT binary patch literal 570 zcmV-A0>%A_P)*`a8*+wFR*)hbh_o6Y7qVU;jPxsytzx2T?qC@#N7E3V-W(78^qTtcL0FFmlBz5|hKo6fQCQbi_Vm zg+fR;d%p!KXrNejEi=F1j*`0sM==2=;t{-@ieUG+gr6s6^hxPUntw5hH?N{}R*muG#iOb^}|6b=Y6y(;Y{!a!g z@UQp#@Aw}>L3(}s|7f5BUjeuKZvQRjV<2U7yvu*H{aAbvQ6K!@3oKzW z-{Qa8d3gae1^)HE{~f^!v<1}u>;4xnKvUpW540I-w9J3a{{r=B3T*2g{_BH1CtaZO zpZ`6V0*V5g1e5i;`_=Z#_e=H*@8|93RG@lX;D!K7TKswwko8{x0000A?80v9Z^YZA8as&YaOiG2qAVzYLj+o?N|k`)kPFX7%epMT)pIgD?z$ zz0k7x#eWfQHil2%e>0rE^YzTbTVLW%P1UySD{rve8ZZphV4}^gtsg#oV8j^<1D2Tp2_^}JGDwbz00000NkvXXu0mjfU=gFa literal 0 HcmV?d00001 diff --git a/icones_barre/text_indent_remove.png b/icones_barre/text_indent_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..1651b074ebe5f830c23c909d04ed3282cb8892aa GIT binary patch literal 351 zcmV-l0igbgP)$KO_&&&86Lj*&d?hr!$_C#5QQ<|d}62BjvZR2H60wE-$B^mK6y(Kw&{<9vg>Q9!g~ne(gm zmj4swoA@7?D86%i^8WzK9JM17E&sp&Z#dpHfz$E-U9ks&4?Z9Gyg!%0k2Q{M-Tz#> z2OnD>vrPZ*#{EHKLq)>Jcx{H|Ovdb&|4aQZWSipI{El%e^Cxx{^9vSw28s;a3IDB= TS1%U=TF&6<>gTe~DWM4fm>N^1 literal 0 HcmV?d00001 diff --git a/icones_barre/text_list_bullets.png b/icones_barre/text_list_bullets.png new file mode 100644 index 0000000000000000000000000000000000000000..4a8672bde48f806d3d4d37db192588a9aa3eac10 GIT binary patch literal 344 zcmV-e0jK_nP)PbXFR5;6H z`2YVu10|S&DhA}te_Swi*Xsu$nk)lAnzx?+_#Z@r_~qs0*+Bfiq@?73K|#U)?Ck9S zsi~>|6A}{sM@B~e4-O9gPhA%bd?2RGd{of6>E(lvp1b6Ep>6&12TPB<{a?EDDL4@0 z;^ML+A|n0=1_u83^78uc?CkvC#>VEqiHXU7U0vP(YHDhzff&$ntDt1@;|H#l*M@2! z+U8#>h@W=vfpy*`^1J}j+`sMRe-I7g8yOj8Yin!&S5Z;VicFNp}SURRVGD{CSNFe~ni^^#wyl5uzj4je z|23%2?k#{x(*%mqe9M%mih+W%ElRQ}7!$^91> z7ymCLB=nz$hvz>#JNtiTW@gkt1Zf0eyP_){bPq%T_kY#2Z7&xs00000NkvXXu0mjf DNYA0= literal 0 HcmV?d00001 diff --git a/icones_barre/text_strikethrough.png b/icones_barre/text_strikethrough.png new file mode 100644 index 0000000000000000000000000000000000000000..612058a78eba4e3ca259aa13417fd60cd6cf2fbd GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-%c@9E+gqH#X?$N2_%qkv$?&V++! z-fX$@sb%KG-5a$|R8J4(Tcmu7`G0cYgxS-++3#dN^zA^J(=P8r|6lx9G_LLaZ+v5S z!d9iC@)!RP{FnQmdw#}3Ee(C$|NPA#|L6YmR@fBO9w|C7oMMQ$vc`Tu(RETvC<`(>OPJ!ieM-fH~m>7>j" + . entites_html($texte) + . "\n"; +} + +?> diff --git a/inc/barre_outils.php b/inc/barre_outils.php new file mode 100644 index 0000000..fa43bf5 --- /dev/null +++ b/inc/barre_outils.php @@ -0,0 +1,546 @@ +valeur + */ + function Barre_outils($params=array()){ + foreach ($params as $p=>$v) { + if (isset($this->$p)) { + // si tableau, on verifie les entrees + if (is_array($v)) { + $v = $this->verif_params($p,$v); + } + $this->$p = $v; + } + } + } + + /** + * Verifie que les parametres transmis existent + * et retourne un tableau des parametres valides + * + * @param string $nom : cle du parametre (eventuel) + * @param array $params : parametres du parametre (param->valeur) + */ + function verif_params($nom, $params=array()) { + // si markupset, on boucle sur les items + if (stripos($nom, 'markupSet')!==false) { + foreach ($params as $i=>$v) { + $params[$i] = $this->verif_params($i, $v); + } + } + // sinon on teste la validite + else { + foreach ($params as $p=>$v) { + if (!in_array($p, $this->_liste_params_autorises)) { + unset($params[$p]); + } + } + } + return $params; + } + + /** + * Permet d'affecter des parametres a un element de la barre + * La fonction retourne les parametres, de sorte qu'on peut s'en servir pour simplement recuperer ceux-ci. + * + * Il est possible d'affecter des parametres avant/apres l'element trouve + * en definisant une valeur differente pour le $lieu : 'dedans','avant','apres' + * par defaut 'dedans' (modifie l'element trouve). + * + * Lorsqu'on demande d'inserer avant ou apres, la fonction retourne les parametres inseres + * + * @param string $identifiant : identifiant du bouton a afficher + * @param array $params : parametres a affecter a la trouvaille + * @param string $lieu : lieu d'affectation des parametres (dedans, avant, apres) + * @param false/array $tableau : tableau ou chercher les elements (sert pour la recursion) + */ + function affecter(&$tableau, $identifiant, $params=array(), $lieu='dedans'){ + static $cle_de_recherche = 'id'; // ou className ? + + if ($tableau === null) + $tableau = &$this->markupSet; + + if (!in_array($lieu, array('dedans','avant','apres'))) + $lieu = 'dedans'; + + // present en premiere ligne ? + $trouve = false; + foreach ($tableau as $i=>$v){ + if (isset($v[$cle_de_recherche]) and ($v[$cle_de_recherche] == $identifiant)) { + $trouve = $i; + break; + } + } + // si trouve, affectations + if (($trouve !== false)) { + if ($params) { + $params = $this->verif_params($identifiant, $params); + // dedans on merge + if ($lieu == 'dedans') { + return $tableau[$trouve] = array_merge($tableau[$trouve], $params); + } + // avant ou apres, on insere + elseif ($lieu == 'avant') { + array_splice($tableau, $trouve, 0, array($params)); + return $params; + } + elseif ($lieu == 'apres') { + array_splice($tableau, $trouve+1, 0, array($params)); + return $params; + } + } + return $tableau[$trouve]; + } + + // recursivons sinon ! + foreach ($tableau as $i=>$v){ + if (is_array($v)) { + foreach ($v as $m=>$n) { + if (is_array($n) AND ($r = $this->affecter($tableau[$i][$m], $identifiant, $params, $lieu))) + return $r; + } + } + } + return false; + } + + + /** + * Permet d'affecter des parametres toutes les elements de la barre + * + * @param array $params : parametres a affecter a la trouvaille + * @param array $ids : tableau identifiants particuliers a qui on affecte les parametres + * si vide, tous les identifiants seront modifies + * @param false/array $tableau : tableau ou chercher les elements (sert pour la recursion) + */ + function affecter_a_tous(&$tableau, $params=array(), $ids=array()){ + if (!$params) + return false; + + if ($tableau === null) + $tableau = &$this->markupSet; + + $params = $this->verif_params('divers', $params); + + // merge de premiere ligne + foreach ($tableau as $i=>$v){ + if (!$ids OR in_array($v['id'], $ids)) { + $tableau[$i] = array_merge($tableau[$i], $params); + } + // recursion si sous-menu + if (isset($tableau[$i]['dropMenu'])) { + $this->affecter_a_tous($tableau[$i]['dropMenu'], $params, $ids); + } + } + return true; + } + + + /** + * Affecte les valeurs des parametres indiques au bouton demande + * et retourne l'ensemble des parametres du bouton (sinon false) + * + * @param string/array $identifiant : id du ou des boutons a afficher + * @param array $params : param->valeur + * @return mixed + */ + function set($identifiant, $params=array()) { + // prudence tout de meme a pas tout modifier involontairement (si array) + if (!$identifiant) return false; + + if (is_string($identifiant)) { + return $this->affecter($this->markupSet, $identifiant, $params); + } + elseif (is_array($identifiant)) { + return $this->affecter_a_tous($this->markupSet, $params, $identifiant); + } + return false; + } + + /** + * Retourne les parametres du bouton demande + * + * @param string $identifiant : nom (de la classe du) bouton + * @return mixed + */ + function get($identifiant) { + if ($a = $this->affecter($this->markupSet, $identifiant)) { + return $a; + } + return false; + } + + + /** + * Affiche le bouton demande + * + * @param string $identifiant : nom (de la classe du) bouton a afficher + * @return true/false + */ + function afficher($identifiant){ + return $this->set($identifiant,array('display'=>true)); + } + + + /** + * Cache le bouton demande + * + * @param string $identifiant : nom (de la classe du) bouton a afficher + * @return true/false + */ + function cacher($identifiant){ + return $this->set($identifiant,array('display'=>false)); + } + + + /** + * Affiche tous les boutons + * + * @param string $identifiant : nom (de la classe du) bouton a afficher + * @return true/false + */ + function afficherTout(){ + return $this->affecter_a_tous($this->markupSet, array('display'=>true)); + } + + /** + * Cache tous les boutons + * + * @param string $identifiant : nom (de la classe du) bouton a afficher + * @return true/false + */ + function cacherTout(){ + return $this->affecter_a_tous($this->markupSet, array('display'=>false)); + } + + + /** + * ajouter un bouton ou quelque chose, avant un autre deja present + * + * @param string $identifiant : identifiant du bouton ou l'on doit se situer + * @param array $params : parametres de l'ajout + */ + function ajouterAvant($identifiant, $params){ + return $this->affecter($this->markupSet, $identifiant, $params, 'avant'); + } + + /** + * ajouter un bouton ou quelque chose, apres un autre deja present + * + * @param string $identifiant : identifiant du bouton ou l'on doit se situer + * @param array $params : parametres de l'ajout + */ + function ajouterApres($identifiant, $params){ + return $this->affecter($this->markupSet, $identifiant, $params, 'apres'); + + } + + /** + * ajouter une fonction js pour etre utilises dans les boutons + * + * @param string $fonction : code de la fonction js + * @return null + */ + function ajouterFonction($fonction){ + if (false === strpos($this->functions, $fonction)){ + $this->functions .= "\n" . $fonction . "\n"; + } + } + + /** + * Supprimer les elements non affiches (display:false) + * + * @param false/array $tableau : tableau a analyser (sert pour la recursion) + */ + function enlever_elements_non_affiches(&$tableau){ + if ($tableau === null) + $tableau = &$this->markupSet; + + foreach ($tableau as $p=>$v){ + + if (isset($v['display']) AND !$v['display']) { + unset($tableau[$p]); + $tableau = array_values($tableau); // remettre les cles automatiques sinon json les affiche et ça plante. + } + // sinon, on lance une recursion sur les sous-menus + else { + if (isset($v['dropMenu']) and is_array($v['dropMenu'])) { + $this->enlever_elements_non_affiches($tableau[$p]['dropMenu']); + // si le sous-menu est vide, on enleve l'icone + if (!$tableau[$p]['dropMenu']) { + unset($tableau[$p]); + $tableau = array_values($tableau); + } + } + } + } + } + + /** + * Supprime les elements vides (uniquement a la racine de l'objet) + * et uniquement si chaine ou tableau. + * + * Supprime les parametres prives + * Supprime les parametres inutiles a markitup/json dans les parametres markupSet + * (id, display, icone) + */ + function enlever_parametres_inutiles() { + foreach($this as $p=>$v){ + if (!$v) { + if (is_array($v) or is_string($v)) { + unset($this->$p); + } + } elseif ($p == 'functions') { + unset($this->$p); + } + } + foreach($this->markupSet as $p=>$v) { + foreach ($v as $n=>$m) { + if (in_array($n, array('id', 'display', 'icon'))) { + unset($this->markupSet[$p][$n]); + } + } + } + unset ($this->_liste_params_autorises); + } + + + /** + * Cree la sortie json pour le javascript des parametres de la barre + * et la retourne + * + * @return string : declaration json de la barre + */ + function creer_json(){ + $barre = $this; + $type = $barre->nameSpace; + $fonctions = $barre->functions; + + $barre->enlever_elements_non_affiches($this->markupSet); + $barre->enlever_parametres_inutiles(); + + $json = Barre_outils::json_export($barre); + + // on lance la transformation des &chose; en veritables caracteres + // sinon markitup restitue « au lieu de « directement + // lorsqu'on clique sur l'icone + include_spip('inc/charsets'); + $json = unicode2charset(html2unicode($json)); + return "\n\nbarre_outils_$type = ".$json . "\n\n $fonctions"; + } + + /** + * Transform a variable into its javascript equivalent (recursive) + * (depuis ecrire/inc/json, mais modifie pour que les fonctions + * js ne soient pas mises dans un string + * + * @access private + * @param mixed the variable + * @return string js script | boolean false if error + */ + function json_export($var) { + $asso = false; + switch (true) { + case is_null($var) : + return 'null'; + case is_string($var) : + if (strtolower(substr(ltrim($var),0,8))=='function') + return $var; + return '"' . addcslashes($var, "\"\\\n\r") . '"'; + case is_bool($var) : + return $var ? 'true' : 'false'; + case is_scalar($var) : + return $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 . '":' . Barre_outils::json_export($elt); + $sep = ','; + } + return $ret ."}\n"; + } else { + $ret = '['; + foreach ($var as $elt) { + $ret .= $sep . Barre_outils::json_export($elt); + $sep = ','; + } + return $ret ."]\n"; + } + } + return false; + } + +} + + + +/** + * Cette fonction cree la css pour les images + * des icones des barres d'outils + * en s'appuyant sur la description des jeux de barres disponibles. + * + * elle cherche une fonction barre_outils_($barre)_icones pour chaque + * barre et l'appelle si existe. + * + * @return string : declaration css des icones + */ +function barre_outils_css_icones(){ + // recuperer la liste, extraire les icones + $css = ""; + + // liste des barres + if (!$barres = barre_outils_liste()) + return null; + + // liste des classes css et leur correspondance avec une icone + $classe2icone = array(); + foreach ($barres as $barre) { + include_spip('barre_outils/' . $barre); + if ($f = charger_fonction($barre . '_icones', 'barre_outils', true)) { + if (is_array($icones = $f())) { + $classe2icone = array_merge($classe2icone, $icones); + } + } + } + + // passer le tout dans un pipeline pour ceux qui ajoute de simples icones a des barres existantes + $classe2icone = pipeline('porte_plume_lien_classe_vers_icone',$classe2icone); + + // passage en css + foreach ($classe2icone as $n=>$i) { + $css .= "\n.markItUp .$n a {\n\tbackground-image:url(".url_absolue(find_in_path("icones_barre/$i")).");\n}"; + } + + return $css; +} + + +/** + * Retourne une instance de Barre_outils + * cree a partir du type de barre demande + * + * @param string $set : type de barre + * @return object/false : objet de type barre_outil + */ +function barre_outils_initialiser($set){ + if ($f = charger_fonction($set, 'barre_outils')) { + // retourne une instance de l'objet Barre_outils + return $f(); + } + return false; +} + +/** + * Retourne la liste des barres d'outils connues + * + * @return array/false : tableau des noms de barres trouvees + */ +function barre_outils_liste(){ + static $sets = -1; + if ($sets !== -1) + return $sets; + + // on recupere l'ensemble des barres d'outils connues + if (!$sets = find_all_in_path('barre_outils/','.*[.]php') + or !is_array($sets)) { + $sets = false; + return $sets; + } + + foreach($sets as $fichier=>$adresse) { + $sets[$fichier] = substr($fichier,0,-4); // juste le nom + } + return $sets; +} + +?> diff --git a/javascript/jquery.markitup.js b/javascript/jquery.markitup.js new file mode 100644 index 0000000..1bdf319 --- /dev/null +++ b/javascript/jquery.markitup.js @@ -0,0 +1,553 @@ +// ---------------------------------------------------------------------------- +// markItUp! Universal MarkUp Engine, JQuery plugin +// v 1.1.5 +// Dual licensed under the MIT and GPL licenses. +// ---------------------------------------------------------------------------- +// Copyright (C) 2007-2008 Jay Salvat +// http://markitup.jaysalvat.com/ +// ---------------------------------------------------------------------------- +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// ---------------------------------------------------------------------------- +(function($) { + $.fn.markItUp = function(settings, extraSettings) { + var options, ctrlKey, shiftKey, altKey; + ctrlKey = shiftKey = altKey = false; + + options = { id: '', + nameSpace: '', + root: '', + previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes' + previewAutoRefresh: true, + previewPosition: 'after', + previewTemplatePath: '~/templates/preview.html', + previewParserPath: '', + previewParserVar: 'data', + resizeHandle: true, + beforeInsert: '', + afterInsert: '', + onEnter: {}, + onShiftEnter: {}, + onCtrlEnter: {}, + onTab: {}, + markupSet: [ { /* set */ } ] + }; + $.extend(options, settings, extraSettings); + + // compute markItUp! path + if (!options.root) { + $('script').each(function(a, tag) { + miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/); + if (miuScript !== null) { + options.root = miuScript[1]; + } + }); + } + + return this.each(function() { + var $$, textarea, levels, scrollPosition, caretPosition, caretOffset, + clicked, hash, header, footer, previewWindow, template, iFrame, abort; + $$ = $(this); + textarea = this; + levels = []; + abort = false; + scrollPosition = caretPosition = 0; + caretOffset = -1; + + options.previewParserPath = localize(options.previewParserPath); + options.previewTemplatePath = localize(options.previewTemplatePath); + + // apply the computed path to ~/ + function localize(data, inText) { + if (inText) { + return data.replace(/("|')~\//g, "$1"+options.root); + } + return data.replace(/^~\//, options.root); + } + + // init and build editor + function init() { + id = ''; nameSpace = ''; + if (options.id) { + id = 'id="'+options.id+'"'; + } else if ($$.attr("id")) { + id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"'; + + } + if (options.nameSpace) { + nameSpace = 'class="'+options.nameSpace+'"'; + } + $$.wrap('

'); + $$.wrap('
'); + $$.wrap('
'); + $$.addClass("markItUpEditor"); + + // add the header before the textarea + header = $('
').insertBefore($$); + $(dropMenus(options.markupSet)).appendTo(header); + + // add the footer after the textarea + footer = $('
').insertAfter($$); + + // add the resize handle after textarea + if (options.resizeHandle === true && $.browser.safari !== true) { + resizeHandle = $('
') + .insertAfter($$) + .bind("mousedown", function(e) { + var h = $$.height(), y = e.clientY, mouseMove, mouseUp; + mouseMove = function(e) { + $$.css("height", Math.max(20, e.clientY+h-y)+"px"); + return false; + }; + mouseUp = function(e) { + $("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp); + return false; + }; + $("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp); + }); + footer.append(resizeHandle); + } + + // listen key events + $$.keydown(keyPressed).keyup(keyPressed); + + // bind an event to catch external calls + $$.bind("insertion", function(e, settings) { + if (settings.target !== false) { + get(); + } + if (textarea === $.markItUp.focused) { + markup(settings); + } + }); + + // remember the last focus + $$.focus(function() { + $.markItUp.focused = this; + }); + } + + // recursively build header with dropMenus from markupset + function dropMenus(markupSet) { + var ul = $('
    '), i = 0; + $('li:hover > ul', ul).css('display', 'block'); + $.each(markupSet, function() { + var button = this, t = '', title, li, j; + title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||''); + key = (button.key) ? 'accesskey="'+button.key+'"' : ''; + if (button.separator) { + li = $('
  • '+(button.separator||'')+'
  • ').appendTo(ul); + } else { + i++; + for (j = levels.length -1; j >= 0; j--) { + t += levels[j]+"-"; + } + li = $('
  • '+(button.name||'')+'
  • ') + .bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click + return false; + }).click(function() { + return false; + }).mouseup(function() { + if (button.call) { + eval(button.call)(); + } + markup(button); + return false; + }).hover(function() { + $('> ul', this).show(); + $(document).one('click', function() { // close dropmenu if click outside + $('ul ul', header).hide(); + } + ); + }, function() { + $('> ul', this).hide(); + } + ).appendTo(ul); + if (button.dropMenu) { + levels.push(i); + $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu)); + } + } + }); + levels.pop(); + return ul; + } + + // markItUp! markups + function magicMarkups(string) { + if (string) { + string = string.toString(); + string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g, + function(x, a) { + var b = a.split('|!|'); + if (altKey === true) { + return (b[1] !== undefined) ? b[1] : b[0]; + } else { + return (b[1] === undefined) ? "" : b[0]; + } + } + ); + // [![prompt]!], [![prompt:!:value]!] + string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g, + function(x, a) { + var b = a.split(':!:'); + if (abort === true) { + return false; + } + value = prompt(b[0], (b[1]) ? b[1] : ''); + if (value === null) { + abort = true; + } + return value; + } + ); + return string; + } + return ""; + } + + // prepare action + function prepare(action) { + if ($.isFunction(action)) { + action = action(hash); + } + return magicMarkups(action); + } + + // build block to insert + function build(string) { + openWith = prepare(clicked.openWith); + placeHolder = prepare(clicked.placeHolder); + replaceWith = prepare(clicked.replaceWith); + closeWith = prepare(clicked.closeWith); + if (replaceWith !== "") { + block = openWith + replaceWith + closeWith; + } else if (selection === '' && placeHolder !== '') { + block = openWith + placeHolder + closeWith; + } else { + block = openWith + (string||selection) + closeWith; + } + return { block:block, + openWith:openWith, + replaceWith:replaceWith, + placeHolder:placeHolder, + closeWith:closeWith + }; + } + + // define markup to insert + function markup(button) { + var len, j, n, i; + hash = clicked = button; + get(); + + $.extend(hash, { line:"", + root:options.root, + textarea:textarea, + selection:(selection||''), + caretPosition:caretPosition, + ctrlKey:ctrlKey, + shiftKey:shiftKey, + altKey:altKey + } + ); + // callbacks before insertion + prepare(options.beforeInsert); + prepare(clicked.beforeInsert); + if (ctrlKey === true && shiftKey === true) { + prepare(clicked.beforeMultiInsert); + } + $.extend(hash, { line:1 }); + + if (ctrlKey === true && shiftKey === true) { + lines = selection.split(/\r?\n/); + for (j = 0, n = lines.length, i = 0; i < n; i++) { + if ($.trim(lines[i]) !== '') { + $.extend(hash, { line:++j, selection:lines[i] } ); + lines[i] = build(lines[i]).block; + } else { + lines[i] = ""; + } + } + string = { block:lines.join('\n')}; + start = caretPosition; + len = string.block.length + (($.browser.opera) ? n : 0); + } else if (ctrlKey === true) { + string = build(selection); + start = caretPosition + string.openWith.length; + len = string.block.length - string.openWith.length - string.closeWith.length; + len -= fixIeBug(string.block); + } else if (shiftKey === true) { + string = build(selection); + start = caretPosition; + len = string.block.length; + len -= fixIeBug(string.block); + } else { + string = build(selection); + start = caretPosition + string.block.length ; + len = 0; + start -= fixIeBug(string.block); + } + if ((selection === '' && string.replaceWith === '')) { + caretOffset += fixOperaBug(string.block); + + start = caretPosition + string.openWith.length; + len = string.block.length - string.openWith.length - string.closeWith.length; + + caretOffset = $$.val().substring(caretPosition, $$.val().length).length; + caretOffset -= fixOperaBug($$.val().substring(0, caretPosition)); + } + $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); + + if (string.block !== selection && abort === false) { + insert(string.block); + set(start, len); + } else { + caretOffset = -1; + } + get(); + + $.extend(hash, { line:'', selection:selection }); + + // callbacks after insertion + if (ctrlKey === true && shiftKey === true) { + prepare(clicked.afterMultiInsert); + } + prepare(clicked.afterInsert); + prepare(options.afterInsert); + + // refresh preview if opened + if (previewWindow && options.previewAutoRefresh) { + refreshPreview(); + } + + // reinit keyevent + shiftKey = altKey = ctrlKey = abort = false; + } + + // Substract linefeed in Opera + function fixOperaBug(string) { + if ($.browser.opera) { + return string.length - string.replace(/\n*/g, '').length; + } + return 0; + } + // Substract linefeed in IE + function fixIeBug(string) { + if ($.browser.msie) { + return string.length - string.replace(/\r*/g, '').length; + } + return 0; + } + + // add markup + function insert(block) { + if (document.selection) { + var newSelection = document.selection.createRange(); + newSelection.text = block; + } else { + $$.val($$.val().substring(0, caretPosition) + block + $$.val().substring(caretPosition + selection.length, $$.val().length)); + } + } + + // set a selection + function set(start, len) { + if (textarea.createTextRange){ + // quick fix to make it work on Opera 9.5 + if ($.browser.opera && $.browser.version >= 9.5 && len == 0) { + return false; + } + range = textarea.createTextRange(); + range.collapse(true); + range.moveStart('character', start); + range.moveEnd('character', len); + range.select(); + } else if (textarea.setSelectionRange ){ + textarea.setSelectionRange(start, start + len); + } + textarea.scrollTop = scrollPosition; + textarea.focus(); + } + + // get the selection + function get() { + textarea.focus(); + + scrollPosition = textarea.scrollTop; + if (document.selection) { + selection = document.selection.createRange().text; + if ($.browser.msie) { // ie + var range = document.selection.createRange(), rangeCopy = range.duplicate(); + rangeCopy.moveToElementText(textarea); + caretPosition = -1; + while(rangeCopy.inRange(range)) { // fix most of the ie bugs with linefeeds... + rangeCopy.moveStart('character'); + caretPosition ++; + } + } else { // opera + caretPosition = textarea.selectionStart; + } + } else { // gecko + caretPosition = textarea.selectionStart; + selection = $$.val().substring(caretPosition, textarea.selectionEnd); + } + return selection; + } + + // open preview window + function preview() { + if (!previewWindow || previewWindow.closed) { + if (options.previewInWindow) { + previewWindow = window.open('', 'preview', options.previewInWindow); + } else { + iFrame = $(''); + if (options.previewPosition == 'after') { + iFrame.insertAfter(footer); + } else { + iFrame.insertBefore(header); + } + previewWindow = iFrame[iFrame.length-1].contentWindow || frame[iFrame.length-1]; + } + } else if (altKey === true) { + if (iFrame) { + iFrame.remove(); + } + previewWindow.close(); + previewWindow = iFrame = false; + } + if (!options.previewAutoRefresh) { + refreshPreview(); + } + } + + // refresh Preview window + function refreshPreview() { + if (previewWindow.document) { + try { + sp = previewWindow.document.documentElement.scrollTop + } catch(e) { + sp = 0; + } + previewWindow.document.open(); + previewWindow.document.write(renderPreview()); + previewWindow.document.close(); + previewWindow.document.documentElement.scrollTop = sp; + } + if (options.previewInWindow) { + previewWindow.focus(); + } + } + + function renderPreview() { + if (options.previewParserPath !== '') { + $.ajax( { + type: 'POST', + async: false, + url: options.previewParserPath, + data: options.previewParserVar+'='+encodeURIComponent($$.val()), + success: function(data) { + phtml = localize(data, 1); + } + } ); + } else { + if (!template) { + $.ajax( { + async: false, + url: options.previewTemplatePath, + success: function(data) { + template = localize(data, 1); + } + } ); + } + phtml = template.replace(//g, $$.val()); + } + return phtml; + } + + // set keys pressed + function keyPressed(e) { + shiftKey = e.shiftKey; + altKey = e.altKey; + ctrlKey = (!(e.altKey && e.ctrlKey)) ? e.ctrlKey : false; + + if (e.type === 'keydown') { + if (ctrlKey === true) { + li = $("a[accesskey="+String.fromCharCode(e.keyCode)+"]", header).parent('li'); + if (li.length !== 0) { + ctrlKey = false; + li.triggerHandler('mouseup'); + return false; + } + } + if (e.keyCode === 13 || e.keyCode === 10) { // Enter key + if (ctrlKey === true) { // Enter + Ctrl + ctrlKey = false; + markup(options.onCtrlEnter); + return options.onCtrlEnter.keepDefault; + } else if (shiftKey === true) { // Enter + Shift + shiftKey = false; + markup(options.onShiftEnter); + return options.onShiftEnter.keepDefault; + } else { // only Enter + markup(options.onEnter); + return options.onEnter.keepDefault; + } + } + if (e.keyCode === 9) { // Tab key + if (shiftKey == true || ctrlKey == true || altKey == true) { // Thx Dr Floob. + return false; + } + if (caretOffset !== -1) { + get(); + caretOffset = $$.val().length - caretOffset; + set(caretOffset, 0); + caretOffset = -1; + return false; + } else { + markup(options.onTab); + return options.onTab.keepDefault; + } + } + } + } + + init(); + }); + }; + + $.fn.markItUpRemove = function() { + return this.each(function() { + $$ = $(this).unbind().removeClass('markItUpEditor'); + $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$); + } + ); + }; + + $.markItUp = function(settings) { + var options = { target:false }; + $.extend(options, settings); + if (options.target) { + return $(options.target).each(function() { + $(this).focus(); + $(this).trigger('insertion', [options]); + }); + } else { + $('textarea').trigger('insertion', [options]); + } + }; +})(jQuery); diff --git a/javascript/jquery.markitup_pour_spip.js b/javascript/jquery.markitup_pour_spip.js new file mode 100644 index 0000000..eba981e --- /dev/null +++ b/javascript/jquery.markitup_pour_spip.js @@ -0,0 +1,776 @@ +// ---------------------------------------------------------------------------- +// markItUp! Universal MarkUp Engine, JQuery plugin +// v 1.1.5 +// Dual licensed under the MIT and GPL licenses. +// ---------------------------------------------------------------------------- +// Copyright (C) 2007-2008 Jay Salvat +// http://markitup.jaysalvat.com/ +// ---------------------------------------------------------------------------- +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// ---------------------------------------------------------------------------- + +/* + * Le code original de markitup 1.1.5 + * a ete modifie pour prendre en compte + * + * 1) la langue utilisee dans les textarea : + * - si un textarea possede un attribut lang='xx' alors + * markitup n'affichera que les icones qui correspondent a cette langue + * - on peut passer une valeur de langue par defaut a markitup (le textarea peut ne pas en definir) + * .markitup(set_spip,{lang:'fr'}); + * - une option supplementaire optionnelle 'lang' est introduite dans les parametres + * des boutons (markupset), par exemple : lang:['fr','es','en'] + * - si un bouton n'a pas ce parametre, l'icone s'affiche + * quelque soit la langue designee dans le textarea ou les parametres de markitup ; + * sinon, il faut que la langue soit contenue dedans pour que l'icone s'affiche. + * 2) les control + shift (ou alt) + click bouton qui ne semblaient pas fonctionner + * en tout cas sous FF3/ubintu/jquery 1.2.6 a verifier chez les autres (opera 9.5/ubuntu ok) + * 3) gerer des types de selections differentes : + * - normales comme dans markitup (rien a faire) + * - 'selectionType':'word' : aux mots le plus proche si pas de selection (sinon la selection) + * - 'selectionType':'line' : aux lignes les plus proches + * - and 'return' : ugly hack to generate list (and so on) on key 'return' press + * 4) forcer des actions multilignes sans avoir besoin de faire control+click + * - 'forceMultiline':true : force donc une insertion multiligne + * 5) correction de la recuperation des selections d'Opera et de IE + * en utilisant une autre fonction de split() qui corrige leurs bugs. + * (caretOffset n'est plus necessaire) + * + */ +;(function($) { + $.fn.markItUp = function(settings, extraSettings) { + var options, ctrlKey, shiftKey, altKey, enterKey; + ctrlKey = shiftKey = altKey = enterKey = false; + + options = { id: '', + nameSpace: '', + root: '', + lang: '', + previewInWindow: '', // 'width=800, height=600, resizable=yes, scrollbars=yes' + previewAutoRefresh: true, + previewPosition: 'after', + previewTemplatePath: '~/templates/preview.html', + previewParserPath: '', + previewParserVar: 'data', + resizeHandle: true, + beforeInsert: '', + afterInsert: '', + onEnter: {}, + onShiftEnter: {}, + onCtrlEnter: {}, + onTab: {}, + markupSet: [ { /* set */ } ] + }; + $.extend(options, settings, extraSettings); + + // compute markItUp! path + if (!options.root) { + $('script').each(function(a, tag) { + miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/); + if (miuScript !== null) { + options.root = miuScript[1]; + } + }); + } + + return this.each(function() { + var $$, textarea, levels, scrollPosition, caretPosition, caretEffectivePosition, + clicked, hash, header, footer, previewWindow, template, iFrame, abort, + before, after; + $$ = $(this); + textarea = this; + levels = []; + abort = false; + scrollPosition = caretPosition = 0; + + options.previewParserPath = localize(options.previewParserPath); + options.previewTemplatePath = localize(options.previewTemplatePath); + + // apply the computed path to ~/ + function localize(data, inText) { + if (inText) { + return data.replace(/("|')~\//g, "$1"+options.root); + } + return data.replace(/^~\//, options.root); + } + + // init and build editor + function init() { + id = ''; nameSpace = ''; + if (options.id) { + id = 'id="'+options.id+'"'; + } else if ($$.attr("id")) { + id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"'; + + } + if (options.nameSpace) { + nameSpace = 'class="'+options.nameSpace+'"'; + } + $$.wrap('
    '); + $$.wrap('
    '); + $$.wrap('
    '); + $$.addClass("markItUpEditor"); + + // add the header before the textarea + header = $('
    ').insertBefore($$); + $(dropMenus(options.markupSet)).appendTo(header); + // remove empty dropMenu + $(header).find("li.markItUpDropMenu ul:empty").parent().remove(); + + // add the footer after the textarea + footer = $('
    ').insertAfter($$); + + // add the resize handle after textarea + if (options.resizeHandle === true && $.browser.safari !== true) { + resizeHandle = $('
    ') + .insertAfter($$) + .bind("mousedown", function(e) { + var h = $$.height(), y = e.clientY, mouseMove, mouseUp; + mouseMove = function(e) { + $$.css("height", Math.max(20, e.clientY+h-y)+"px"); + return false; + }; + mouseUp = function(e) { + $("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp); + return false; + }; + $("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp); + }); + footer.append(resizeHandle); + } + + // listen key events + $$.keydown(keyPressed).keyup(keyPressed); + + // bind an event to catch external calls + $$.bind("insertion", function(e, settings) { + if (settings.target !== false) { + get(); + } + if (textarea === $.markItUp.focused) { + markup(settings); + } + }); + + // remember the last focus + $$.focus(function() { + $.markItUp.focused = this; + }); + } + + // recursively build header with dropMenus from markupset + function dropMenus(markupSet) { + var ul = $('
      '), i = 0; + var lang = ($$.attr('lang')||options.lang); + + $('li:hover > ul', ul).css('display', 'block'); + $.each(markupSet, function() { + var button = this, t = '', title, li, j; + // pas de langue ou dans la langue ; et uniquement si langue autorisee + if ((!lang || !button.lang || ($.inArray(lang, button.lang) != -1)) + && (!button.lang_not || ($.inArray(lang, button.lang_not) == -1))) { + title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||''); + key = (button.key) ? 'accesskey="'+button.key+'"' : ''; + if (button.separator) { + li = $('
    • '+(button.separator||'')+'
    • ').appendTo(ul); + } else { + i++; + for (j = levels.length -1; j >= 0; j--) { + t += levels[j]+"-"; + } + li = $('
    • '+(button.name||'')+'
    • ') + .bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click + return false; + }).click(function() { + return false; + }).mouseup(function() { + if (button.call) { + eval(button.call)(); + } + markup(button); + return false; + }).hover(function() { + $('> ul', this).show(); + $(document).one('click', function() { // close dropmenu if click outside + $('ul ul', header).hide(); + } + ); + }, function() { + $('> ul', this).hide(); + } + ).appendTo(ul); + if (button.dropMenu) { + levels.push(i); + $(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu)); + } + } + } + }); + levels.pop(); + return ul; + } + + // markItUp! markups + function magicMarkups(string) { + if (string) { + string = string.toString(); + string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g, + function(x, a) { + var b = a.split('|!|'); + if (altKey === true) { + return (b[1] !== undefined) ? b[1] : b[0]; + } else { + return (b[1] === undefined) ? "" : b[0]; + } + } + ); + // [![prompt]!], [![prompt:!:value]!] + string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g, + function(x, a) { + var b = a.split(':!:'); + if (abort === true) { + return false; + } + value = prompt(b[0], (b[1]) ? b[1] : ''); + if (value === null) { + abort = true; + } + return value; + } + ); + return string; + } + return ""; + } + + // prepare action + function prepare(action) { + if ($.isFunction(action)) { + action = action(hash); + } + return magicMarkups(action); + } + + // build block to insert + function build(string) { + openWith = prepare(clicked.openWith); + placeHolder = prepare(clicked.placeHolder); + replaceWith = prepare(clicked.replaceWith); + closeWith = prepare(clicked.closeWith); + if (replaceWith !== "") { + block = openWith + replaceWith + closeWith; + } else if (selection === '' && placeHolder !== '') { + block = openWith + placeHolder + closeWith; + } else { + block = openWith + (string||selection) + closeWith; + } + return { block:block, + openWith:openWith, + replaceWith:replaceWith, + placeHolder:placeHolder, + closeWith:closeWith + }; + } + + + function selectWord(){ + selectionBeforeAfter(/\s|[.,;:!¡?¿()]/); + selectionSave(); + } + function selectLine(){ + selectionBeforeAfter(/\r?\n/); + selectionSave(); + } + + function selectionRemoveLast(pattern){ + // Remove space by default + if (!pattern) pattern = /\s/; + last = selection[selection.length-1]; + if (last && last.match(pattern)) { + set(caretPosition, selection.length-1); + get(); + $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); + } + } + + function selectionBeforeAfter(pattern) { + if (!pattern) pattern = /\s/; + before = $$.val().substring(0, caretEffectivePosition); + after = $$.val().substring(caretEffectivePosition + selection.length - fixOperaBug(selection) - fixIeBug(selection)); + + before = before.xSplit(pattern); + after = after.xSplit(pattern); + } + + function selectionSave(){ + nb_before = before ? before[before.length-1].length : 0; + nb_after = after ? after[0].length : 0; + + nb = nb_before + selection.length + nb_after - fixIeBug(selection); + caretPosition = caretPosition - nb_before; + + set(caretPosition, nb); + get(); + $.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); + } + + // define markup to insert + function markup(button) { + var len, j, n, i; + hash = clicked = button; + get(); + + $.extend(hash, { line:"", + root:options.root, + textarea:textarea, + selection:(selection||''), + caretPosition:caretPosition, + ctrlKey:ctrlKey, + shiftKey:shiftKey, + altKey:altKey, + enterKey:enterKey + } + ); + + // corrections des selections pour que + // - soit le curseur ne change pas + // - soit on prend le mot complet (si pas de selection) + // - soit on prend la ligne (avant, apres la selection) + if (button.selectionType) { + + if (button.selectionType == "word") { + if (!selection) { + selectWord(); + } else { + // win/ff add space on double click ? (hum, seems strange) + selectionRemoveLast(/\s/); + } + } + if (button.selectionType == "line") { + selectLine(); + } + // horrible chose, mais tellement plus pratique + // car on ne peut pas de l'exerieur (json) utiliser + // les fonctions internes de markitup + if (button.selectionType == "return"){ + selectionBeforeAfter(/\r?\n/); + before_last = before[before.length-1]; + after = ''; + // gestion des listes -# et -* + if (r = before_last.match(/^-([*#]+) ?(.*)$/)) { + if (r[2]) { + button.replaceWith = "\n-"+r[1]+' '; + before_last = ''; + } else { + // supprime le -* present + // (before le fera) + button.replaceWith = "\n"; + } + } else { + before_last = ''; + button.replaceWith = "\n"; + } + before[before.length-1] = before_last; + selectionSave(); + } + + } + // / fin corrections + + // callbacks before insertion + prepare(options.beforeInsert); + prepare(clicked.beforeInsert); + if (ctrlKey === true && shiftKey === true) { + prepare(clicked.beforeMultiInsert); + } + $.extend(hash, { line:1 }); + + // insertion forcee en multiligne ou ctrl+click + if ((button.forceMultiline === true && selection.length) + || (ctrlKey === true && shiftKey === true)) { + lines = selection.xSplit(/\r?\n/); + for (j = 0, n = lines.length, i = 0; i < n; i++) { + if ($.trim(lines[i]) !== '') { + $.extend(hash, { line:++j, selection:lines[i] } ); + lines[i] = build(lines[i]).block; + } else { + lines[i] = ""; + } + } + string = { block:lines.join('\n')}; + start = caretPosition; + len = string.block.length + (($.browser.opera) ? n : 0); + } else if (ctrlKey === true) { + string = build(selection); + start = caretPosition + string.openWith.length; + len = string.block.length - string.openWith.length - string.closeWith.length; + len -= fixIeBug(string.block); + } else if (shiftKey === true) { + string = build(selection); + start = caretPosition; + len = string.block.length; + len -= fixIeBug(string.block); + } else { + string = build(selection); + start = caretPosition + string.block.length ; + len = 0; + start -= fixIeBug(string.block); + } + + if (selection === ''){ + start += fixOperaBug(string.replaceWith); + } + //$.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } ); + + if (string.block !== selection && abort === false) { + insert(string.block); + set(start, len); + } + + get(); + + $.extend(hash, { line:'', selection:selection }); + + // callbacks after insertion + if ((button.forceMultiline === true) + || (ctrlKey === true && shiftKey === true)) { + prepare(clicked.afterMultiInsert); + } + + prepare(clicked.afterInsert); + prepare(options.afterInsert); + + // refresh preview if opened + if (previewWindow && options.previewAutoRefresh) { + refreshPreview(); + } + + // reinit keyevent + shiftKey = altKey = ctrlKey = enterKey = abort = false; + + } + + // Substract linefeed in Opera + function fixOperaBug(string) { + if ($.browser.opera) { + return string.length - string.replace(/\n*/g, '').length; + } + return 0; + } + // Substract linefeed in IE + function fixIeBug(string) { + if ($.browser.msie) { + return string.length - string.replace(/\r*/g, '').length; + } + return 0; + } + + // add markup + function insert(block) { + if (document.selection) { + var newSelection = document.selection.createRange(); + newSelection.text = block; + } else { + $$.val($$.val().substring(0, caretEffectivePosition) + block + $$.val().substring(caretEffectivePosition + selection.length)); + } + } + + // set a selection + function set(start, len) { + if (textarea.createTextRange){ + range = textarea.createTextRange(); + range.collapse(true); + range.moveStart('character', start); + range.moveEnd('character', len); + range.select(); + } else if (textarea.setSelectionRange ){ + textarea.setSelectionRange(start, start + len); + } + textarea.scrollTop = scrollPosition; + textarea.focus(); + } + + // get the selection + function get() { + textarea.focus(); + + scrollPosition = textarea.scrollTop; + if (document.selection) { + selection = document.selection.createRange().text; + if ($.browser.msie) { // ie + var range = document.selection.createRange(), rangeCopy = range.duplicate(); + rangeCopy.moveToElementText(textarea); + caretPosition = -1; + while(rangeCopy.inRange(range)) { // fix most of the ie bugs with linefeeds... + rangeCopy.moveStart('character'); + caretPosition ++; + } + caretEffectivePosition = caretPosition; + } else { // opera + caretPosition = textarea.selectionStart; + lenSelection = selection.length; + // calcul du nombre reel de caracteres pour les substr() + set(0,caretPosition); + opBefore = document.selection.createRange().text; + caretEffectivePosition = opBefore.length - fixOperaBug(opBefore); + set(caretPosition, lenSelection); + selection = document.selection.createRange().text; + } + } else { // gecko + caretPosition = textarea.selectionStart; + caretEffectivePosition = caretPosition; + selection = $$.val().substring(caretPosition, textarea.selectionEnd); + } + return selection; + } + + // open preview window + function preview() { + if (!previewWindow || previewWindow.closed) { + if (options.previewInWindow) { + previewWindow = window.open('', 'preview', options.previewInWindow); + } else { + iFrame = $(''); + if (options.previewPosition == 'after') { + iFrame.insertAfter(footer); + } else { + iFrame.insertBefore(header); + } + previewWindow = iFrame[iFrame.length-1].contentWindow || frame[iFrame.length-1]; + } + } else if (altKey === true) { + if (iFrame) { + iFrame.remove(); + } + previewWindow.close(); + previewWindow = iFrame = false; + } + if (!options.previewAutoRefresh) { + refreshPreview(); + } + } + + // refresh Preview window + function refreshPreview() { + if (previewWindow.document) { + try { + sp = previewWindow.document.documentElement.scrollTop + } catch(e) { + sp = 0; + } + previewWindow.document.open(); + previewWindow.document.write(renderPreview()); + previewWindow.document.close(); + previewWindow.document.documentElement.scrollTop = sp; + } + if (options.previewInWindow) { + previewWindow.focus(); + } + } + + function renderPreview() { + if (options.previewParserPath !== '') { + $.ajax( { + type: 'POST', + async: false, + url: options.previewParserPath, + data: options.previewParserVar+'='+encodeURIComponent($$.val()), + success: function(data) { + phtml = localize(data, 1); + } + } ); + } else { + if (!template) { + $.ajax( { + async: false, + url: options.previewTemplatePath, + success: function(data) { + template = localize(data, 1); + } + } ); + } + phtml = template.replace(//g, $$.val()); + } + return phtml; + } + + // set keys pressed + function keyPressed(e) { + if (e.type === 'keydown') { + if (e.keyCode === 18) {e.altKey = true;} // alt + if (e.keyCode === 17) {e.ctrlKey = true;} // control + if (e.keyCode === 16) {e.shiftKey = true;} // shift + } + shiftKey = e.shiftKey; + altKey = e.altKey; + ctrlKey = (!(e.altKey && e.ctrlKey)) ? e.ctrlKey : false; + if (e.type === 'keydown') { + if (ctrlKey === true) { + li = $("a[accesskey="+String.fromCharCode(e.keyCode)+"]", header).parent('li'); + if (li.length !== 0) { + ctrlKey = false; + li.triggerHandler('mouseup'); + return false; + } + } + // si opera, on s'embete pas, il cree plus de problemes qu'autre chose + // car il ne prend pas en compte l'arret de ces evenements + if (!$.browser.opera) { + if (e.keyCode === 13 || e.keyCode === 10) { // Enter key + enterKey = true; + if (ctrlKey === true) { // Enter + Ctrl + ctrlKey = false; + markup(options.onCtrlEnter); + return options.onCtrlEnter.keepDefault; + } else if (shiftKey === true) { // Enter + Shift + shiftKey = false; + markup(options.onShiftEnter); + return options.onShiftEnter.keepDefault; + } else { // only Enter + markup(options.onEnter); + return options.onEnter.keepDefault; + } + } + + if (e.keyCode === 9) { // Tab key + // don't know what that is for... + if (shiftKey == true || ctrlKey == true || altKey == true) { // Thx Dr Floob. + return false; + } + markup(options.onTab); + return options.onTab.keepDefault; + } + } + } + } + + init(); + }); + }; + + $.fn.markItUpRemove = function() { + return this.each(function() { + $$ = $(this).unbind().removeClass('markItUpEditor'); + $$.parent('div').parent('div.markItUp').parent('div').replaceWith($$); + } + ); + }; + + $.markItUp = function(settings) { + var options = { target:false }; + $.extend(options, settings); + if (options.target) { + return $(options.target).each(function() { + $(this).focus(); + $(this).trigger('insertion', [options]); + }); + } else { + $('textarea').trigger('insertion', [options]); + } + }; + +})(jQuery); + + +/* + * Corriger les split qui ne fonctionnent pas pareil + * sous IE particulierement. Provient de : + * http://blog.stevenlevithan.com/archives/cross-browser-split + * (ici, remplace par la fonction xSplit) + */ + +/* + Cross-Browser Split 0.3 + By Steven Levithan + MIT license + Provides a consistent cross-browser, ECMA-262 v3 compliant split method +*/ + +//String.prototype._$$split = String.prototype._$$split || String.prototype.split; + +//String.prototype.split = function (s /* separator */, limit) { +String.prototype.xSplit = function (s /* separator */, limit) { + // if separator is not a regex, use the native split method + if (!(s instanceof RegExp)) + return String.prototype.split.apply(this, arguments); + //return String.prototype._$$split.apply(this, arguments); + + var flags = (s.global ? "g" : "") + (s.ignoreCase ? "i" : "") + (s.multiline ? "m" : ""), + s2 = new RegExp("^" + s.source + "$", flags), + output = [], + origLastIndex = s.lastIndex, + lastLastIndex = 0, + i = 0, match, lastLength; + + /* behavior for limit: if it's... + - undefined: no limit + - NaN or zero: return an empty array + - a positive number: use limit after dropping any decimal + - a negative number: no limit + - other: type-convert, then use the above rules + */ + if (limit === undefined || +limit < 0) { + limit = false; + } else { + limit = Math.floor(+limit); + if (!limit) + return []; + } + + if (s.global) + s.lastIndex = 0; + else + s = new RegExp(s.source, "g" + flags); + + while ((!limit || i++ <= limit) && (match = s.exec(this))) { + var emptyMatch = !match[0].length; + + // Fix IE's infinite-loop-resistant but incorrect lastIndex + if (emptyMatch && s.lastIndex > match.index) + s.lastIndex--; + + if (s.lastIndex > lastLastIndex) { + // Fix browsers whose exec methods don't consistently return undefined for non-participating capturing groups + if (match.length > 1) { + match[0].replace(s2, function () { + for (var j = 1; j < arguments.length - 2; j++) { + if (arguments[j] === undefined) + match[j] = undefined; + } + }); + } + + output = output.concat(this.slice(lastLastIndex, match.index)); + if (1 < match.length && match.index < this.length) + output = output.concat(match.slice(1)); + lastLength = match[0].length; // only needed if s.lastIndex === this.length + lastLastIndex = s.lastIndex; + } + + if (emptyMatch) + s.lastIndex++; // avoid an infinite loop + } + + // since this uses test(), output must be generated before restoring lastIndex + output = lastLastIndex === this.length ? + (s.test("") && !lastLength ? output : output.concat("")) : + (limit ? output : output.concat(this.slice(lastLastIndex))); + s.lastIndex = origLastIndex; // only needed if s.global, else we're working with a copy of the regex + return output; +}; diff --git a/javascript/jquery.previsu_spip.js b/javascript/jquery.previsu_spip.js new file mode 100644 index 0000000..6539ed3 --- /dev/null +++ b/javascript/jquery.previsu_spip.js @@ -0,0 +1,77 @@ +;(function($) { + $.fn.previsu_spip = function(settings) { + var options; + + options = { + previewParserPath: '' , + previewParserVar: 'data', + textEditer: 'Editer', + textVoir: 'Voir' + }; + $.extend(options, settings); + + return this.each(function() { + var $$, textarea, tabs, preview; + $$ = $(this); + textarea = this; + + // init and build previsu buttons + function init() { + tabs = $('
      ').prependTo($$.parent()); + $(tabs).append( + '' + options.textVoir + '' + + '' + options.textEditer + '' + ); + + preview = $('
      ').insertAfter(tabs); + preview.hide(); + + $('.previsuVoir').click(function(){ + mark = $(this).parent().parent(); + $(mark).find('.markItUpPreview').height( + $(mark).find('.markItUpHeader').height() + + $(mark).find('.markItUpEditor').height() + + $(mark).find('.markItUpFooter').height() + ); + $(mark).find('.markItUpHeader').hide(); + $(mark).find('.markItUpEditor').hide(); + $(mark).find('.markItUpFooter').hide(); + $(this).addClass('on').next().removeClass('on'); + $(mark).find('.markItUpPreview').show() + .addClass('ajaxLoad') + .html(renderPreview()) + .removeClass('ajaxLoad'); + return false; + }); + $('.previsuEditer').click(function(){ + mark = $(this).parent().parent(); + $(mark).find('.markItUpPreview').hide(); + $(mark).find('.markItUpHeader').show(); + $(mark).find('.markItUpEditor').show(); + $(mark).find('.markItUpFooter').show(); + $(this).addClass('on').prev().removeClass('on'); + return false; + }); + } + + + function renderPreview() { + var phtml; + if (options.previewParserPath !== '') { + $.ajax( { + type: 'POST', + async: false, + url: options.previewParserPath, + data: options.previewParserVar+'='+encodeURIComponent($$.val()), + success: function(data) { + phtml = data; + } + } ); + } + return phtml; + } + + init(); + }); + }; +})(jQuery); diff --git a/lang/barre_outils_ar.php b/lang/barre_outils_ar.php new file mode 100644 index 0000000..6e5c101 --- /dev/null +++ b/lang/barre_outils_ar.php @@ -0,0 +1,89 @@ + 'تنظيف الرموز البرمجية من كل علامات HTML', +'barre_lorem_ipsum' => 'إدراج فقرة زائفة', +'barre_lorem_ipsum_3' => 'إدراج ثلاث فقرات زائفة', +'barre_liste_ul' => 'تحويل الى لائحة', +'barre_liste_ol' => 'تحويل الى لائحة مرقمة', +'barre_indenter' => 'إزاحة لائحة', +'barre_desindenter' => 'إلغاء إزاحة لائحة', +'barre_inserer_caracteres' => 'إدراج حروف محددة', + +'editer'=>'تحرير', +'voir'=>'معاينة', + + +// B (depuis SPIP) +'barre_a_accent_grave' => 'إدراج A مع نبر الاطالة: À', +'barre_aide' => 'استخدم شريط اختصارات الكتابة لإغناء تصميم صفحتك', +'barre_e_accent_aigu' => 'ادراج E كبير مع نبر حاد - É', +'barre_eo' => 'ادراج e داخل e: œ', +'barre_eo_maj' => 'ادراج E كبير داخل O كبير: Œ', +'barre_euro' => 'ادراج رمز €', +'barre_gras' => '{{اسود}}', +'barre_guillemets' => 'احاطة «بعلامتي اقتباس مزدوجة»', +'barre_guillemets_simples' => 'وضع بين "علامتي إقتباس مزدوجة من المستوى الثاني"', +'barre_intertitre' => 'تحويل الى {{{عنوان فقرة}}}', +'barre_italic' => '{مائل}', +'barre_lien' => 'تحويل الى [وصلة هايبرتكست->http://...]', +'barre_lien_input' => 'الرجاء ادخال عنوان الوصلة (يمكنك ادخال عنوان نسيج على شكل http://www.mysite.com او ادخال رقم مقال من الموقع الحالي فقط).', +'barre_note' => 'تحويل الى [[حاشية]]', +'barre_paragraphe' => 'انشاء فقرة', +'barre_quote' => 'اقتباس رسالة', + +// B (depuis BTv2) +'barre_langue' => 'لغة مختصرة', +'barre_miseenevidence' => '[*إبراز*] النص', +'barre_exposant' => 'تحويل الى <sup>نص فوقي</sup>', +'barre_petitescapitales' => 'تحويل الى <sc>حروف كبيرة مصغرة</sc>', +'barre_centrer' => '[|توسيط|] الفقرة', +'barre_alignerdroite' => 'محاذاة الى [/اليمين/]', +'barre_encadrer' => 'وضع في [(إطار)]', +'barre_e_accent_grave' => 'إدراج E كبير مع نبر الاطالة: È', +'barre_ea' => 'ادراج e داخل a: æ', +'barre_ea_maj' => 'ادراج E كبير داخل A كبير: Æ', +'barre_c_cedille_maj' => 'ادراج C كبير مع علامة لفظية: Ç', + +'barre_chercher' => 'بحث واستبدال', +'barre_tableau' => 'إدراج جدول أو تعديل جدول (تحديده أولاً)', +'barre_glossaire' => 'مدخل في [?المعجم] (ويكيبيديا)', + +'barre_caracteres' => 'حروف خاصة', +'barre_adresse' => 'عنوان', +'barre_lien_externe' => 'رابط خارجي', +'barre_bulle' => 'بالون تعليمات', +'barre_formatages_speciaux' => 'تنسيقات خاصة', +'barre_galerie' => 'فتح صالة العرض', +'barre_gestion_caption' => 'وصف وملخص', +'barre_gestion_colonne' => 'عدد الأعمدة', +'barre_gestion_ligne' => 'عدد السطور', +'barre_gestion_entete' => 'ترويسة', +'barre_gestion_taille' => 'حجم ثابت', +'barre_gestion_cr_changercasse' => 'تغيير حجم الحروف', +'barre_gestion_cr_changercassemajuscules' => 'تحويل الى الحروف كبيرة', +'barre_gestion_cr_changercasseminuscules' => 'تحويل الى الحروف صغيرة', +'barre_gestion_cr_chercher' => 'بحث', +'barre_gestion_cr_remplacer' => 'استبدال', +'barre_gestion_cr_casse' => 'تطابق حجم الحروف', +'barre_gestion_cr_tout' => 'استبدال الكل', +'barre_gestion_cr_entier' => 'كلمة كاملة', +'barre_preview' => 'معاينة', +'barre_stats' => 'عرض احصاءات النص', + +'barre_code' => 'تنسيق <code>مقطع رموز برمجية</code>', +'barre_cadre' => 'وضع في <cadre>مجال إدخال نصوص</cadre>', +'barre_poesie' => 'تنسيق <poesie>شعر</poesie>', + +'barre_ancres' => 'إدارة المراسي', +'barre_gestion_anc_caption' => 'إدارة المراسي', +'barre_gestion_anc_inserer' => 'تحويل الى مرساة', +'barre_gestion_anc_nom' => 'اسم المرساة', +'barre_gestion_anc_pointer' => 'التصويب الى مرساة', +'barre_gestion_anc_cible' => 'المرساة الهدف', +'barre_gestion_anc_bulle' => 'بالون تعليمات المرساة' + + +); +?> diff --git a/lang/barre_outils_en.php b/lang/barre_outils_en.php new file mode 100644 index 0000000..6d12994 --- /dev/null +++ b/lang/barre_outils_en.php @@ -0,0 +1,89 @@ + 'Clean the code of all HTML tags', +'barre_lorem_ipsum' => 'Insert a fake paragraph', +'barre_lorem_ipsum_3' => 'Insert three fake paragraphs', +'barre_liste_ul' => 'Set list', +'barre_liste_ol' => 'Set numbered list', +'barre_indenter' => 'Indent a line', +'barre_desindenter' => 'Unindent a line', +'barre_inserer_caracteres' => 'Insert special characters', + +'editer'=>'Edit', +'voir'=>'Preview', + + +// B (depuis SPIP) +'barre_a_accent_grave' => 'Insert a capital A with grave accent', +'barre_aide' => 'Use the typographic short cuts to refine your layout', +'barre_e_accent_aigu' => 'Insert a capital E with acute accent', +'barre_eo' => 'Insert an oe-ligature', +'barre_eo_maj' => 'Insert a capital EO-ligature', +'barre_euro' => 'Insert the € symbol', +'barre_gras' => 'Put in {{bold type}}', +'barre_guillemets' => 'Place between «double quotes«', +'barre_guillemets_simples' => 'Place between “single quotes“', +'barre_intertitre' => 'Turn into a {{{subheading}}}', +'barre_italic' => 'Put in {italics}', +'barre_lien' => 'Turn into a [hyperlink->http://...]', +'barre_lien_input' => 'Please enter the target of your hyperlink (you may give an internet URL in the form http://www.mysite.com or else simply the number of an article on this site).', +'barre_note' => 'Turn into a [[Footnote]]', +'barre_paragraphe' => 'Create a paragraph', +'barre_quote' => 'Quote a message', + +// B (depuis BTv2) +'barre_langue' => 'Abbreviated lnguage', +'barre_miseenevidence' => 'Mettre le texte en [*évidence*]', +'barre_exposant' => 'Put the text in <sup>superscript</sup>', +'barre_petitescapitales' => 'Put the text in <sc>small capitales</sc>', +'barre_centrer' => '[|Center|] paragraph', +'barre_alignerdroite' => '[/Right align/] paragraph', +'barre_encadrer' => '[(Frame)] paragraph', +'barre_e_accent_grave' => 'Insert capital E grave', +'barre_ea' => 'Insert æ', +'barre_ea_maj' => 'Insert Æ', +'barre_c_cedille_maj' => 'Insert capital C cedilla', + +'barre_chercher' => 'Search & Replace', +'barre_tableau' => 'Insert/modify a table (select it first)', +'barre_glossaire' => '[?Glossary] reference (Wikipedia)', + +'barre_caracteres' => 'Special characters', +'barre_adresse' => 'Address', +'barre_lien_externe' => 'External link', +'barre_bulle' => 'Help bubble', +'barre_formatages_speciaux' => 'Special formating', +'barre_galerie' => 'Open gallery', +'barre_gestion_caption' => 'Caption and Summary', +'barre_gestion_colonne' => 'No. of columns', +'barre_gestion_ligne' => 'No. of lines', +'barre_gestion_entete' => 'Header', +'barre_gestion_taille' => 'Fixed size', +'barre_gestion_cr_changercasse' => 'Change case', +'barre_gestion_cr_changercassemajuscules' => 'Convert to upper case', +'barre_gestion_cr_changercasseminuscules' => 'Convert to lower case', +'barre_gestion_cr_chercher' => 'Search', +'barre_gestion_cr_remplacer' => 'Replace', +'barre_gestion_cr_casse' => 'Match case', +'barre_gestion_cr_tout' => 'Replace all', +'barre_gestion_cr_entier' => 'Only complete words', +'barre_preview' => 'Preview mode', +'barre_stats' => 'Show text statistics', + +'barre_code' => 'Edit a <code>computer code</code>', +'barre_cadre' => 'Put in a <cadre>textarea</cadre>', +'barre_poesie' => 'Edit as a <poesie>poetry</poesie>', + +'barre_ancres' => 'Anchors', +'barre_gestion_anc_caption' => 'Anchors', +'barre_gestion_anc_inserer' => 'Convert to anchor', +'barre_gestion_anc_nom' => 'Anchor name', +'barre_gestion_anc_pointer' => 'Point to an anchor', +'barre_gestion_anc_cible' => 'Anhor target', +'barre_gestion_anc_bulle' => 'Anchor help bubble', + + +); +?> diff --git a/lang/barre_outils_fr.php b/lang/barre_outils_fr.php new file mode 100644 index 0000000..ec6cb64 --- /dev/null +++ b/lang/barre_outils_fr.php @@ -0,0 +1,90 @@ + 'Nettoyer le code de toutes les balises HTML', +'barre_lorem_ipsum' => 'Insérer un paragraphe factice', +'barre_lorem_ipsum_3' => 'Insérer trois paragraphes factices', +'barre_liste_ul' => 'Mettre en liste', +'barre_liste_ol' => 'Mettre en liste numérotée', +'barre_indenter' => 'Indenter une liste', +'barre_desindenter' => 'Désindenter une liste', +'barre_inserer_caracteres' => 'Insérer des caractères spécifiques', +'barre_barre' => 'Barrer le texte', + +'editer'=>'Éditer', +'voir'=>'Voir', + + +// B (depuis SPIP) +'barre_a_accent_grave' => 'Insérer un A accent grave majuscule', +'barre_aide' => 'Utilisez les raccourcis typographiques pour enrichir votre mise en page', +'barre_e_accent_aigu' => 'Insérer un E accent aigu majuscule', +'barre_eo' => 'Insérer un E dans l\'O', +'barre_eo_maj' => 'Insérer un E dans l\'O majuscule', +'barre_euro' => 'Insérer le symbole €', +'barre_gras' => 'Mettre en {{gras}}', +'barre_guillemets' => 'Entourer de « guillemets »', +'barre_guillemets_simples' => 'Entourer de “guillemets de second niveau”', +'barre_intertitre' => 'Transformer en {{{intertitre}}}', +'barre_italic' => 'Mettre en {italique}', +'barre_lien' => 'Transformer en [lien hypertexte->http://...]', +'barre_lien_input' => 'Veuillez indiquer l\'adresse de votre lien (vous pouvez indiquer une adresse Internet sous la forme http://www.monsite.com, une adresse courriel, ou simplement indiquer le numéro d\'un article de ce site.', +'barre_note' => 'Transformer en [[Note de bas de page]]', +'barre_paragraphe' => 'Créer un paragraphe', +'barre_quote' => 'Citer un message', + +// B (depuis BTv2) +'barre_langue' => 'Langue abrégée', +'barre_miseenevidence' => 'Mettre le texte en [*évidence*]', +'barre_exposant' => 'Mettre le texte en <sup>exposant</sup>', +'barre_petitescapitales' => 'Mettre le texte en <sc>petites capitales</sc>', +'barre_centrer' => '[|Centrer|] le paragraphe', +'barre_alignerdroite' => '[/Aligne à droite/] le paragraphe', +'barre_encadrer' => '[(Encadrer)] le paragraphe', +'barre_e_accent_grave' => 'Insérer un E majuscule accent grave', +'barre_ea' => 'Insérer un E dans l\'A', +'barre_ea_maj' => 'Insérer un E dans l\'A majuscule', +'barre_c_cedille_maj' => 'Insérer un C cédille majuscule', + +'barre_chercher' => 'Chercher Remplacer', +'barre_tableau' => 'Insérer/modifier (le sélectionner avant) un tableau', +'barre_glossaire' => 'Entrée du [?glossaire] (Wikipedia)', + +'barre_caracteres' => 'Caractères spéciaux', +'barre_adresse' => 'Adresse', +'barre_lien_externe' => 'Lien externe', +'barre_bulle' => 'Bulle d\'aide', +'barre_formatages_speciaux' => 'Formatage spéciaux', +'barre_galerie' => 'Ouvrir la galerie', +'barre_gestion_caption' => 'Caption et Résumé', +'barre_gestion_colonne' => 'Nb colonnes', +'barre_gestion_ligne' => 'Nb lignes', +'barre_gestion_entete' => 'Entete', +'barre_gestion_taille' => 'Taille fixe', +'barre_gestion_cr_changercasse' => 'Changer la casse', +'barre_gestion_cr_changercassemajuscules' => 'Passer en majuscules', +'barre_gestion_cr_changercasseminuscules' => 'Passer en minuscules', +'barre_gestion_cr_chercher' => 'Chercher', +'barre_gestion_cr_remplacer' => 'Remplacer', +'barre_gestion_cr_casse' => 'Respecter la casse', +'barre_gestion_cr_tout' => 'Tout remplacer', +'barre_gestion_cr_entier' => 'Mot entier', +'barre_preview' => 'Mode prévisualisation', +'barre_stats' => 'Afficher les statistiques du texte', + +'barre_code' => 'Mettre en forme un <code>code informatique</code>', +'barre_cadre' => 'Placer dans une <cadre>zone de saisie de texte</cadre>', +'barre_poesie' => 'Mettre en forme comme une <poesie>poésie</poesie>', + +'barre_ancres' => 'Gestion des ancres', +'barre_gestion_anc_caption' => 'Gestion des ancres', +'barre_gestion_anc_inserer' => 'Transformer en ancre', +'barre_gestion_anc_nom' => 'Nom de l\'ancre', +'barre_gestion_anc_pointer' => 'Pointer vers une ancre', +'barre_gestion_anc_cible' => 'Ancre cible', +'barre_gestion_anc_bulle' => 'Bulle d\'aide ancre' + + +); +?> diff --git a/markitup/readme.txt b/markitup/readme.txt new file mode 100644 index 0000000..dfbb656 --- /dev/null +++ b/markitup/readme.txt @@ -0,0 +1,55 @@ +markItUp! 1.1.3 + +CHANGE LOG +markItUp! 1.1.3 2008-09-12 +- Fixed: IE7 preview problem + +markItUp! 1.1.2 2008-07-17 +- Fixed: Quick fix for Opera 9.5 caret position problem after insertion + +markItUp! 1.1.1 2008-06-02 +- Fixed: Key events status are passed to callbacks properly +- Improved: ScrollPosition is kept in the preview when its refreshed + +markItUp! 1.1.0 2008-05-04 +- Modified: Textarea's id is no more moved to the main container +- Modified: NameSpace Span become a Div to remain strict +- Added: Relative path to the script is computed +- Added: Relative path to the script passed to callbacks +- Added: Global instance ID property +- Added: $(element).markItUpRemove() to remove markItUp! +- Added: Resize handle is now optional with resizeHandle property +- Added: Property previewInWindow is added and accept window parameter +- Added: Property previewPosition is added +- Modified: Resize handle is no more displayed in Safari to avoid repetition with the native handle +- Modified: Property previewIframeRefresh become previewAutorefresh +- Modified: Built-in Html Preview call a template file +- Improved: Autorefreshing is now apply for preview in window too +- Improved: Cancel button in prompt window cancel now the whole insertion process +- Improved: Cleaner markItUp! code added to the DOM +- Removed: Depreciated preview properties as previewBaseUrl, previewCharset, previewCssPath, previewBodyId, previewBodyClassName +- Removed: Property previewIframe not longer exists +- Fixed: "Magic markups" works with line feeds +- Fixed: Key events are initialized after insertion +- Fixed: Internet Explorer line feed offset bug +- Fixed: Shortcut keys on Mac OS +- Fixed: Ctrl+click works and doesn't open Mac context menu anymore +- Fixed: Ctrl+click works and doesn't open the page in a new tab anymore +- Fixed: Minor Css modifications + +markItUp! 1.0.3 2008-04-04 +- Fixed: IE7 Preview empty baseurl problem +- Fixed: IE7 external targeted insertion +- Added: Property scrollPosition is passed to callbacks functions + +markItUp! 1.0.2 2008-03-31 +- Fixed: IE7 Html preview problems +- Fixed: Selection is kept if nothing is inserted +- Improved: Code minified + +markItUp! 1.0.1 2008-03-21 +- Removed: Global PlaceHolder +- Modified: Property previewCharset is setted to "utf-8" by default + +markItUp! 1.0.0 2008-03-01 +- First public release diff --git a/markitup/templates/preview.css b/markitup/templates/preview.css new file mode 100644 index 0000000..ad91a87 --- /dev/null +++ b/markitup/templates/preview.css @@ -0,0 +1,5 @@ +/* preview style examples */ +body { + background-color:#EFEFEF; + font:70% Verdana, Arial, Helvetica, sans-serif; +} \ No newline at end of file diff --git a/markitup/templates/preview.html b/markitup/templates/preview.html new file mode 100644 index 0000000..b8b3702 --- /dev/null +++ b/markitup/templates/preview.html @@ -0,0 +1,11 @@ + + + + +markItUp! preview template + + + + + + diff --git a/plugin.xml b/plugin.xml new file mode 100644 index 0000000..b13c863 --- /dev/null +++ b/plugin.xml @@ -0,0 +1,29 @@ + + Porte plume - Une barre d'outil pour bien écrire + Matthieu Marcillaud + GNU/GPL + 1.2.6 + + "Porte plume" est une barre d'outil géniale pour SPIP qui + utilise la librairie javascript [MarkItUp->http://markitup.jaysalvat.com/home/] + + Utilise les icones [FamFamFam->http://www.famfamfam.com/] + + http://documentation.magraine.net/-Porte-Plume- + stable + porte_plume + + porte_plume_options.php + inc/barre_outils.php + + + insert_head + porte_plume_pipelines.php + + + header_prive + insert_head + porte_plume_pipelines.php + + + diff --git a/porte_plume.js.html b/porte_plume.js.html new file mode 100644 index 0000000..f2618f5 --- /dev/null +++ b/porte_plume.js.html @@ -0,0 +1,4 @@ +#CACHE{7*24*3600} +#HTTP_HEADER{Content-Type: text/javascript; charset=#CHARSET} + +[(#VAL|porte_plume_creer_json_markitup)] diff --git a/porte_plume.js_fonctions.php b/porte_plume.js_fonctions.php new file mode 100644 index 0000000..99e90b6 --- /dev/null +++ b/porte_plume.js_fonctions.php @@ -0,0 +1,61 @@ +ajouterApres('bold',array(params)); + // $barre->ajouterAvant('bold',array(params)); + // + // $bold = $barre->get('bold'); + // $bold['id'] = 'bold2'; + // $barre->ajouterApres('italic',$bold); + $barres = pipeline('porte_plume_barre_pre_charger', $barres); + + + // 3 chargement + // permet de cacher ou afficher certains boutons au besoin + // exemples : + // $barre = &$flux['spip']; + // $barre->afficher('bold'); + // $barre->cacher('bold'); + // + // $barre->cacherTout(); + // $barre->afficher(array('bold','italic','header1')); + $barres = pipeline('porte_plume_barre_charger', $barres); + + + // 4 on cree les jsons + $json = ""; + foreach($barres as $set=>$barre) { + $json .= $barre->creer_json(); + } + return $json; +} + + +?> diff --git a/porte_plume_options.php b/porte_plume_options.php new file mode 100644 index 0000000..ed0e246 --- /dev/null +++ b/porte_plume_options.php @@ -0,0 +1,20 @@ + diff --git a/porte_plume_pipelines.php b/porte_plume_pipelines.php new file mode 100644 index 0000000..176f0d7 --- /dev/null +++ b/porte_plume_pipelines.php @@ -0,0 +1,55 @@ +\n" + . "\n" + . "\n" + . "\n" + . "\n"; + + $preview = url_absolue(generer_url_public('preview')); + $tEditer = _T('barre_outils:editer'); + $tVoir = _T('barre_outils:voir'); + $flux .= << + + +EOF; + + return $flux; +} + + +?> diff --git a/preview.html b/preview.html new file mode 100644 index 0000000..621696a --- /dev/null +++ b/preview.html @@ -0,0 +1,6 @@ +#CACHE{0} +#HTTP_HEADER{Content-Type: text/html; charset=#CHARSET} +
      +[(#ENV*{data}|propre|image_reduire{440}|liens_absolus)] +[
      (#NOTES)
      ] +
      diff --git a/tests/all_tests.php b/tests/all_tests.php new file mode 100644 index 0000000..31ce28f --- /dev/null +++ b/tests/all_tests.php @@ -0,0 +1,12 @@ +SpipTestSuite('Barre MarkitUp'); + $this->addDir(__FILE__); + #$this->addFile(find_in_path('tests/barre_outil_markitup.php')); + } +} + +?> diff --git a/tests/barre_outil_markitup.php b/tests/barre_outil_markitup.php new file mode 100644 index 0000000..9dba800 --- /dev/null +++ b/tests/barre_outil_markitup.php @@ -0,0 +1,359 @@ +SpipTest("Test de la classe Barre_outils"); + + // instancier une barre d'outil + include_spip('inc/barre_outils'); + $this->baseParamsBarre = array( + 'nameSpace' => 'spip', + 'markupSet' => array( + // H1 - {{{ + array( + "id" => 'header1', + "name" => _T('barre_outils:barre_intertitre'), + "key" => "H", + "className" => "outil_header1", + "openWith" => "{{{", + "closeWith" => "}}}", + "display" => true, + ))); + $p = $this->baseParamsBarre; + $p['markupSet'][1] = array( + "id" => 'couleurs', + "name" => _T('barre_outils:barre_couleur'), + "key" => "C", + "className" => "outil_couleur", + "openWith" => '[color=[![Color]!]]', + "closeWith" => '[/color]', + "display" => true, + "dropMenu" => array( + array( + "id" => "couleur_jaune", + "name" => 'Yellow', + "openWith" => '[color=yellow]', + "closeWith" => '[/color]', + "className" => "outil_couleur", + "display" => true, + ), + array( + "id" => "couleur_orange", + "name" => 'Orange', + "openWith" => '[color=orange]', + "closeWith" => '[/color]', + "className" => "outil_couleur", + "display" => true, + ), + array( + "id" => "couleur_rouge", + "name" => 'Red', + "openWith" => '[color=red]', + "closeWith" => '[/color]', + "className" => "outil_couleur", + "display" => true, + ), + ), + ); + $this->baseParamsBarreEtendue = $p; + } + + // avant chaque appel de fonction test + function setUp() { + + } + // apres chaque appel de fonction test + function tearDown() { + + } + + + function testInitialisationBarre(){ + // parametres inseres a leur bonne place + $b = new Barre_outils($this->baseParamsBarre); + $this->assertEqual('spip', $b->nameSpace); + $this->assertEqual('header1', $b->markupSet[0]['id']); + $this->assertEqual(7, count($b->markupSet[0])); + } + + function testInitialisationBarreEtendue(){ + // parametres inseres a leur bonne place, + // meme quand il y a des sous-menu d'icones + $b = new Barre_outils($this->baseParamsBarreEtendue); + $this->assertEqual('spip', $b->nameSpace); + $this->assertEqual('header1', $b->markupSet[0]['id']); + $this->assertEqual(7, count($b->markupSet[0])); + $this->assertEqual('couleurs', $b->markupSet[1]['id']); + $this->assertEqual(3, count($b->markupSet[1]['dropMenu'])); + } + + function testOptionsIncorrectesNonIncluses(){ + $p = $this->baseParamsBarre; + $p['fausseVariable'] = "je ne dois pas m'installer"; + $p['markupSet'][0]['fauxParam'] = "je ne dois pas m'installer"; + $b = new Barre_outils($p); + $this->assertEqual('spip',$b->nameSpace); + $this->assertNull($b->fausseVariable); + $this->assertNull($b->markupSet[0]['fauxParam']); + $this->assertEqual(7, count($b->markupSet[0])); + } + + function testRecuperationDeParametreAvecGet(){ + // trouver des id de premier niveau + $p = $this->baseParamsBarre; + $b = new Barre_outils($p); + $this->assertEqual($b->get('header1'), $p['markupSet'][0]); + + // trouver des id de second niveau + $p = $this->baseParamsBarreEtendue; + $b = new Barre_outils($p); + $this->assertEqual($b->get('header1'), $p['markupSet'][0]); + $this->assertEqual($b->get('couleurs'), $p['markupSet'][1]); + $this->assertEqual($b->get('couleur_jaune'), $p['markupSet'][1]['dropMenu'][0]); + $this->assertEqual($b->get('couleur_orange'), $p['markupSet'][1]['dropMenu'][1]); + $this->assertEqual($b->get('couleur_rouge'), $p['markupSet'][1]['dropMenu'][2]); + + // ne pas trouver d'id inconnu + $this->assertFalse($b->get('je_nexiste_pas')); + } + + function testModificationDeParametresAvecSet(){ + $p = $this->baseParamsBarre; + $b = new Barre_outils($p); + $p['markupSet'][0]['name'] = 'New'; + $r = $p['markupSet'][0]; + $x = $b->set('header1', array("name"=>"New")); + + $this->assertEqual($r, $x); // set retourne la chaine modifiee complete + $this->assertEqual($r, $b->get('header1')); + + // on ne peut ajouter de mauvais parametres + $x = $b->set('header1', array("Je Suis Pas Bon"=>"No no no")); + $this->assertEqual($r, $x); // set retourne la chaine modifiee complete + $this->assertEqual($r, $b->get('header1')); + } + + function testAjoutDeParametresApres(){ + $b = new Barre_outils($this->baseParamsBarre); + $p = $this->baseParamsBarreEtendue; + + // ajoutons la couleur apres + $b->ajouterApres('header1',$p['markupSet'][1]); + $this->assertEqual(2, count($b->markupSet)); // 2 boutons de premier niveau maintenant + $this->assertEqual($b->get('couleurs'), $p['markupSet'][1]); // get renvoie bien le bon ajout + $this->assertEqual($b->markupSet[1], $p['markupSet'][1]); // et l'ajout est au bon endroit + + // ajoutons une couleur dans l'ajout + $coul = $p['markupSet'][1]['dropMenu'][0]; + $coul['id'] = 'couleur_violette'; + $b->ajouterApres('couleur_orange',$coul); + $this->assertEqual(4, count($b->markupSet[1]['dropMenu'])); // sous boutons + $this->assertEqual($b->get('couleur_violette'), $coul); + $this->assertEqual($b->markupSet[1]['dropMenu'][2], $coul); // insertion au bon endroit + + // ajoutons un header2 encore apres + $p['markupSet'][0]['id'] = 'header2'; + $b->ajouterApres('couleurs',$p['markupSet'][0]); + $this->assertEqual(3, count($b->markupSet)); + $this->assertEqual($b->get('header2'), $p['markupSet'][0]); + $this->assertEqual($b->markupSet[2], $p['markupSet'][0]); + } + + function testAjoutDeParametresAvant(){ + $b = new Barre_outils($this->baseParamsBarre); + $p = $this->baseParamsBarreEtendue; + + // ajoutons la couleur apres + $b->ajouterAvant('header1',$p['markupSet'][1]); + $this->assertEqual(2, count($b->markupSet)); // 2 boutons de premier niveau maintenant + $this->assertEqual($b->get('couleurs'), $p['markupSet'][1]); // get renvoie bien le bon ajout + $this->assertEqual($b->markupSet[0], $p['markupSet'][1]); // et l'ajout est au bon endroit + + // ajoutons une couleur dans l'ajout + $coul = $p['markupSet'][1]['dropMenu'][0]; + $coul['id'] = 'couleur_violette'; + $b->ajouterAvant('couleur_orange',$coul); + $this->assertEqual(4, count($b->markupSet[0]['dropMenu'])); // sous boutons + $this->assertEqual($b->get('couleur_violette'), $coul); + $this->assertEqual($b->markupSet[0]['dropMenu'][1], $coul); // insertion au bon endroit + + // ajoutons un header2 avant le 1 + $p['markupSet'][0]['id'] = 'header2'; + $b->ajouterAvant('header1',$p['markupSet'][0]); + $this->assertEqual(3, count($b->markupSet)); + $this->assertEqual($b->get('header2'), $p['markupSet'][0]); + $this->assertEqual($b->markupSet[1], $p['markupSet'][0]); + } + + function testAfficherEtCacher(){ + $b = new Barre_outils($this->baseParamsBarre); + $b->cacher('header1'); + $this->assertFalse($b->markupSet[0]['display']); + $b->afficher('header1'); + $this->assertTrue($b->markupSet[0]['display']); + } + + function testAfficherEtCacherTout(){ + $b = new Barre_outils($this->baseParamsBarreEtendue); + $b->cacherTout(); + $this->assertFalse($b->markupSet[0]['display']); + $this->assertFalse($b->markupSet[1]['dropMenu'][0]['display']); + + $b->afficherTout(); + $this->assertTrue($b->markupSet[0]['display']); + $this->assertTrue($b->markupSet[1]['dropMenu'][0]['display']); + } + + function testAfficherEtCacherPlusieursBoutons(){ + $b = new Barre_outils($this->baseParamsBarreEtendue); + $b->cacher(array('header1','couleur_jaune')); + $this->assertFalse($b->markupSet[0]['display']); + $this->assertFalse($b->markupSet[1]['dropMenu'][0]['display']); + $this->assertTrue($b->markupSet[1]['dropMenu'][1]['display']); + + $b->cacherTout(); + $b->afficher(array('header1','couleur_jaune')); + $this->assertTrue($b->markupSet[0]['display']); + $this->assertTrue($b->markupSet[1]['dropMenu'][0]['display']); + $this->assertFalse($b->markupSet[1]['dropMenu'][1]['display']); + } + + function testSetAvecIdVideNeDoitRienModifier(){ + $b = new Barre_outils($this->baseParamsBarreEtendue); + $b->set(array(),array('display'=>false)); + $this->assertTrue($b->markupSet[0]['display']); + $this->assertTrue($b->markupSet[1]['dropMenu'][0]['display']); + } + + function testSetAvecIdArrayDoitModifTousLesIds(){ + $b = new Barre_outils($this->baseParamsBarreEtendue); + $b->set(array('header1','couleur_jaune'),array('display'=>false)); + $this->assertFalse($b->markupSet[0]['display']); + $this->assertFalse($b->markupSet[1]['dropMenu'][0]['display']); + $this->assertTrue($b->markupSet[1]['dropMenu'][1]['display']); + } + + function testCreerJson(){ + $b = new Barre_outils($this->baseParamsBarre); + $b->ajouterApres('header1', array( + "id" => 'Caracteres decodes', + "name" => "étrange", + "className" => "outil_fr", + "openWith" => "[fr]", + "display" => true, + )); + $json = $b->creer_json(); + $this->assertPattern(',barre_outils_spip = {,',$json); + $this->assertPattern(',\[{"name":",',$json); + $this->assertNoPattern(',eacute;,',$json); + } + + function testBoutonsDUneLangue(){ + $b = new Barre_outils($this->baseParamsBarre); + $ico2 = $ico1 = array( + "id" => 'ico_fr1', + "name" => "test apparaissant si langue est le francais", + "className" => "outil_fr", + "openWith" => "[fr]", + "lang" => array("fr"), + "display" => true, + ); + $ico2['id'] = 'ico_fr2'; + $ico2['lang'] = array("fr","en","es"); + + $b->ajouterApres('header1', $ico1); + $b->ajouterApres('ico_fr1', $ico2); + $this->assertEqual($ico1, $b->get('ico_fr1')); + $this->assertEqual($ico2, $b->get('ico_fr2')); + + // verifier que ces nouveaux array() + // ne posent pas de problemes dans les recursions + $b->cacherTout(); + $this->assertFalse($b->markupSet[1]['display']); + $b->afficher('ico_fr1'); + $this->assertTrue($b->markupSet[1]['display']); + $b->cacherTout(); + $b->afficher(array('ico_fr1','ico_fr2')); + $this->assertTrue($b->markupSet[1]['display']); + + // la langue est bien transmise au json + $json = $b->creer_json(); + $this->assertPattern(',"lang":\[,', $json); + } + + + function testFonctionsJavacriptDansParametreNeDoitPasEtreEntreguillemetsDansJson(){ + $b = new Barre_outils($this->baseParamsBarre); + $clean = array( + "id" => 'clean', + "name" => _T('barre_outils:barre_clean'), + "className" => "outil_clean", + // function doit etre echappe + "replaceWith" => 'function(markitup) { return markitup.selection.replace(/<(.*?)>/g, "") }', + "display" => true, + ); + $b->ajouterApres('header1', $clean); + $json = $b->creer_json(); + // pas de :"function(... ..." + $this->assertPattern('/:function\(/',$json); + } + + function testParametreFunctionsDansJson(){ + $b = new Barre_outils($this->baseParamsBarre); + $b->functions = "function dido(){}"; + $json = $b->creer_json(); + // function n'est plus dans la barre + $this->assertFalse($b->functions); + // mais uniquement en fin du fichier json + $this->assertPattern('/function dido\(/', $json); + } + + function testAjouterFonctions(){ + $b = new Barre_outils($this->baseParamsBarre); + $b->Ajouterfonction("function dido(){}"); + $this->assertPattern('/function dido\(/', $b->fonctions); + } + + /* + function squeletteTest(){ + $sq = new SqueletteTest("SimpleTest"); + $sq->addInsertHead(); + $sq->addToBody(" +
      +
      + +
      +
      + "); + return $sq; + } + + function testPresenceBarreOutilPublique(){ + include_spip('simpletest/browser'); + include_spip('simpletest/web_tester'); + + $sq = $this->squeletteTest(); + + $browser = &new SimpleBrowser(); + $browser->get($f=$this->urlTestCode($sq->code())); + $browser->setField('texte', 'me'); + $this->dump($browser->getField('texte')); + $this->dump($browser->getContent()); + #$this->dump($c); + #$this->assertPattern('/jquery\.markitup_pour_spip\.js/', $c); + }*/ +} + + +?> diff --git a/tests/lanceur_spip.php b/tests/lanceur_spip.php new file mode 100644 index 0000000..b14b355 --- /dev/null +++ b/tests/lanceur_spip.php @@ -0,0 +1,36 @@ +Echec : SPIP ne peut pas etre demarre automatiquement pour le test.
      + Vous utilisez certainement un lien symbolique dans votre repertoire plugins."); +} +include_spip('inc/tests'); +if (!class_exists('SpipTestSuite')) { + die("Echec : le plugin pour les tests unitaires avec SimpleTest ne semble pas actif."); +} +?>