Table of Contents

À propos de ce site

Bon, pourquoi avoir choisi un Wiki pour un site perso plutôt que du HTML pur, WML, Mambo, SPIP, [ou autre selon vos préférences] ?

En fait, c'est tout simple, je voulais essayer autre chose que le WML (Website Meta Language). Un Wiki paraît bien et DokuWiki génère des pages plutôt jolies. Par ailleurs, un Wiki s'avérera utile pour des contributions externes aux pages d'aide de Basilisk II ou SheepShaver. ;-)

Les plugins DokuWiki suivants sont installés: Boxes, Include. Par ailleurs, une barre de navigation est également disponible à gauche. Ces extensions sont légèrement adaptées à mes besoins, voir plus bas pour les détails (patches pour parties GPL). Le cannevas ACH est également utilisé.

Patches

Dokuwiki

Je voulais que {{this}} pointe vers la racine de ce site. Bon, il est vrai que basedir ou baseurl auraient pu faire l'affaire aussi.

--- dokuwiki-2005-09-22/inc/confutils.php	2005-09-22 19:21:09.000000000 +0200
+++ dokuwiki/inc/confutils.php	2005-11-07 21:19:30.000000000 +0100
@@ -111,7 +111,7 @@ function getInterwiki() {
     }
   }
   //add sepecial case 'this'
-  $wikis['this'] = DOKU_URL.'{NAME}';
+  $wikis['this'] = DOKU_URL.'../{NAME}';
   return $wikis;
 }

Include Plugin

Je ne veux pas de fioritures autour des pages inclues.

--- dokuwiki/lib/plugins/include/syntax.php	2005-09-27 02:13:04.000000000 +0200
+++ dokuwiki/lib/plugins/include/syntax.php	2005-11-13 21:35:41.000000000 +0100
@@ -122,9 +122,7 @@ class syntax_plugin_include extends Doku
             $renderer->info['cache'] = FALSE;
 
             // embed the included page
-            $renderer->doc .= '<div class="include">';
             $renderer->doc .= $text;
-            $renderer->doc .= '</div>';
             return true;
         }
         return false;

Support multi-langues

Le support multi-langues est très basique ici. Le nom du namespace principal permet d'identifier la langue du document. À cet effet, les chemins et noms des pages doivent être identiques, quelque soit la langue choisie (français ou anglais ici). Ce patch suppose que le modèle sidebar est utilisé mais peut très bien être adapté à d'autres.

Remarque: je ne connais pas PHP donc il existe sans doute un moyen de faire cela plus proprement.

--- dokuwiki-2005-09-22/inc/template.php	2005-10-21 13:43:58.000000000 +0200
+++ dokuwiki/inc/template.php	2005-11-12 11:35:00.000000000 +0100
@@ -248,6 +248,28 @@ function tpl_link($url,$name,$more=''){
 }
 
 /**
+ * Print links to alternate language pages
+ */
+function tpl_lang_links($pagename){
+  global $conf;
+  $path = explode(':', $pagename);
+  $lang = $path[0];
+  if (in_array($lang, $conf['available_languages'])) {
+    foreach ($conf['available_languages'] as $l) {
+      if ($l != $lang) {
+        $path[0] = $l;
+        $new_id = implode(':', $path);
+        if (@file_exists(wikiFN($new_id))) {
+          print "<div class=\"pagename\">[[";
+          tpl_link(wl($new_id), $l);
+          print "]]</div>\n";
+        }
+      }
+    }
+  }
+}
+
+/**
  * Prints a link to a WikiPage
  *
  * Wrapper around html_wikilink
--- dokuwiki-2005-09-22/lib/tpl/sidebar/main.php	2005-09-20 14:19:56.000000000 +0200
+++ dokuwiki/lib/tpl/sidebar/main.php	2005-11-07 21:25:00.000000000 +0100
@@ -71,6 +71,7 @@ include(dirname(__FILE__).'/sidebar.php'
       <div class="pagename">
         [[<?php tpl_link(wl($ID,'do=backlink'),$ID)?>]]
       </div>
+      <?php tpl_lang_links($ID)?>
     </div>
 
     <?php /*old includehook*/ @include(dirname(__FILE__).'/header.html')?>

