小説サイトのJavaScript Chips

第4回 小説ページのリンクナビゲーション

 小説ページにいつもあるもののひとつがナビゲーション。
「前のページへ、次のページへ」のリンクです。
 当サイトの小説ページではページの上部と下部に設置しています。
 サンプルはこれ ↓ (動作しません)

<<戻る      目次      進む>>

 まずはこれのhtmlを。

<p>
<a href="前のページ.html"><<戻る□□□□□
<a href="目次ページ.html">目次□□□□□
<a href="次のページ.html">進む>>
</p>

 cssはこんな感じ。

background-color	:#ffffff;
border-top	:1px solid #666666;
border-bottom	:1px solid #666666;
line-height	:3;
text-align	:center;

 でも、このナビゲーション。いつも必ずあるものなんだけど、いつもリンク先が違う面倒なものです。
 hrefの指定をうっかり間違えると、はい、乱丁の出来上がり。
 そこで、これを毎回指定しなおさなくてもよいように考えました。
「よし。現在のページを取得して、前のページは−1、次のページは+1だ!」
 幸運なことに、ファイル名は連番でした。
(連番でなかったファイルは連番にしちゃいました)
 例えば、風紋の場合はこんな感じ。

 目次ページ:st.html
 第一夜 一:st_00.html
 第一夜 二:st_01.html
 第一夜 三:st_02.html
 第一夜 四:st_03.html
 第二夜 一:st_04.html
 ……
 第七夜 一:st_16.html  ←今、ここ(笑)

なので、ナビゲーションはこうなります。

第三夜 四の場合 ファイル名は「st_10.html」
<p>
	<a href="st_09.html"><<戻る□□□□□
	<a href="st.html">目次□□□□□
	<a href="st_11.html">進む>>
</p>

 もちろん、htmlですべてのページに記入すればいいのです。
 だけどわたしは自他共に認める「面倒くさがり屋」。
 コピー&ペースト+修正 も、4ページ目からはイヤになりました。
 さらにプロットの変更があって間に1ページ追加、ということになろうものなら、以降のページは全部書換えです。……
 開いて修正して閉じて、開いて修正して閉じて、開いて修正して閉じて。
 タブ式エディタでも、開いて修正して、タブを移動して修正して、タブを移動して修正して。だんだん、気分がくさってきます。
 そこで、これもjavascriptで記述することにしました。

 基本はやっぱり、「document.write」(htmlに文字を書き出す)。
 こんな風に記述します。


var last_page = 24;
var org = location.pathname;

varsp = org.split(".",2);
var num = sp[0].length;

var last_slash = sp[0].lastIndexOf("/",num);

var num0 = parseInt(sp[0].substring(num-1,num));
var num00 = parseInt(sp[0].substring(num-2,num-1));

var current_page = num0 + num00 * 10;
var prev_page = current_page-1;
var next_page = current_page+1;

var tail = "." + sp[1];
var file = sp[0].substring(last_slash+1,num-2);
var index = sp[0].substring(last_slash+1,num-3)+ tail;

var prev;
var next;

flag = isNaN(current_page)
if(flag){
	document.write("")
} else {
	if(prev_page == -1){
		prev = index;
	} else {
		if(prev_page < 10){
			prev = file + "0" + prev_page + tail;
		} else{
			prev = file + prev_page + tail;
		}
	}
	if(next_page > last_page){
		next = "none";
	} else{
		if(next_page < 10){
			next = file + "0" + next_page + tail;
		}else{
			next = file + next_page + tail;
		}
	}

	var index_url = "<a href=\""+ index + "\">";
	var prev_url = "<a href=\"" + prev + "\">";
	var next_url;

	if(next == "none"){
		next_url = "";
	} else {
		next_url = "<a href=\"" + next + "\">";
	}

	var navi = "<p>"
		+ prev_url
		+ "<<戻る</a>□□□□□"
		+ index_url
		+ "目次</a>□□□□□"
		+ next_url
		+ "次へ>></a></p>";

	document.write(navi);
}

 解説します。(解説は要らない、と言う方は、こちらを)
 最後の行をごらんください。
「document.write(navi);」
 これは、「document(この場合はそのページです)」の中に、「navi」を「write(記述)」しましょう、という意味です。
「navi」は、そのすぐ上の「var navi = ...」の部分です。
 ですが、この「navi」。このままhtmlで記述するとどうなるでしょう。

<p>
prev_url
<<戻る</a>□□□□□
index_url
目次</a>□□□□□
next_url
次へ>></a></p>

 こんな風に表示されますよね。


prev_url<<戻る     index_url目次     next_url次へ>>

 prev_url、index_url、next_url?
 ? なんでしょう?
 これはそれぞれ、前のページのURL、目次ページのURL、次のページのURLを表します。
 それが、var navi =...の前のカタマリ、
