2 * FeedBlog CoreScript
\r
4 * @copyright 2013 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)
\r
5 * @author Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)
\r
10 // ブログ本体のHTMLファイルのURL
\r
19 // ログのリストが書かれたXMLのファイルパス
\r
26 * XMLファイルから読み込んだファイルのバリデートモード
\r
27 * 0 = 改行コード部分に<br/>を挿入
\r
28 * 1 = 改行コード部分に<br/>を挿入しない
\r
35 // fetchEntries 用のセマフォ
\r
36 var fetchEntriesSemaphore = new Semaphore();
\r
38 // URL末尾用文字列(スクリプトを開いた瞬間のミリ秒を記録)
\r
42 * 記事を実際に生成します。この部分を編集することでデザインを変更可能です。
\r
43 * @param {Entry} entry 記事の情報が代入されたEntryオブジェクト
\r
44 * @param {String} drawitem 「本文」を描画すべきパネルのDIV要素のid
\r
45 * @param {String} renderto 「タイトル・更新日時・本文」の1日分の記事データを最終的に描画すべきパネルのDIV要素のid
\r
46 * @param {String} closed (Ext jsパネルオプション)記事をクローズ状態で生成するか否か
\r
48 function generatePanel(entry, drawitem, renderto, closed) {
\r
50 if ( typeof ($("#" + renderto).feedblog_contents_plugin) == "function") {
\r
51 $("#" + renderto).feedblog_contents_plugin({
\r
57 var htmlBuffer = [];
\r
60 var feedblogContentId = "" + renderto + "_content_div";
\r
63 $("#" + drawitem).html(entry.content);
\r
65 // ヘッダパネルを生成 class= .feedblog_header
\r
66 htmlBuffer.push("<div class='feedblog_header' onclick='closePanel(\"" + feedblogContentId + "\")'><span>" + entry.title + "</span></div>" +
\r
68 // 本体記事を作成 class= .feedblog_content
\r
69 "<div class='feedblog_content' id='" + feedblogContentId + "'><span>" + document.getElementById(renderto).innerHTML + "</span></div>");
\r
72 $("#" + renderto).html(htmlBuffer.join(""));
\r
76 * システム表示画面を実際に生成します。この部分を編集することでデザインを変更可能です。
\r
77 * @param {Entry} entry 記事の情報が代入されたEntryオブジェクト
\r
78 * @param {String} drawitem パネルの本文を格納したDIV要素のid
\r
79 * @param {String} renderto 「タイトル・更新日時・本文」の1日分の記事データを焼き付けるDIV要素のid
\r
80 * @param {String} closed (Ext jsパネルオプション)記事をクローズ状態で生成するか否か
\r
82 function generateSystemPanel(entry, drawitem, renderto, closed) {
\r
84 var htmlBuffer = [];
\r
87 var feedblogContentId = "" + renderto + "_content_div";
\r
90 $("#" + drawitem).html(entry.content);
\r
92 // ヘッダパネルを生成 class= .feedblog_header
\r
93 htmlBuffer.push("<div class='feedblog_header' onclick='closePanel(\"" + feedblogContentId + "\")'><span>" + entry.title + "</span></div>" +
\r
95 // 本体記事を作成 class= .feedblog_content
\r
96 "<div class='feedblog_content' id='" + feedblogContentId + "'><span>" + document.getElementById(renderto).innerHTML + "</span></div>");
\r
98 $("#" + renderto).html(htmlBuffer.join(""));
\r
104 function initialize() {
\r
105 // 初期値をhiddenパラメータより読み込みます
\r
106 mainPageUrl = $("#feedblog_mainpageurl").val();
\r
107 searchPageUrl = $("#feedblog_searchpageurl").val();
\r
108 latestXml = $("#feedblog_latestxml").val();
\r
109 logXmlUrl = $("#feedblog_loglistxmlurl").val();
\r
110 showLength = parseInt($("#feedblog_showlength").val());
\r
111 if (isNaN(showLength)) {
\r
114 validateMode = $("#feedblog_validatemode").val();
\r
117 urlSuffix = +new Date();
\r
122 if (mainPageUrl === undefined) {
\r
123 errorBuf.push("設定値「feedblog_mainpageurl」が欠落しています。");
\r
125 if (searchPageUrl === undefined) {
\r
126 errorBuf.push("設定値「feedblog_searchpageurl」が欠落しています。");
\r
128 if (latestXml === undefined) {
\r
129 errorBuf.push("設定値「feedblog_latestxml」が欠落しています。");
\r
131 if (logXmlUrl === undefined) {
\r
132 errorBuf.push("設定値「feedblog_loglistxmlurl」が欠落しています。");
\r
134 if (showLength === undefined) {
\r
135 errorBuf.push("設定値「feedblog_showlength」が欠落しています。");
\r
137 if (validateMode === undefined) {
\r
138 errorBuf.push("設定値「feedblog_validatemode」が欠落しています。");
\r
142 if ( typeof (CryptoJS.SHA1) != "function") {
\r
143 errorBuf.push("crypt-jsモジュール(hmac-sha1.js)が読み込まれていません。");
\r
146 errorBuf.push("crypt-jsモジュール(hmac-sha1.js)が読み込まれていません。");
\r
150 if ($("#feedblog_writearea").length == 0) {
\r
151 errorBuf.push("描画エリア「feedblog_writearea」が存在しません。");
\r
153 if ($("#feedblog_logselecter").length == 0) {
\r
154 errorBuf.push("描画エリア「feedblog_logselecter」が存在しません。");
\r
157 // エラーがある場合は以降の処理を継続しない
\r
158 if (errorBuf.length > 0) {
\r
159 alert("初期設定値に誤りがあります。\n詳細:\n" + errorBuf.join("\n"));
\r
167 * jQueryへのイベント登録です。すべてのDOMが利用可能になった時点で実行されます。
\r
169 $(document).ready(function() {
\r
171 if (!initialize()) {
\r
175 // 制御に必要な各種パラメタを取得する
\r
176 var tag = getParamFromUrl("tag");
\r
177 var id = getParamFromUrl("id");
\r
178 var urlhash = getHashFromUrl();
\r
180 // ハッシュが空か、ハッシュ形式の正規表現に一致しないようなら通常モードで実行
\r
181 if (urlhash.length == 0 && tag.length == 0 && id.length == 0) {
\r
182 fullWriteMode(latestXml);
\r
184 } else if (urlhash.length == 0 && id.length == 0) {
\r
185 // タグが指定されているのでタグ探索モード
\r
186 searchTagMode(tag);
\r
188 } else if (urlhash.length == 0) {
\r
189 // IDが指定されているのでID探索モード
\r
193 // ハッシュ形式の正規表現に一致したら探索モード
\r
194 searchHashMode(urlhash);
\r
200 * jQueryでのパネル開閉を制御します
\r
202 function closePanel(id) {
\r
203 $("#" + id).slideToggle();
\r
208 * @param {Object} obj entry 要素の DOM オブジェクト
\r
210 function Entry(obj) {
\r
211 this.title = $("title:first", obj).text();
\r
212 if (this.title == "")
\r
213 requiredElementError(obj, "title");
\r
214 this.title = validateText(this.title);
\r
215 this.content = $("content:first", obj).text();
\r
216 this.content = validateText(this.content);
\r
217 this.id = $("id:first", obj).text();
\r
219 requiredElementError(obj, "id");
\r
220 this.date = $("updated:first", obj).text();
\r
221 if (this.date == "")
\r
222 requiredElementError(obj, "updated");
\r
223 this.date = validateData(this.date);
\r
224 this.category = $("category", obj);
\r
229 * @param {Object} obj entry 要素の DOM オブジェクト
\r
231 function SystemEntry(obj) {
\r
232 this.title = $("title:first", obj).text();
\r
233 this.title = validateText(this.title);
\r
234 this.content = $("content:first", obj).text();
\r
235 this.content = validateText(this.content);
\r
236 this.id = $("id:first", obj).text();
\r
237 this.date = $("updated:first", obj).text();
\r
238 this.date = validateData(this.date);
\r
239 this.category = $("category", obj);
\r
243 * 呼び出すとDIV:id名:feedblog_writearea上のHTMLを削除し、ロードエフェクトを表示します
\r
245 function loadingEffect() {
\r
246 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
\r
249 var systemEntry = new SystemEntry();
\r
250 systemEntry.title = "Now Loading .....";
\r
251 systemEntry.content = '<br/>長時間画面が切り替わらない場合はページをリロードしてください。<br/><br/>';
\r
252 generateSystemPanel(systemEntry, "feedblog_drawitem", "feedblog_drawpanel", false);
\r
256 * 記事データのエラー時の処理を行います
\r
258 function showError() {
\r
259 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
\r
262 var systemEntry = new SystemEntry();
\r
263 systemEntry.title = "エラー";
\r
264 var errorContent = [];
\r
265 errorContent.push('<br/>記事ファイル(XML)の取得に失敗しました。以下のような原因が考えられます。<br/><br/>');
\r
266 errorContent.push('・設定値「feedblog_latestxml」に正しいパスが設定されていない。<br/>');
\r
267 errorContent.push('・設定値「feedblog_loglistxmlurl」に正しいパスが設定されていない。<br/>');
\r
268 errorContent.push('・ローカル環境で起動している(必ずサーバにアップロードして実行してください)。<br/>');
\r
269 errorContent.push('<br/>');
\r
270 systemEntry.content = errorContent.join("\n");
\r
271 generateSystemPanel(systemEntry, "feedblog_drawitem", "feedblog_drawpanel", false);
\r
274 $("#feedblog_resultwritearea").html("<div class='feedblog_result_status'></div>");
\r
278 * 記事データのエラー時の処理を行います
\r
280 function notFoundError() {
\r
281 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
\r
284 var systemEntry = new SystemEntry();
\r
285 systemEntry.title = "検索失敗";
\r
286 systemEntry.content = '<br/>検索条件に一致する記事は見つかりませんでした。<br/><br/>';
\r
287 generateSystemPanel(systemEntry, "feedblog_drawitem", "feedblog_drawpanel", false);
\r
291 * 記事データのエラー時の処理を行います
\r
293 function requiredElementError(parent, name) {
\r
294 alert(parent.ownerDocument.URL + ": 必須な要素 " + name + " が存在しないか空な " + parent.tagName + " 要素が存在します");
\r
297 function xmlAttrContentEscape(str) {
\r
298 return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/^[ ]+/mg, " ").replace(/^[\t]+/mg, "");
\r
302 * 日付のHTML表示用バリデーション処理を行います
\r
303 * @param {String} data RFC3339形式のdate-time文字列
\r
305 function validateData(data) {
\r
306 var regT = new RegExp("T", "gm");
\r
307 data = data.replace(regT, " ");
\r
309 // 秒数の小数点以下の部分はカットする
\r
310 data = data.substring(0, 19);
\r
316 * 記事本文のバリデーション処理を行います
\r
317 * @param {String} contents 記事の本文が格納されている文字列
\r
319 function validateText(contents) {
\r
321 if (validateMode == 0) {
\r
322 contents = contents.replace(/[\n\r]|\r\n/g, "<br />");
\r
329 * URLからパラメタを取得するための関数
\r
331 function getParamFromUrl(paramName) {
\r
332 // GETパラメタよりタグを取得する
\r
334 if (location.search.length > 1) {
\r
335 var queries = location.search.substring(1).split('&');
\r
336 for (var i = 0; i < queries.length; i++) {
\r
337 if (("" + queries[i].split('=')[0]) == paramName) {
\r
338 tag = "" + queries[i].split('=')[1];
\r
347 * URLからハッシュを取得するための関数
\r
349 function getHashFromUrl() {
\r
350 return "" + location.hash.substring(1);
\r
355 * @param {String} a 比較対象(1)
\r
356 * @param {String} b 比較対象(2)
\r
358 function compareLengthDecrease(a, b) {
\r
361 return a > b ? -1 : a < b ? 1 : 0;
\r
367 function Semaphore() {
\r
377 Semaphore.prototype.init = function() {
\r
378 while (this.xhrs.length > 0) {
\r
379 this.xhrs.shift().abort();
\r
381 this.id = Math.random();
\r
387 * ログファイル選択用のコンボボックスをid名:feedblog_logselecterに生成します
\r
388 * class - .feedblog_logform, .feedblog_logselecter
\r
390 function logXMLLoader() {
\r
393 url : logXmlUrl + '?time=' + urlSuffix,
\r
396 success : function(xmlData) {
\r
397 var separateTag = xmlData.getElementsByTagName("file");
\r
399 // 読み込んだ要素をStoreに格納して表示
\r
400 var boxBuffer = [];
\r
401 boxBuffer.push("<form class='feedblog_logselecter' name='feedblog_logform'><select class='feedblog_logselecter' id='feedblog_logbox' onchange='fullWriteMode(this.options[this.selectedIndex].value)'>");
\r
402 for (var i = 0; i < separateTag.length; i++) {
\r
403 boxBuffer.push("<option value='" + separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue + "'>" + separateTag[i].getElementsByTagName("display")[0].firstChild.nodeValue + "</option>");
\r
405 boxBuffer.push("</select></form>");
\r
408 $("#feedblog_logselecter").html(boxBuffer.join(""));
\r
414 * 記事のデータが記述されたXMLデータを読み込むロジックを生成します
\r
415 * @param {String} fileName 読み込み記事のデータが記述されているXMLファイルのパス
\r
417 function fullWriteMode(fileName) {
\r
421 var url = fileName;
\r
424 var loader = new jQuery.ajax({
\r
425 url : url + '?time=' + urlSuffix,
\r
427 success : function(xmlData) {
\r
428 var separateTag = xmlData.getElementsByTagName("entry");
\r
429 var stringBuffer = [];
\r
430 // メモリ上での保持変数を初期化します
\r
431 loadedEntries = [];
\r
433 // メモリ上の変数に全ての記事要素を格納します
\r
434 for (var i = 0; i < separateTag.length; i++) {
\r
435 loadedEntries.push(new Entry(separateTag[i]));
\r
439 showEntriesRange(showLength, 0);
\r
446 * 渡された文字列と一致するfeed1.0:updated要素を持った記事を検索し、表示します
\r
447 * @param {String} urlhash feed1.0:updated要素と一致する文字列
\r
449 function searchHashMode(urlhash) {
\r
454 var loader = new jQuery.ajax({
\r
455 url : logXmlUrl + '?time=' + urlSuffix,
\r
458 success : function(xmlData) {
\r
459 // ファイルパスの要素のみを抽出する
\r
460 var separateTag = xmlData.getElementsByTagName("file");
\r
461 var urls = new Array(separateTag.length);
\r
463 // すべてのファイルパスを配列に格納する
\r
464 for (var i = 0; i < separateTag.length; i++) {
\r
466 urls[i] = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
\r
470 fetchEntriesSemaphore.init();
\r
471 fetchEntriesSemaphore.urls = urls;
\r
472 fetchEntriesSemaphore.count = urls.length;
\r
474 // ファイルパス配列に格納されているすべての記事に対し、探索を開始する
\r
475 for (var i = 0; i < separateTag.length; i++) {
\r
476 // ファイルパス配列の要素からリクエストを生成し、対象データをロードする
\r
477 var xhr = new jQuery.ajax({
\r
480 success : fetchHashEntries
\r
482 fetchEntriesSemaphore.xhrs.push(xhr);
\r
489 * URLハッシュ検索用のjQueryコールバック関数
\r
491 function fetchHashEntries(xmlData) {
\r
492 // 既に検索結果が算出されていた場合は、何もしない
\r
493 if (fetchEntriesSemaphore.buf > 0) {
\r
498 var urlhash = getHashFromUrl();
\r
501 var entries = xmlData.getElementsByTagName("entry");
\r
503 for (var i = 0; i < entries.length; i++) {
\r
504 // entryタグ内部のidノードの値のみ抽出し、入力されたhashと比較を行う
\r
505 var entry = new Entry(entries[i]);
\r
508 if (urlhash == entry.id) {
\r
509 // 一致した場合は該当記事を表示する
\r
510 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
\r
511 generatePanel(entry, "feedblog_drawitem", "feedblog_drawpanel", false);
\r
513 fetchEntriesSemaphore.buf.push(entry);
\r
517 // セマフォのカウンタを減少させます (Ajaxとの同期のため)
\r
518 fetchEntriesSemaphore.count--;
\r
520 // 最後のファイルまで探索しても記事が見つからなかった場合はエラーを表示します。
\r
521 if (fetchEntriesSemaphore.count == 0) {
\r
522 var entries = fetchEntriesSemaphore.buf;
\r
524 if (entries.length == 0) {
\r
533 * 渡された文字列と一致するfeed1.0:id(sha-1)要素を持った記事を検索し、表示します
\r
534 * @param {String} urlhash feed1.0:id(sha-1)要素と一致する文字列
\r
536 function searchIdMode(urlhash) {
\r
541 var loader = new jQuery.ajax({
\r
542 url : logXmlUrl + '?time=' + urlSuffix,
\r
545 success : function(xmlData) {
\r
546 // ファイルパスの要素のみを抽出する
\r
547 var separateTag = xmlData.getElementsByTagName("file");
\r
548 var urls = new Array(separateTag.length);
\r
550 // すべてのファイルパスを配列に格納する
\r
551 for (var i = 0; i < separateTag.length; i++) {
\r
553 urls[i] = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
\r
557 fetchEntriesSemaphore.init();
\r
558 fetchEntriesSemaphore.urls = urls;
\r
559 fetchEntriesSemaphore.count = urls.length;
\r
561 // ファイルパス配列に格納されているすべての記事に対し、探索を開始する
\r
562 for (var i = 0; i < separateTag.length; i++) {
\r
563 // ファイルパス配列の要素からリクエストを生成し、対象データをロードする
\r
564 var xhr = new jQuery.ajax({
\r
567 success : fetchIdEntries
\r
569 fetchEntriesSemaphore.xhrs.push(xhr);
\r
576 * ID検索用のjQueryコールバック関数
\r
578 function fetchIdEntries(xmlData) {
\r
579 // 既に検索結果が算出されていた場合は、何もしない
\r
580 if (fetchEntriesSemaphore.buf > 0) {
\r
585 var id = getParamFromUrl("id");
\r
588 var entries = xmlData.getElementsByTagName("entry");
\r
590 for (var i = 0; i < entries.length; i++) {
\r
591 // entryタグ内部のidノードの値のみ抽出し、入力されたhashと比較を行う
\r
592 var entry = new Entry(entries[i]);
\r
595 if (id == CryptoJS.SHA1(entry.id).toString()) {
\r
596 // 一致した場合は該当記事を表示する
\r
597 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
\r
598 generatePanel(entry, "feedblog_drawitem", "feedblog_drawpanel", false);
\r
600 fetchEntriesSemaphore.buf.push(entry);
\r
604 // セマフォのカウンタを減少させます (Ajaxとの同期のため)
\r
605 fetchEntriesSemaphore.count--;
\r
607 // 最後のファイルまで探索しても記事が見つからなかった場合はエラーを表示します。
\r
608 if (fetchEntriesSemaphore.count == 0) {
\r
609 var entries = fetchEntriesSemaphore.buf;
\r
611 if (entries.length == 0) {
\r
620 * 渡された文字列と一致するfeed1.0:category:termタグ要素を持った記事を検索し、表示します
\r
621 * @param {String} urlhash feed1.0:category:term要素と一致する文字列
\r
623 function searchTagMode(tag) {
\r
628 var loader = new jQuery.ajax({
\r
629 url : logXmlUrl + '?time=' + urlSuffix,
\r
632 success : function(xmlData) {
\r
633 // ファイルパスの要素のみを抽出する
\r
634 var separateTag = xmlData.getElementsByTagName("file");
\r
635 var urls = new Array(separateTag.length);
\r
637 // すべてのファイルパスを配列に格納する
\r
638 for (var i = 0; i < separateTag.length; i++) {
\r
640 urls[i] = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
\r
644 fetchEntriesSemaphore.init();
\r
645 fetchEntriesSemaphore.urls = urls;
\r
646 fetchEntriesSemaphore.count = urls.length;
\r
648 // ファイルパス配列に格納されているすべての記事に対し、探索を開始する
\r
649 for (var i = 0; i < separateTag.length; i++) {
\r
650 // ファイルパス配列の要素からリクエストを生成し、対象データをロードする
\r
651 var xhr = new jQuery.ajax({
\r
654 success : fetchTagEntries
\r
656 fetchEntriesSemaphore.xhrs.push(xhr);
\r
663 * タグ検索用のjQueryコールバック関数
\r
665 function fetchTagEntries(xmlData) {
\r
666 // 既に記事の表示が行われている場合、何も実施しない
\r
667 if (fetchEntriesSemaphore.buf.length > 0) {
\r
672 var tag = getParamFromUrl("tag");
\r
675 var entries = xmlData.getElementsByTagName("entry");
\r
677 for (var j = 0; j < entries.length; j++) {
\r
678 var entry = new Entry(entries[j]);
\r
680 for (var k = 0; k < entry.category.length; k++) {
\r
682 if (tag == entry.category.eq(k).attr("term")) {
\r
684 fetchEntriesSemaphore.buf.push(entry);
\r
689 // セマフォのカウンタを減少させます (Ajaxとの同期のため)
\r
690 fetchEntriesSemaphore.count--;
\r
692 if (fetchEntriesSemaphore.count == 0) {
\r
693 var entries = fetchEntriesSemaphore.buf;
\r
695 if (entries.length == 0) {
\r
701 entries = entries.sort(function(a, b) {
\r
704 return a > b ? -1 : a < b ? 1 : 0;
\r
707 loadedEntries = entries;
\r
710 showEntriesRange(showLength, 0);
\r
716 * class - div.feedblog_pager, ul.feedblog_pager, li.feedblog_pager などなど
\r
717 * @param {int} showLength 一回の画面に表示する記事数
\r
718 * @param {int} startIndex 表示を開始する記事のインデックス
\r
720 function showEntriesRange(showLength, startIndex) {
\r
722 var entries = loadedEntries;
\r
724 // 表示インデックスが範囲外の場合はエラーパネルを表示して終了
\r
725 if (startIndex < 0 || (entries.length <= startIndex && entries.length != 0)) {
\r
730 var stringBuffer = [];
\r
733 var loopLimit = (showLength + startIndex > entries.length) ? entries.length : showLength + startIndex;
\r
734 var indexShowEntries = loopLimit + 1;
\r
737 var menuInfoBuffer = [];
\r
738 menuInfoBuffer.push("<div class='feedblog_pager_shownumber'>");
\r
739 var viewStartIndex = 0;
\r
740 entries.length == 0 ? viewStartIndex = 0 : viewStartIndex = startIndex + 1;
\r
741 menuInfoBuffer.push(viewStartIndex + "件~" + loopLimit + "件(全" + entries.length + "件)目の記事を表示中<br/>");
\r
742 menuInfoBuffer.push("</div>");
\r
744 // ページ移動メニュー表示用バッファです
\r
745 var menuMoveBuffer = [];
\r
746 menuMoveBuffer.push("<ul class='feedblog_pager'>");
\r
749 menuMoveBuffer.push("<li class='feedblog_pager_blank'></li>");
\r
752 if (startIndex - showLength >= 0) {
\r
753 menuMoveBuffer.push("\<li class='feedblog_pager_goback'><span class='feedblog_pager_goback' onclick='showEntriesRange(" + showLength + ", " + (startIndex - showLength) + "); return false;'>\< 前の" + showLength + "件を表示</span\></li>");
\r
755 menuMoveBuffer.push("\<li class='feedblog_pager_goback'>\< 前の" + showLength + "件を表示</a\></li>");
\r
759 menuMoveBuffer.push("<li class='feedblog_pager_center'>[ ");
\r
760 var menuNumbers = Math.ceil(entries.length / showLength);
\r
761 for ( i = 0; i < menuNumbers; i++) {
\r
762 if (startIndex / showLength == i) {
\r
763 menuMoveBuffer.push(i + " ");
\r
765 menuMoveBuffer.push("<span class='feedblog_pager_center' onclick='showEntriesRange(" + showLength + ", " + (i * showLength) + "); return false;'>");
\r
766 menuMoveBuffer.push(i);
\r
767 menuMoveBuffer.push("</span> ");
\r
770 menuMoveBuffer.push("]</li>");
\r
773 if (entries.length > startIndex + showLength) {
\r
774 menuMoveBuffer.push("\<li class='feedblog_pager_gonext'><span class='feedblog_pager_gonext' onclick='showEntriesRange(" + showLength + ", " + (startIndex + showLength) + "); return false;'>\次の" + showLength + "件を表示 \></span\></li>");
\r
776 menuMoveBuffer.push("\<li class='feedblog_pager_gonext'>次の" + showLength + "件を表示 \></li>");
\r
780 menuMoveBuffer.push("<li class='feedblog_pager_blank'></li>");
\r
782 menuMoveBuffer.push("</ul>");
\r
784 // メニューを結合してパネル(前方)に組み込みます
\r
785 stringBuffer.push("<div class='feedblog_pager_wrapper'>");
\r
786 stringBuffer.push(menuInfoBuffer.join(""));
\r
787 stringBuffer.push(menuMoveBuffer.join(""));
\r
788 stringBuffer.push("</div>");
\r
790 // 記事描画部分のパネルを生成します
\r
791 for (var i = startIndex; i < loopLimit; i++) {
\r
792 stringBuffer.push('<div class="feedblog_drawpanel" id="feedblog_drawpanel');
\r
793 stringBuffer.push(i);
\r
794 stringBuffer.push('"><div class="feedblog_drawitem" id="feedblog_drawitem');
\r
795 stringBuffer.push(i);
\r
796 stringBuffer.push('"><\/div><\/div>');
\r
799 // メニューを結合してパネル(後方)に組み込みます
\r
800 stringBuffer.push("<div class='feedblog_pager_wrapper'>");
\r
801 stringBuffer.push(menuMoveBuffer.join(""));
\r
802 stringBuffer.push(menuInfoBuffer.join(""));
\r
803 stringBuffer.push("</div>");
\r
805 $("#feedblog_writearea").html(stringBuffer.join(""));
\r
807 for (var i = startIndex; i < loopLimit; i++) {
\r
808 // 各要素をオブジェクトに格納します
\r
809 var entry = entries[i];
\r
811 // すべてのパネルをオープン状態で生成します
\r
812 generatePanel(entry, "feedblog_drawitem" + i, "feedblog_drawpanel" + i, false);
\r