/日本語アンカー名
#indent
#contents

////////////////////////////////////////////////////////////////
*方針 [#wbd776ad]
 
日本語のページ名を設定できることが PukiWiki 流派の売りの一つ。
しかし、アンカー名は HTML の制約を受けて英字限定のままである。

Wiki は HTML ではない。
Wiki は HTML のできないことをして良い。
日本語のページが必要とされるように、日本語のアンカー名も必要である。

また、日本語のページ名に対応するため、PukiWiki では「ブラケット名」と呼ばれる以下の構文を導入している。
###
   [[ページ名#アンカー名]]
###
これに対し、アンカーを下ろすには aname プラグインを使う必要がある。
###
   &aname(アンカー名);
###
この非対称を無くすため、そして、アンカーを目立たせるため、
aname に対応した Wiki 構文 = [[ネイティブエイリアス>../ネイティブエイリアス]]を設けべし。
 
////////////////////////////////////////////////////////////////
* 仕様 [#q38acc3a]
////////////////////////////////////////////////////////////////
** アンカープラグイン aname とブラケット書式 ##[&[;〜&];]##の仕様変更 [#xfd8274a]
アンカーに日本語を許す。
ただし、半角記号「##[>#]##」は書式に使用するため、アンカー文字に使用不可とする。

** アンカーのエンコード方式 [#hc15664a]
アンカーのエンコードは PukiWiki に使われる URL のエンコード方式を流用する。
ただし、HTML の id の仕様を満たすため、以下の変換とする。
#ceq(e)
    変換規則
#ceq(q)
    例:アンカー名
#ceq(a)
    目的
#ceq(e)
    1. rawurlencode で URL 文字列に変換
#ceq(q)
    %A5%A2%A5%F3%A5%AB%A1%BC%CC%BE
#ceq(a)
    PukiWiki の URL エンコード方式
#ceq(e)
    2. 「##%##」を「##_##」に置換
#ceq(q)
    _A5_A2_A5_F3_A5_AB_A1_BC_CC_BE
#ceq(a)
    HTML の id では「%」を使用不能。
#ceq(e)
    3. 「Anchor」を先頭に付加
#ceq(q)
    Anchor_A5_A2_A5_F3_A5_AB_A1_BC_CC_BE
#ceq(a)
    HTML の id は「_」を先頭に配置不能。Anchorであることを明示。
#ceq(end)

** ネイティブエイリアス ##[&[;[〜]&];]## [#db881104]
リンクのネイティブ書式が ##&[;[〜]&];## に因み、アンカーを ##[&[;[〜]&];]## とする。
これは、似た目的のインライン書式に同じ記号を割り当てる Wiki の方針に則っている。
|      |l:lx:            |lx:       |lx:      |l:lx:              |c
|太字  |: ##'&';〜&';'##|## ⇔ ##|斜体     |: ##'&';'〜'&';'##|
|削除  |: ##%&%;〜&%;%##|## ⇔ ##|更新     |: ##%&%;%〜%&%;%##|
|リンク|: ##[&[;〜&];]##|## ⇔ ##|アンカー |: ##[&[;[〜]&];]##|

##[&[;〜&];]## 自体の拡張も検討したが、##[&[;〜&];]## が既に複雑であることを考慮し、別書式とした。
- 例: アンカー ##[&[;#&#;〜&];]## ## ⇔ ## リンク ##[&[;#〜&];]##

ネイティブエイリアス##[&[;[〜]&];]##の書式を以下の3つのモードとする。
:アンカーのみ ##[&[;[&#;## '''Anchor''' ##]&];]##|
-'''Anchor''' をアンカーに設定する。
-アンカー位置には何も表示しない。
:エイリアス指定 ##[&[;[## '''Alias''' ##]&];]##|
-'''Alias'''をアンカーに設定する。
-アンカー位置に'''Alias'''を表示する。
:エイリアスとアンカーの同時指定 ##[&[;[## '''Alias''' ># '''Anchor''' ##]&];]##|
-'''Anchor''' をアンカーに設定する。
-アンカー位置に'''Alias'''を表示する。
 
////////////////////////////////////////////////////////////////
* 実装 [#g668057c]
////////////////////////////////////////////////////////////////
** プラグイン aname [#y4dab69e]
- ##plugin/aname.inc.php## の先頭、グローバル領域にて、
    #code(diff){{{{
        // Max length of ID
    -   define('PLUGIN_ANAME_ID_MAX',   40);
    +   define('PLUGIN_ANAME_ID_MAX',   1024);
    }}}}
    日本語アンカーのエンコード結果が、半角40文字を容易に超えるために拡張した。
    HTML としては id の最大長を指定してないようだが、実用的文字数とブラウザの実装限界を考慮して 1024 と決め付けた。
- ##plugin/aname.inc.php## の ##function lugin_aname_tag## の中、##id## を取得直後に以下を追加。
    #code(diff){{{{
        function plugin_aname_tag($args = array(), $convert = TRUE)
        {
            ...
            
            $id = array_shift($args);
    +       if (! preg_match(PLUGIN_ANAME_ID_REGEX, $id))
    +       {
    +           $id = rawurlencode($id);
    +           $id = 'Anchor' . str_replace('%', '_', $id);
    +       }
    }}}}