「var index_url="<a href=\""+ index + "\">";」から「}」までに記されています。
 index_urlは「<a href="index">」
 prev_urlは「<a href="prev">」
 next_urlは、条件が分岐しています。
 if(もし)next_page(次のurl)がnone(ない)場合は、""(記述内容なし)
 else(そうでなければ)"<a href="next">"をnext_urlに=(代入)する。
 これを、前出のhtmlに当てはめると、

<p>
<a href="prev"><<戻る</a>□□□□□
<a href="index">目次</a>□□□□□
<a href="next">次へ>></a>
</p>

<<戻る     目次     次へ>>

もしくは
<p>
<a href="prev"><<戻る</a>□□□□□
<a href="index">目次</a>□□□□□
次へ>>
</p>

<<戻る     目次     次へ>>

 と、なります。
 でも、まだこれでは動きません。prev、index、nextというファイルが存在しないからです。
 prev、index、nextにそれぞれのページ名を割りふらなくてはなりません。
 それが、その前のカタマリ、
「if(prev_page==-1){ 」から「next = file + next_page + tail;  } } 」です。
 ですが、ここで、冒頭部分を見てください。
 そろそろページ上部に戻るのが面倒くさくなってきたので、再度該当部分を表示します。

var last_page = 24;
var org = location.pathname;

var sp = org.split(".",2);
var num = sp[0].length;

var last_slash = sp[0].lastIndexOf("/",num);

var num0 = parseInt(sp[0].substring(num-1,num));
var num00 = parseInt(sp[0].substring(num-2,num-1));

var current_page = num0 + num00 * 10;
var prev_page = current_page-1;
var next_page = current_page+1;

var tail = "." + sp[1];
var file = sp[0].substring(last_slash+1,num-2);
var index = sp[0].substring(last_slash+1,num-3)+ tail;

var prev;
var next;

 これは、「宣言」を行なっている箇所です。
「この言葉は、こういう意味で使いますよ」という宣言、だと思っていただいて、たぶん、今は大丈夫です。
 一行目、「var last_page=24;」は
「last_page」と言われたら、それは24のことですよ、という意味です。
 このlast_pageというのは最後のページを表すのですが、これは「final_page」とか「saigo_no_page」とか、まあ、お好きな言葉で構いません。とりあえず、わたしは「last_page」にしました。思いついた中で一番、文字数が少なかったから(笑)
 行頭のvarは「変数宣言」で、省略できることもあります(省略できないこともあります《ローカル変数の場合ですね》)が、ここでは基本に忠実に(?)すべてを宣言しました。
 では、順に、何が宣言されているのか読んでゆきましょう。

var last_page = 24;
//最終ページを last_page と名付け、その値は 24 とします

var org = location.pathname;
//現在のページのパスは org と名付け、その値は location.pathname で取得します
//仮にURLが「http://hanaakari.jp/text/library/st/st_12.html」だとすると、
//「/text/library/st/st_12.html」がパス名となります。


var sp = org.split(".",2);
//現在のページのパスを sp と名付け .(ドット) で 2 分割します
//sp[0]「/text/library/st/st_12」とsp[1]「html」に分かれました

var num = sp[0].length;
//sp[0]の文字数を数え、その数値を num と名付けます
//「/text/library/st/st_12」の文字数は 22 です。num = 22 


var last_slash = sp[0].lastIndexOf("/",num);
//sp[0]の最後の /(スラッシュ) が 何文字目か取得し、その値を last_slash とします
//「/text/library/st/st_12」の「/st_12」の「/」は 16 文字目 です。 last_slash =16

var num0 = parseInt(sp[0].substring(num-1,num));
//sp[0]の後ろから一文字目を抜き出して、数値に変換し、これを num0 とします
//「/text/library/st/st_12」の最後の文字は「2」 num0 = 2

var num00 = parseInt(sp[0].substring(num-2,num-1));
//sp[0]の後ろから二文字目を抜き出して、数値に変換し、これを num00 とします
//「/text/library/st/st_12」の後ろから二つ目の文字は「1」 num00 = 1


var current_page = num0 + num00 * 10;
//現在のページを current_page と名付け、そのページ数は num0 + num00 * 10 とします
//この場合、現在のページ = current_page = 2+1×10 = 12 です

var prev_page = current_page - 1;
//前のページを prev_page と名付け、そのページ数は current_page−1 とします
//current_page は 12 ですから、12−1 で 11 です

var next_page = current_page + 1;
//次ぎのページを next_page と名付け、そのページ数は current_page+1 とします
//current_page は 12 ですから、12+1 で 13 です


var tail = "." + sp[1];
//「.(ドット)」と sp[1](二つに分けた二つ目のカタマリ)を接合し、
//これを tail と名付けます
//sp[1]は「html」ですから、「.html」 = 拡張子部分 ができました

var file = sp[0].substring(last_slash+1,num-2);
//last_slashから一つ目の文字〜最後から三つ目の文字までを抜き出し、
//これを file と名付けます
//「st_」が抜き出されました。これはファイル名の変動しない部分です

var index = sp[0].substring(last_slash+1,num-3)+ tail;
//last_slashから一つ目の文字〜最後から四つ目の文字までを抜き出し、index と名付けます
//「st」が抜き出されました。これが目次ページとなります。


