1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/日本語アンカー名
#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## の前にて、以下を挿入
  ((継承している##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