////////////////////////////////////////////////////////////////
** ブラケット書式 ##[&[;〜&];]## [#xbc98cc4]
- ##lib/make_link.inc.php## の先頭、グローバル領域にて、##plugin/aname.inc.php## で設定されているアンカー名の正規表現を設定する。
    #code(diff){{{{
    +   // Pattern of ID
    +   define('PLUGIN_ANAME_ID_REGEX', '/^[A-Za-z][\w\-]*$/');
    }}}}
- ##lib/make_link.inc.php## の中ほど、##class Link_bracketname extends Link## の ##function get_pattern## にて、##return## 対象の正規表現を変更。
    #code(diff){{{{
            function get_pattern()
            {
                global $WikiName, $BracketName;
            
                $s2 = $this->start + 2;
                return <<<EOD
        \[\[                     # Open bracket
        (?:((?:(?!\]\]).)+)>)?   # (1) Alias
        (\[\[)?                  # (2) Open bracket
        (                        # (3) PageName
         (?:$WikiName)
         |
         (?:$BracketName)
        )?
    -   (\#(?:[a-zA-Z][\w-]*)?)? # (4) Anchor
    +   (?:\#([^\[\>\#\]]+)?)?   # (4) Anchor
        (?($s2)\]\])             # Close bracket if (2)
        \]\]                     # Close bracket
        EOD;
            }
    }}}}
- ##lib/make_link.inc.php## の中ほど、##class Link_bracketname extends Link## の ##function toString## にて、
    #code(diff){{{{
    +           if (! preg_match(PLUGIN_ANAME_ID_REGEX,$this->anchor))
    +           {
    +               $this->anchor = rawurlencode($this->anchor);
    +               $this->anchor = 'Anchor' . str_replace('%', '_', $this->anchor);
    +           }
    +           $this->anchor = '#'.$this->anchor;
    +           
                return make_pagelink(
                    $this->name,
                    $this->alias,
                    $this->anchor,
                    $this->page
    }}}}
////////////////////////////////////////////////////////////////
** ネイティブエイリアス ##[&[;[〜]&];]## [#z82f4475]

- ##lib/make_link.inc.php## の先頭、##class InlineConverter## の ##function InlineConverter## にて、##'bracketname'## を登録直前、
    #code(diff){{{{
            function InlineConverter($converters = NULL, $excludes = NULL)
            {
                if ($converters === NULL) {
                    $converters = array(
                        ...
    +                   'bracketanchor', // BracketAnchor
                        'bracketname',   // BracketName
                        ...
                    );
                }
    }}}}
    正規表現として ##[&[;[〜]&];]## は ##[&[;〜&];]## に包含されるため、'bracketanchor' は必ず 'bracketname' の前に登録する必要がある。
- ##lib/make_link.inc.php## の中ほど、##class Link_bracketname## の前にて、以下を挿入。
- ##lib/make_link.inc.php## の中ほど、##class Link_bracketname## の前にて、以下を挿入
  ((継承している##Link_plugin_alias## は [[ネイティブエイリアス>../ネイティブエイリアス]] で実装したクラスである。))。
    #code(php){{{{
        // BracketAnchor
        // Native-alias for &aname plugin
        class Link_bracketanchor extends Link_plugin_alias
        {
            var $name    = 'aname';
            var $pattern = '\[\[\[(()(?:([^\[\>\#\]]+)>?)?(?:\#?([^\[\]\>\#]+?))?)\]\]\]';
            
            function set($arr, $page)
            {
                list(, $this->plain, , $body, $this->param) = $this->splice($arr);
                if ($this->param == '') {$this->param = $body;}                         // アンカー省略=エイリアスをアンカーに使用
                return parent::setParam($page, $this->name, $body, 'plugin');
            }
        }
    }}}}
%bodynote

////////////////////////////////////////////////////////////////
* 課題 [#l64ec37e]

- 見出しのアンカー ##[#〜]## をアンカーのネイティブエイリアス ##[&[;[〜]&];]## に統合すべし。
-- 見出しのハッシュではなく、文字列自体をアンカーにすべし。
--- 今でも ##**[&[;[見出し1]&];]## のようにコーディングすれば一応できるけど。
--- アンカーの禁止文字「##[>#]##」を何とかすべし。
-- 見出しの階層構造に応じたアンカーの階層化を検討すべし。
--- 例: ##ページ階層1/ページ階層2/ページ名#見出し1/見出し1-1/見出し1-1-1 ##
--- 例: ##ページ階層1/ページ階層2/ページ名#見出し1-1-1 ## ← も衝突しない限り可能にしたい。


////////////////////////////////////////////////////////////////
    初基 一覧 検索 最新 バックアップ リンク元   ヘルプ   最終更新のRSS