Autres Plugins

Partial Include

Ce plugin permet d'inclure partiellement une page dans une autre, et ce avec n_sections sections au maximum. Une section est identifiée par des blocs head (H1, H2, etc.) ou des listes pour le niveau optional_min_level, si précisé (valeur par défaut: 1). Bon, ce plugin fonctionne pour mes besoins, et peut misérablement foirer pour d'autres personnes. À noter que quand le nombre maximal de sections est atteint, un lien ([...]) vers les autres est ajouté.

Ce code est dérivé des plugins Include et Blog, donc lui aussi placé sous GPL.

<?php
/**
 * Partial Include Plugin: displays parts of a wiki page within another
 * Usage:
 * {{subpage>page}} for "page" in same namespace
 * {{subpage>:page}} for "page" in top namespace
 * {{subpage>namespace:page}} for "page" in namespace "namespace"
 * {{subpage>.namespace:page}} for "page" in subnamespace "namespace"
 * {{subpage>page#n_sections;optional_min_level}} for a section of "page"
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Gwenole Beauchesne <masked-email>
 */
 
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
 
/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class syntax_plugin_partial_include extends DokuWiki_Syntax_Plugin {
 
    /**
     * return some info
     */
    function getInfo(){
        return array(
            'author' => 'Gwenole Beauchesne',
            'email'  => '<masked-email>',
            'date'   => '2005-11-01',
            'name'   => 'Partial Include Plugin',
            'desc'   => 'displays parts of a wiki page within another',
            'url'    => '',
        );
    }
 
    /**
     * What kind of syntax are we?
     */
    function getType(){
        return 'substition';
    }
 
    /**
     * Where to sort in?
     */
    function getSort(){
        return 309;
    }
 
    /**
     * Paragraph Type
     */
    function getPType(){
        return 'block';
    }
 
    /**
     * Connect pattern to lexer
     */
    function connectTo($mode) {
        $this->Lexer->addSpecialPattern('\{\{subpage.+?\}\}',$mode,'plugin_partial_include');
    }
 
    /**
     * Handle the match
     */
    function handle($match, $state, $pos, &$handler){
        global $ID;
        global $filechain;
 
        $match = substr($match,10,-2);                // strip markup
        $match = preg_split('/\#/u',$match,2);        // split hash from filename
        resolve_pageid(getNS($ID),$match[0],$exists); // resolve shortcuts
 
        // check for existence and permission
        if ((!$exists) || (auth_quickaclcheck($match[0]) < 1)) return false;
 
        // check for and establish start of $filechain
        if (!isset($filechain)) $filechain[] = $ID;
 
        // don't allow the same file to be included more than once
        if (in_array($match[0], $filechain)) return false;
 
        // add included page to the filechain
        $filechain[] = $match[0];
 
        // get sections information
        list($num, $level, $type) = explode(';',$match[1],3);
        if ($num == 0)
            $num = 1;
        if ($level == 0)
            $level = 1;
        if ($type == '')
            $type = 'header';
        switch ($type) {
        case 'header': case 'list': break;
        default: return false;
        }
 
        return array($match[0], $num, $level, $type);
    }    
 
    /**
     * Create output
     */
    function render($mode, &$renderer, $data) {
 
        if($mode == 'xhtml'){
            $file = wikiFN($data[0]);
            if (!@file_exists($file)) return false;
 
            // get instructions
            $instr = p_cached_instructions($file, false);
 
            // filter section
            $instr = $this->{'_getSection_'.$data[3]}($data[1], $data[2], $more, $instr);
 
            // correct relative internal links and media
            $instr = $this->_correctRelNS($instr, $data[0]);
 
            // render the instructions on the fly
            $text = p_render('xhtml',$instr,$info);
 
            // remove toc, section edit buttons and category tags
            $patterns = array('!<div class="toc">.*?(</div>\n</div>)!s',
                              '#<!-- SECTION \[(\d*-\d*)\] -->#e',
                              '!<div class="category">.*?</div>!s');
            $replace  = array('','','');
            $text = preg_replace($patterns,$replace,$text);
 
            // prevent caching to ensure the included page is always fresh
            $renderer->info['cache'] = FALSE;
 
            // embed the included page
            $renderer->doc .= $text;
 
            // append continuation link
            if ($more) {
                $level = $data[2];
                $mlink = $renderer->internallink($data[0],'...','','true');
                switch ($data[3]) {
                case 'header':
                    $renderer->doc .= "<div class=\"level$level\">[$mlink]</div>";
                    break;
                case 'list': // <ul> is open at this stage
                    $renderer->doc .= "<li class=\"level$level\"><div class=\"li\">[$mlink]</div></li></ul>";
                }
            }
 
            return true;
        }
        return false;
    }
 
    /**
     * Get N 'header' sections including their subsections
     */
    function _getSection_header($max_sections,$min_level,&$more,$instructions){
        $more = 0;
        $n_sections = 0;
        foreach ($instructions as $instruction){
            if ($instruction[0] == 'header'){
                $level = $instruction[1][1];
                if ($level >= $min_level) {
                    if ($level == $min_level) {
                        $n_sections += 1;
                        if ($n_sections > $max_sections) {
                            $more = 1;
                            return $i;
                        }
                    }
                    $i[] = $instruction;
                } elseif ($n_sections && $level < $min_level)
                    return $i;
            } elseif ($n_sections) {
                $i[] = $instruction;
            }
        }
        return $i;
    }
 
    /**
     * Get N 'list items including their sublists
     * XXX factorisation candidate
     */
    function _getSection_list($max_sections,$min_level,&$more,$instructions){
        $more = 0;
        $n_sections = 0;
        for ($it = 0; $it < sizeof($instructions); $it++){
            $instruction = $instructions[$it];
            if ($instruction[0] == 'listitem_open'){
                $level = $instruction[1][0];
                if ($level >= $min_level) {
                    if ($level == $min_level) {
                        $n_sections += 1;
                        if ($n_sections == 1) 
                            $i[] = $instructions[$it-1];
                        elseif ($n_sections > $max_sections) {
                            $more = 1;
                            return $i;
                        }
                    }
                    $i[] = $instruction;
                } elseif ($n_sections && $level < $min_level)
                    return $i;
            } elseif ($n_sections) {
                $i[] = $instruction;
            }
        }
        return $i;
    }
 
    /**
     * Corrects relative internal links and media
     */
    function _correctRelNS($instr,$incl){
        global $ID;
 
        // check if included page is in same namespace
        $iNS = getNS($incl);
        if (getNS($ID) == $iNS) return $instr;
 
        // convert internal links and media from relative to absolute
        $n = count($instr);
        for($i = 0; $i < $n; $i++){
            if (substr($instr[$i][0], 0, 8) == 'internal'){
 
                // relative subnamespace
                if ($instr[$i][1][0]{0} == '.'){
                    $instr[$i][1][0] = $iNS.':'.substr($instr[$i][1][0], 1);
 
                // relative link
                } elseif (strpos($instr[$i][1][0],':') === false) {
                    $instr[$i][1][0] = $iNS.':'.$instr[$i][1][0];
                }
            }
        }
        return $instr;
    }
}
 