var prev;
var next;
//省略しても構いません。
//今後、prev、nextという言葉を変数として使用します、という意味です

 簡単に言うと、この宣言部分では、「今のファイル名の末尾から数字を取り出して、前のページと次のページの数字を決定する」という作業をしています。
 ファイル名ではなく、例えばlocation.hrefでURLそのものを取得する方法も考えたのですが、同じディレクトリにあるリンクなら、絶対参照より相対参照のほうが綺麗だな、と(笑)
 が、ファイル名だけを取り出す方法が探せず、仕方なくパス名からファイル名を取り出すという手立てを講じることになりました。
 ファイル名のみを取り出すことができるなら、org と sp はいらないんですけどね……。
 それはさておき。
 では最後に、このスクリプトの肝の部分をご紹介いたします。

flag = isNaN(current_page)
if(flag){
	document.write("")
} else {
	if(prev_page == -1){
		prev = index;
	} else {
		if(prev_page < 10){
			prev = file + "0" + prev_page + tail;
		} else{
			prev = file + prev_page + tail;
		}
	}
	if(next_page > last_page){
		next = "none";
	} else{
		if(next_page < 10){
			next = file + "0" + next_page + tail;
		}else{
			next = file + next_page + tail;
		}
	}

 大きく二つに分かれています。
 五行目からの前半部は「prev_page(前のページ)」に、後半は「next_page(次のページ)」に関する記述です。
 前半部「prev_page」について読んでみましょう。
 もし、「prev_page」が「-1」である場合は「prev_page」には「index」を。
 そうではない場合、……ここで再び条件が分かれます。
 もし、「prev_page」が「10」より<(小さい)場合は、
「file(ファイル名の変動しない部分)」+ 0 +「prev_page」 + 「tail(拡張子部分)」のように表示、
 そうでなければ、
「file(ファイル名の変動しない部分)」 + 「prev_page」 + 「tail(拡張子部分)」のように表示しなさい、
 と、書かれています。
 では次に後半部です。
 もし、「next_page」が「last_page(最後のページ)」よりも大きい場合、「next_page」には「none」を。
 そうでない場合、さらに条件が分岐します。
 もし、「next_page」が「10」より小さい場合は、
「file(ファイル名の変動しない部分)」 + 0 + 「next_page」 + 「tail(拡張子部分)」のように表示、
 そうでなければ、
「file(ファイル名の変動しない部分)」 + 「next_page」 + 「tail(拡張子部分)」のように表示しなさい、
 です。
 一度整理します。

【条件分岐】  どちらも基本的には、「ファイル名の変動しない部分+ページ番号+拡張子」です。
・prev_page
 1.前のページがない場合、目次ページを「前のページ」とする
 2.前のページが1から9までのときは、ページ番号の前に0をつけ加える
 3.そのほかは基本どおり
・next_page
 1.次のページが最終ページよりも大きな数字になる場合、「none」とする
 2.次のページが1から9までのときは、ページ番号の前に0をつけ加える
 3.そのほかは基本どおり

 さらに、current_pageの数値が取得できなかった場合には、ナビゲーションを表示しないように、との命令が1行目から4行目までに記されています。
 たとえば、おまけの隠しページなどの場合、st_secret_1.htmlなどと名付ければ、ナビゲーションが表示されません。

 いかがでしたでしょうか。

【まとめ】  前回よりたくさんの記述をしていますが、作業内容は至って簡単です。
 思いっきり端折って言えば、
「今のページ番号を取得して、前のページと次のページ番号を割り振る。ただし、前のページが存在しないときは目次ページにリンクを設定し、次のページがないときはリンクを記述しない」
 です。
 次のページのありなしは、冒頭の 「var last_page」最終ページの設定で行なっています。
 ファイルの名前を上述のように「符号_番号(二桁).html」で連番にし、最終ページを設定すれば、動作するハズです。

 後は、JavaScriptをhtmlに仕込めば出来上がりです。スクリプト名が「navi.js」、仕込みたいhtmlファイルが同じディレクトリ(フォルダ)の中にある場合、こうです

<script type="text/javascript" src="navi.js"></script>

 これを、挿入したい箇所に記述して、完成です。
 お疲れさまでした。
 でも、これでもう、乱丁は発生しませんし、コピーしてペーストして修正する必要もありません。
 労力は十分に報われるのではないでしょうか……え? 手書きするほうが早い? そういうこともあるかもしれませんね。
 特に短編、数ページで完結する場合は、これを用いる利点は少ないかと思います。
 威力を発揮するのは完結予想30ページ超くらいからでしょうかねぇ。

 さて、ここでひとつ、このスクリプトの重要な欠点を。
 JavaScriptが有効でないブラウザや、設定で無効にしている場合、ナビゲーションがまったく表示されません。
 ご訪問くださる方の環境を調べてから設置をご検討くださいね。

 以上、小説サイトのJavaScript第2回「小説ページのリンクナビゲーション」でした。