//Setup VIM: ex: et ts=4 enc=utf-8 :

Downloads

Il s'agit en fait d'un plugin multi-inclusion de pages nomméés de la façon suivante: dist_AAAAMMJJ. Les pages sont obtenues du namespace donné et au maximum count éléments sont affichés.

Ce code dérive du plugin Include et il est donc placé sous GPL.

<?php
/**
 * Downloads Plugin: agglomerate several download wiki pages into another
 * Usage:
 * {{downloads>namespace}} add all dist_YYYYMMDD wiki pages from namespace
 * {{downloads>namespace#count}} add at most count wiki pages
 *
 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
 * @author     Gwenole Beauchesne <masked-email>
 */
 
if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');
 
 
/**
 * All DokuWiki plugins to extend the parser/rendering mechanism
 * need to inherit from this class
 */
class syntax_plugin_downloads extends DokuWiki_Syntax_Plugin {
 
    /**
     * return some info
     */
    function getInfo(){
        return array(
            'author' => 'Gwenole Beauchesne',
            'email'  => '<masked-email>',
            'date'   => '2005-11-06',
            'name'   => 'Downloads Plugin',
            'desc'   => 'Agglomerate several download wiki pages within another',
            'url'    => '',
        );
    }
 
    /**
     * What kind of syntax are we?
     */
    function getType(){
        return 'substition';
    }
 
    /**
     * Where to sort in?
     */
    function getSort(){
        return 311;
    }
 
    /**
     * Paragraph Type
     */
    function getPType(){
        return 'block';
    }
 
    /**
     * Connect pattern to lexer
     */
    function connectTo($mode) {
      $this->Lexer->addSpecialPattern("{{downloads>.+?}}",$mode,'plugin_downloads');
    }
 
    /**
     * Handle the match
     */
    function handle($match, $state, $pos, &$handler){
        global $ID;
        global $filechain;
 
		$maxd = 100;                                  // more than 100 downloads pages is getting insane
        $match = substr($match,12,-2);                // strip markup
        list($ns,$num) = explode('#',$match,2);       // split hash from namespace
        if (!is_numeric($num)) $num = $maxd;          // default to "all" download items
 
        function _isDistID($id) {
          list($tag,$date) = explode('_',noNS($id),2);
          return $tag === 'dist' && is_numeric($date);
        }
 
        $dpages = array_map(create_function('$var','return $var["id"];'),getRecents(0,$maxd,false,$ns,false));
        $dpages = array_filter($dpages, '_isDistID');
		if (!rsort($dpages)) return false;
		$chunks = array_chunk($dpages,$num);
		$dpages = $chunks[0];
 
        // check for and establish start of $filechain
        if (!isset($filechain)) $filechain[] = $ID;
 
        // don't allow the same file to be included more than once
        if (in_array($match[0], $filechain)) return false;
 
        // add included pages to the filechain
        $filechain = array_merge($filechain, $dpages);
 
        return $dpages;
    }    
 
    /**
     * Create output
     */
    function render($mode, &$renderer, $data) {
 
        if($mode == 'xhtml'){
          for ($i = 0; $i < sizeof($data); $i++){
            $id = $data[$i];
            $file = wikiFN($id);
            if (!@file_exists($file)) return false;
 
            // get instructions
            $instr = p_cached_instructions($file, false);
 
            // correct relative internal links and media
            $instr = $this->_correctRelNS($instr, $id);
 
            // render the instructructions on the fly
            $text = p_render('xhtml',$instr,$info);
 
            // remove toc, section edit buttons and category tags
            $patterns = array('!<div class="toc">.*?(</div>\n</div>)!s',
                              '#<!-- SECTION \[(\d*-\d*)\] -->#e',
                              '!<div class="category">.*?</div>!s');
            $replace  = array('','','');
            $text = preg_replace($patterns,$replace,$text);
 
            // prevent caching to ensure the included page is always fresh
            $renderer->info['cache'] = FALSE;
 
            // embed the included page
            if ($i)
              $renderer->doc .= '<hr noshade="noshade" size="1" />';
            $renderer->doc .= $text;
          }
          return true;
        }
        return false;
    }
 
    /**
     * Corrects relative internal links and media
     */
    function _correctRelNS($instr,$incl){
        global $ID;
 
        // check if included page is in same namespace
        $iNS = getNS($incl);
        if (getNS($ID) == $iNS) return $instr;
 
        // convert internal links and media from relative to absolute
        $n = count($instr);
        for($i = 0; $i < $n; $i++){
            if (substr($instr[$i][0], 0, 8) == 'internal'){
 
                // relative subnamespace
                if ($instr[$i][1][0]{0} == '.'){
 
                    $instr[$i][1][0] = $iNS.':'.substr($instr[$i][1][0], 1);
 
                // relative link
                } elseif (strpos($instr[$i][1][0],':') === false) {
                    $instr[$i][1][0] = $iNS.':'.$instr[$i][1][0];
                }
            }
        }
        return $instr;
    }
}
 
//Setup VIM: ex: et ts=4 enc=utf-8 :