4 * @copyright 2013 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)
5 * @author Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)
19 // ログのリストが書かれたXMLのファイルパス
26 * XMLファイルから読み込んだファイルのバリデートモード
27 * 0 = 改行コード部分に<br/>を挿入
28 * 1 = 改行コード部分に<br/>を挿入しない
35 // fetchEntries 用のセマフォ
36 var fetchEntriesSemaphore = new Semaphore();
38 // URL末尾用文字列(スクリプトを開いた瞬間のミリ秒を記録)
42 * 記事を実際に生成します。この部分を編集することでデザインを変更可能です。
43 * @param {Entry} entry 記事の情報が代入されたEntryオブジェクト
44 * @param {String} drawitem 「本文」を描画すべきパネルのDIV要素のid
45 * @param {String} renderto 「タイトル・更新日時・本文」の1日分の記事データを最終的に描画すべきパネルのDIV要素のid
46 * @param {String} closed (Ext jsパネルオプション)記事をクローズ状態で生成するか否か
48 function generatePanel(entry, drawitem, renderto, closed) {
50 if ( typeof ($("#" + renderto).feedblog_contents_plugin) == "function") {
51 $("#" + renderto).feedblog_contents_plugin({
60 var feedblogContentId = "" + renderto + "_content_div";
63 $("#" + drawitem).html(entry.content);
65 // ヘッダパネルを生成 class= .feedblog_header
66 htmlBuffer.push("<div class='feedblog_header' onclick='closePanel(\"" + feedblogContentId + "\")'><span>" + entry.title + "</span></div>" +
68 // 本体記事を作成 class= .feedblog_content
69 "<div class='feedblog_content' id='" + feedblogContentId + "'><span>" + document.getElementById(renderto).innerHTML + "</span></div>");
72 $("#" + renderto).html(htmlBuffer.join(""));
76 * システム表示画面を実際に生成します。この部分を編集することでデザインを変更可能です。
77 * @param {Entry} entry 記事の情報が代入されたEntryオブジェクト
78 * @param {String} drawitem パネルの本文を格納したDIV要素のid
79 * @param {String} renderto 「タイトル・更新日時・本文」の1日分の記事データを焼き付けるDIV要素のid
80 * @param {String} closed (Ext jsパネルオプション)記事をクローズ状態で生成するか否か
82 function generateSystemPanel(entry, drawitem, renderto, closed) {
87 var feedblogContentId = "" + renderto + "_content_div";
90 $("#" + drawitem).html(entry.content);
92 // ヘッダパネルを生成 class= .feedblog_header
93 htmlBuffer.push("<div class='feedblog_header' onclick='closePanel(\"" + feedblogContentId + "\")'><span>" + entry.title + "</span></div>" +
95 // 本体記事を作成 class= .feedblog_content
96 "<div class='feedblog_content' id='" + feedblogContentId + "'><span>" + document.getElementById(renderto).innerHTML + "</span></div>");
98 $("#" + renderto).html(htmlBuffer.join(""));
104 function initialize() {
105 // 初期値をhiddenパラメータより読み込みます
106 mainPageUrl = $("#feedblog_mainpageurl").val();
107 searchPageUrl = $("#feedblog_searchpageurl").val();
108 latestXml = $("#feedblog_latestxml").val();
109 logXmlUrl = $("#feedblog_loglistxmlurl").val();
110 showLength = parseInt($("#feedblog_showlength").val());
111 if (isNaN(showLength)) {
114 validateMode = $("#feedblog_validatemode").val();
117 urlSuffix = +new Date();
122 if (mainPageUrl === undefined) {
123 errorBuf.push("設定値「feedblog_mainpageurl」が欠落しています。");
125 if (searchPageUrl === undefined) {
126 errorBuf.push("設定値「feedblog_searchpageurl」が欠落しています。");
128 if (latestXml === undefined) {
129 errorBuf.push("設定値「feedblog_latestxml」が欠落しています。");
131 if (logXmlUrl === undefined) {
132 errorBuf.push("設定値「feedblog_loglistxmlurl」が欠落しています。");
134 if (showLength === undefined) {
135 errorBuf.push("設定値「feedblog_showlength」が欠落しています。");
137 if (validateMode === undefined) {
138 errorBuf.push("設定値「feedblog_validatemode」が欠落しています。");
142 if ( typeof (CryptoJS.SHA1) != "function") {
143 errorBuf.push("crypt-jsモジュール(hmac-sha1.js)が読み込まれていません。");
146 errorBuf.push("crypt-jsモジュール(hmac-sha1.js)が読み込まれていません。");
150 if ($("#feedblog_writearea").length == 0) {
151 errorBuf.push("描画エリア「feedblog_writearea」が存在しません。");
153 if ($("#feedblog_logselecter").length == 0) {
154 errorBuf.push("描画エリア「feedblog_logselecter」が存在しません。");
157 // エラーがある場合は以降の処理を継続しない
158 if (errorBuf.length > 0) {
159 alert("初期設定値に誤りがあります。\n詳細:\n" + errorBuf.join("\n"));
167 * jQueryへのイベント登録です。すべてのDOMが利用可能になった時点で実行されます。
169 $(document).ready(function() {
176 var tag = getParamFromUrl("tag");
177 var id = getParamFromUrl("id");
178 var urlhash = getHashFromUrl();
180 // ハッシュが空か、ハッシュ形式の正規表現に一致しないようなら通常モードで実行
181 if (urlhash.length == 0 && tag.length == 0 && id.length == 0) {
182 fullWriteMode(latestXml);
184 } else if (urlhash.length == 0 && id.length == 0) {
185 // タグが指定されているのでタグ探索モード
186 searchTagMode(tag, true);
188 } else if (urlhash.length == 0) {
189 // IDが指定されているのでID探索モード
193 // ハッシュ形式の正規表現に一致したら探索モード
194 searchHashMode(urlhash);
200 * jQueryでのパネル開閉を制御します
202 function closePanel(id) {
203 $("#" + id).slideToggle();
208 * @param {Object} obj entry 要素の DOM オブジェクト
210 function Entry(obj) {
211 this.title = $("title:first", obj).text();
212 if (this.title == "")
213 requiredElementError(obj, "title");
214 this.title = validateText(this.title);
215 this.content = $("content:first", obj).text();
216 this.content = validateText(this.content);
217 this.id = $("id:first", obj).text();
219 requiredElementError(obj, "id");
220 this.date = $("updated:first", obj).text();
222 requiredElementError(obj, "updated");
223 this.date = validateData(this.date);
224 this.category = $("category", obj);
229 * @param {Object} obj entry 要素の DOM オブジェクト
231 function SystemEntry(obj) {
232 this.title = $("title:first", obj).text();
233 this.title = validateText(this.title);
234 this.content = $("content:first", obj).text();
235 this.content = validateText(this.content);
236 this.id = $("id:first", obj).text();
237 this.date = $("updated:first", obj).text();
238 this.date = validateData(this.date);
239 this.category = $("category", obj);
243 * 呼び出すとDIV:id名:feedblog_writearea上のHTMLを削除し、ロードエフェクトを表示します
245 function loadingEffect() {
246 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
249 var systemEntry = new SystemEntry();
250 systemEntry.title = "Now Loading .....";
251 systemEntry.content = '<br/>長時間画面が切り替わらない場合はページをリロードしてください。<br/><br/>';
252 generateSystemPanel(systemEntry, "feedblog_drawitem", "feedblog_drawpanel", false);
256 * 呼び出すとDIV:id名:feedblog_writearea上の先頭に、処理中の記事を表示します
258 function executingEffect() {
259 $("#feedblog_writearea").html('<div id="feedblog_drawpanel_info" class="feedblog_drawpanel"><div id="feedblog_drawitem_info" class="feedblog_drawitem"> <\/div><\/div>');
262 var systemEntry = new SystemEntry();
263 systemEntry.title = "検索処理中";
264 systemEntry.content = '<br/>該当するタグに属する記事を検索中です。<br/><br/>';
265 generateSystemPanel(systemEntry, "feedblog_drawitem_info", "feedblog_drawpanel_info", false);
269 * 呼び出すとDIV:id名:feedblog_drawpanel_info上に、処理完了の記事を表示します
271 function executingEffectCompleteEffect() {
272 $("#feedblog_drawpanel_info").html('<div id="feedblog_drawitem_info" class="feedblog_drawitem"> <\/div><\/div>');
275 var systemEntry = new SystemEntry();
276 systemEntry.title = "検索完了";
277 systemEntry.content = '<br/>検索処理が完了しました。(該当記事:' + fetchEntriesSemaphore.entryCount + '件)<br/><br/>';
278 generateSystemPanel(systemEntry, "feedblog_drawitem_info", "feedblog_drawpanel_info", false);
282 * 呼び出すとDIV:id名:feedblog_drawpanel_abort上に、省略記事がある旨を描画します
284 function showLimitedInfoEffect() {
285 $("#feedblog_writearea").html($("#feedblog_writearea").html() + '<div id="feedblog_drawpanel_abort" class="feedblog_drawpanel"><div id="feedblog_drawitem_abort" class="feedblog_drawitem"> <\/div><\/div>');
288 var systemEntry = new SystemEntry();
289 systemEntry.title = "以降、" + (fetchEntriesSemaphore.entryCount - fetchEntriesSemaphore.entryIndex) + "件の記事が省略されています。";
290 systemEntry.content = '<br/><a style="cursor: pointer;" onclick="javascript: fetchTagHiddenEntries();">全ての記事を表示する。</a><br/><br/>';
291 generateSystemPanel(systemEntry, "feedblog_drawitem_abort", "feedblog_drawpanel_abort", false);
295 * 呼び出すとDIV:id名:feedblog_drawpanel_abortを消去します
297 function showLimitedInfoRemoveEffect() {
298 $("#feedblog_drawpanel_abort").remove();
304 function showErrorEffect() {
305 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
308 var systemEntry = new SystemEntry();
309 systemEntry.title = "エラー";
310 var errorContent = [];
311 errorContent.push('<br/>記事ファイル(XML)の取得に失敗しました。以下のような原因が考えられます。<br/><br/>');
312 errorContent.push('・設定値「feedblog_latestxml」に正しいパスが設定されていない。<br/>');
313 errorContent.push('・設定値「feedblog_loglistxmlurl」に正しいパスが設定されていない。<br/>');
314 errorContent.push('・ローカル環境で起動している(必ずサーバにアップロードして実行してください)。<br/>');
315 errorContent.push('<br/>');
316 systemEntry.content = errorContent.join("\n");
317 generateSystemPanel(systemEntry, "feedblog_drawitem", "feedblog_drawpanel", false);
320 $("#feedblog_resultwritearea").html("<div class='feedblog_result_status'></div>");
326 function notFoundErrorEffect() {
327 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
330 var systemEntry = new SystemEntry();
331 systemEntry.title = "検索失敗";
332 systemEntry.content = '<br/>検索条件に一致する記事は見つかりませんでした。<br/><br/>';
333 generateSystemPanel(systemEntry, "feedblog_drawitem", "feedblog_drawpanel", false);
339 function requiredElementError(parent, name) {
340 alert(parent.ownerDocument.URL + ": 必須な要素 " + name + " が存在しないか空な " + parent.tagName + " 要素が存在します");
343 function xmlAttrContentEscape(str) {
344 return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/^[ ]+/mg, " ").replace(/^[\t]+/mg, "");
348 * 日付のHTML表示用バリデーション処理を行います
349 * @param {String} data RFC3339形式のdate-time文字列
351 function validateData(data) {
352 var regT = new RegExp("T", "gm");
353 data = data.replace(regT, " ");
356 data = data.substring(0, 19);
362 * 記事本文のバリデーション処理を行います
363 * @param {String} contents 記事の本文が格納されている文字列
365 function validateText(contents) {
367 if (validateMode == 0) {
368 contents = contents.replace(/[\n\r]|\r\n/g, "<br />");
375 * URLからパラメタを取得するための関数
377 function getParamFromUrl(paramName) {
380 if (location.search.length > 1) {
381 var queries = location.search.substring(1).split('&');
382 for (var i = 0; i < queries.length; i++) {
383 if (("" + queries[i].split('=')[0]) == paramName) {
384 tag = "" + queries[i].split('=')[1];
393 * URLからハッシュを取得するための関数
395 function getHashFromUrl() {
396 return "" + location.hash.substring(1);
401 * @param {String} a 比較対象(1)
402 * @param {String} b 比較対象(2)
404 function compareLengthDecrease(a, b) {
407 return a > b ? -1 : a < b ? 1 : 0;
413 function Semaphore() {
423 Semaphore.prototype.init = function() {
424 while (this.xhrs.length > 0) {
425 this.xhrs.shift().abort();
427 this.id = Math.random();
433 * ログファイル選択用のコンボボックスをid名:feedblog_logselecterに生成します
434 * class - .feedblog_logform, .feedblog_logselecter
436 function logXMLLoader() {
439 url : logXmlUrl + '?time=' + urlSuffix,
441 error : showErrorEffect,
442 success : function(xmlData) {
443 var separateTag = xmlData.getElementsByTagName("file");
445 // 読み込んだ要素をStoreに格納して表示
447 boxBuffer.push("<form class='feedblog_logselecter' name='feedblog_logform'><select class='feedblog_logselecter' id='feedblog_logbox' onchange='fullWriteMode(this.options[this.selectedIndex].value)'>");
448 for (var i = 0; i < separateTag.length; i++) {
449 boxBuffer.push("<option value='" + separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue + "'>" + separateTag[i].getElementsByTagName("display")[0].firstChild.nodeValue + "</option>");
451 boxBuffer.push("</select></form>");
454 $("#feedblog_logselecter").html(boxBuffer.join(""));
460 * 記事のデータが記述されたXMLデータを読み込むロジックを生成します
461 * @param {String} fileName 読み込み記事のデータが記述されているXMLファイルのパス
463 function fullWriteMode(fileName) {
470 var loader = new jQuery.ajax({
471 url : url + '?time=' + urlSuffix,
473 success : function(xmlData) {
474 var separateTag = xmlData.getElementsByTagName("entry");
475 var stringBuffer = [];
479 // メモリ上の変数に全ての記事要素を格納します
480 for (var i = 0; i < separateTag.length; i++) {
481 loadedEntries.push(new Entry(separateTag[i]));
485 showEntriesRange(showLength, 0);
487 error : showErrorEffect
492 * 渡された文字列と一致するfeed1.0:updated要素を持った記事を検索し、表示します
493 * @param {String} urlhash feed1.0:updated要素と一致する文字列
495 function searchHashMode(urlhash) {
500 var loader = new jQuery.ajax({
501 url : logXmlUrl + '?time=' + urlSuffix,
503 error : showErrorEffect,
504 success : function(xmlData) {
506 var separateTag = xmlData.getElementsByTagName("file");
507 var urls = new Array(separateTag.length);
509 // すべてのファイルパスを配列に格納する
510 for (var i = 0; i < separateTag.length; i++) {
512 urls[i] = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
516 fetchEntriesSemaphore.init();
517 fetchEntriesSemaphore.urls = urls;
518 fetchEntriesSemaphore.count = urls.length;
520 // ファイルパス配列に格納されているすべての記事に対し、探索を開始する
521 for (var i = 0; i < separateTag.length; i++) {
522 // ファイルパス配列の要素からリクエストを生成し、対象データをロードする
523 var xhr = new jQuery.ajax({
526 success : fetchHashEntries
528 fetchEntriesSemaphore.xhrs.push(xhr);
535 * URLハッシュ検索用のjQueryコールバック関数
537 function fetchHashEntries(xmlData) {
538 // 既に検索結果が算出されていた場合は、何もしない
539 if (fetchEntriesSemaphore.buf > 0) {
544 var urlhash = getHashFromUrl();
547 var entries = xmlData.getElementsByTagName("entry");
549 for (var i = 0; i < entries.length; i++) {
550 // entryタグ内部のidノードの値のみ抽出し、入力されたhashと比較を行う
551 var entry = new Entry(entries[i]);
554 if (urlhash == entry.id) {
556 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
557 generatePanel(entry, "feedblog_drawitem", "feedblog_drawpanel", false);
559 fetchEntriesSemaphore.buf.push(entry);
564 // セマフォのカウンタを減少させます (Ajaxとの同期のため)
565 fetchEntriesSemaphore.count--;
567 // 最後のファイルまで探索しても記事が見つからなかった場合はエラーを表示します。
568 if (fetchEntriesSemaphore.count == 0) {
569 var entries = fetchEntriesSemaphore.buf;
571 if (entries.length == 0) {
572 notFoundErrorEffect();
579 * 渡された文字列と一致するfeed1.0:id(sha-1)要素を持った記事を検索し、表示します
580 * @param {String} urlhash feed1.0:id(sha-1)要素と一致する文字列
582 function searchIdMode(urlhash) {
587 var loader = new jQuery.ajax({
588 url : logXmlUrl + '?time=' + urlSuffix,
590 error : showErrorEffect,
591 success : function(xmlData) {
593 var separateTag = xmlData.getElementsByTagName("file");
594 var urls = new Array(separateTag.length);
596 // すべてのファイルパスを配列に格納する
597 for (var i = 0; i < separateTag.length; i++) {
599 urls[i] = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
603 fetchEntriesSemaphore.init();
604 fetchEntriesSemaphore.urls = urls;
605 fetchEntriesSemaphore.count = urls.length;
607 // ファイルパス配列に格納されているすべての記事に対し、探索を開始する
608 for (var i = 0; i < separateTag.length; i++) {
609 // ファイルパス配列の要素からリクエストを生成し、対象データをロードする
610 var xhr = new jQuery.ajax({
613 success : fetchIdEntries
615 fetchEntriesSemaphore.xhrs.push(xhr);
622 * ID検索用のjQueryコールバック関数
624 function fetchIdEntries(xmlData) {
625 // 既に検索結果が算出されていた場合は、何もしない
626 if (fetchEntriesSemaphore.buf > 0) {
631 var id = getParamFromUrl("id");
634 var entries = xmlData.getElementsByTagName("entry");
636 for (var i = 0; i < entries.length; i++) {
637 // entryタグ内部のidノードの値のみ抽出し、入力されたhashと比較を行う
638 var entry = new Entry(entries[i]);
641 if (id == CryptoJS.SHA1(entry.id).toString()) {
643 $("#feedblog_writearea").html('<div id="feedblog_drawpanel" class="feedblog_drawpanel"><div id="feedblog_drawitem" class="feedblog_drawitem"> <\/div><\/div>');
644 generatePanel(entry, "feedblog_drawitem", "feedblog_drawpanel", false);
646 fetchEntriesSemaphore.buf.push(entry);
652 // セマフォのカウンタを減少させます (Ajaxとの同期のため)
653 fetchEntriesSemaphore.count--;
655 // 最後のファイルまで探索しても記事が見つからなかった場合はエラーを表示します。
656 if (fetchEntriesSemaphore.count == 0) {
657 var entries = fetchEntriesSemaphore.buf;
659 if (entries.length == 0) {
660 notFoundErrorEffect();
668 * 渡された文字列と一致するfeed1.0:category:termタグ要素を持った記事を検索し、表示します
669 * @param {String} tag feed1.0:category:term要素と一致する文字列
670 * @param {boolean} showLimit 省略表示をする場合はtrue,全件表示する場合はfalse
672 function searchTagMode(tag, showLimit) {
677 var loader = new jQuery.ajax({
678 url : logXmlUrl + '?time=' + urlSuffix,
680 error : showErrorEffect,
681 success : function(xmlData) {
683 var separateTag = xmlData.getElementsByTagName("file");
684 var urls = new Array(separateTag.length);
686 // すべてのファイルパスを配列に格納する
687 for (var i = 0; i < separateTag.length; i++) {
689 urls[i] = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
693 fetchEntriesSemaphore.init();
694 fetchEntriesSemaphore.urls = urls;
695 fetchEntriesSemaphore.count = urls.length;
696 fetchEntriesSemaphore.entryIndex = 0;
697 fetchEntriesSemaphore.entryCount = 0;
698 fetchEntriesSemaphore.showLimit = showLimit;
699 fetchEntriesSemaphore.hiddenEntries = [];
701 // ファイルパス配列に格納されているすべての記事に対し、探索を開始する
702 for (var i = 0; i < separateTag.length; i++) {
703 // ファイルパス配列の要素からリクエストを生成し、対象データをロードする
704 var xhr = new jQuery.ajax({
707 success : fetchTagEntries
709 fetchEntriesSemaphore.xhrs.push(xhr);
716 * タグ検索用のjQueryコールバック関数
718 function fetchTagEntries(xmlData) {
719 // 既に記事の表示が行われている場合、何も実施しない
720 if (fetchEntriesSemaphore.buf.length > 0) {
725 var tag = getParamFromUrl("tag");
728 var entries = xmlData.getElementsByTagName("entry");
730 for (var j = 0; j < entries.length; j++) {
731 var entry = new Entry(entries[j]);
733 for (var k = 0; k < entry.category.length; k++) {
735 if (tag == entry.category.eq(k).attr("term")) {
736 // 表示数限界を超えていた場合、表示処理を実施しない
737 if (fetchEntriesSemaphore.showLimit == true && fetchEntriesSemaphore.entryIndex >= showLength) {
739 fetchEntriesSemaphore.entryCount++;
741 fetchEntriesSemaphore.hiddenEntries.push(entry);
744 fetchEntriesSemaphore.entryCount++;
746 fetchEntriesSemaphore.entryIndex = showEntriesAdd(entry, fetchEntriesSemaphore.entryIndex);
752 // セマフォのカウンタを減少させます (Ajaxとの同期のため)
753 fetchEntriesSemaphore.count--;
755 if (fetchEntriesSemaphore.count == 0) {
756 if (fetchEntriesSemaphore.entryIndex == 0) {
757 notFoundErrorEffect();
760 executingEffectCompleteEffect();
761 // 省略記事がある場合は、省略パネルを表示する
762 if (fetchEntriesSemaphore.entryIndex != fetchEntriesSemaphore.entryCount) {
763 showLimitedInfoEffect();
771 * 省略表示されている記事一覧を描画します
773 function fetchTagHiddenEntries() {
775 showLimitedInfoRemoveEffect();
778 for (var i = 0; i < fetchEntriesSemaphore.hiddenEntries.length; i++) {
779 fetchEntriesSemaphore.entryIndex = showEntriesAdd(fetchEntriesSemaphore.hiddenEntries[i], fetchEntriesSemaphore.entryIndex);
785 * class - div.feedblog_pager, ul.feedblog_pager, li.feedblog_pager などなど
786 * @param {int} showLength 一回の画面に表示する記事数
787 * @param {int} startIndex 表示を開始する記事のインデックス
789 function showEntriesRange(showLength, startIndex) {
791 var entries = loadedEntries;
793 // 表示インデックスが範囲外の場合はエラーパネルを表示して終了
794 if (startIndex < 0 || (entries.length <= startIndex && entries.length != 0)) {
799 var stringBuffer = [];
802 var loopLimit = (showLength + startIndex > entries.length) ? entries.length : showLength + startIndex;
803 var indexShowEntries = loopLimit + 1;
806 var menuInfoBuffer = [];
807 menuInfoBuffer.push("<div class='feedblog_pager_shownumber'>");
808 var viewStartIndex = 0;
809 entries.length == 0 ? viewStartIndex = 0 : viewStartIndex = startIndex + 1;
810 menuInfoBuffer.push(viewStartIndex + "件~" + loopLimit + "件(全" + entries.length + "件)目の記事を表示中<br/>");
811 menuInfoBuffer.push("</div>");
813 // ページ移動メニュー表示用バッファです
814 var menuMoveBuffer = [];
815 menuMoveBuffer.push("<ul class='feedblog_pager'>");
818 menuMoveBuffer.push("<li class='feedblog_pager_blank'></li>");
821 if (startIndex - showLength >= 0) {
822 menuMoveBuffer.push("\<li class='feedblog_pager_goback'><span class='feedblog_pager_goback' onclick='showEntriesRange(" + showLength + ", " + (startIndex - showLength) + "); return false;'>\< 前の" + showLength + "件を表示</span\></li>");
824 menuMoveBuffer.push("\<li class='feedblog_pager_goback'>\< 前の" + showLength + "件を表示</a\></li>");
828 menuMoveBuffer.push("<li class='feedblog_pager_center'>[ ");
829 var menuNumbers = Math.ceil(entries.length / showLength);
830 for ( i = 0; i < menuNumbers; i++) {
831 if (startIndex / showLength == i) {
832 menuMoveBuffer.push(i + " ");
834 menuMoveBuffer.push("<span class='feedblog_pager_center' onclick='showEntriesRange(" + showLength + ", " + (i * showLength) + "); return false;'>");
835 menuMoveBuffer.push(i);
836 menuMoveBuffer.push("</span> ");
839 menuMoveBuffer.push("]</li>");
842 if (entries.length > startIndex + showLength) {
843 menuMoveBuffer.push("\<li class='feedblog_pager_gonext'><span class='feedblog_pager_gonext' onclick='showEntriesRange(" + showLength + ", " + (startIndex + showLength) + "); return false;'>\次の" + showLength + "件を表示 \></span\></li>");
845 menuMoveBuffer.push("\<li class='feedblog_pager_gonext'>次の" + showLength + "件を表示 \></li>");
849 menuMoveBuffer.push("<li class='feedblog_pager_blank'></li>");
851 menuMoveBuffer.push("</ul>");
853 // メニューを結合してパネル(前方)に組み込みます
854 stringBuffer.push("<div class='feedblog_pager_wrapper'>");
855 stringBuffer.push(menuInfoBuffer.join(""));
856 stringBuffer.push(menuMoveBuffer.join(""));
857 stringBuffer.push("</div>");
860 for (var i = startIndex; i < loopLimit; i++) {
861 stringBuffer.push('<div class="feedblog_drawpanel" id="feedblog_drawpanel');
862 stringBuffer.push(i);
863 stringBuffer.push('"><div class="feedblog_drawitem" id="feedblog_drawitem');
864 stringBuffer.push(i);
865 stringBuffer.push('"><\/div><\/div>');
868 // メニューを結合してパネル(後方)に組み込みます
869 stringBuffer.push("<div class='feedblog_pager_wrapper'>");
870 stringBuffer.push(menuMoveBuffer.join(""));
871 stringBuffer.push(menuInfoBuffer.join(""));
872 stringBuffer.push("</div>");
874 $("#feedblog_writearea").html(stringBuffer.join(""));
876 for (var i = startIndex; i < loopLimit; i++) {
878 var entry = entries[i];
880 // すべてのパネルをオープン状態で生成します
881 generatePanel(entry, "feedblog_drawitem" + i, "feedblog_drawpanel" + i, false);
887 * class - div.feedblog_pager, ul.feedblog_pager, li.feedblog_pager などなど
888 * @param {Entry} 末尾に追加するEntryオブジェクト
889 * @param {int} 現在のEntry数
890 * @return {int} 新規記事を追加し終えた後のEntry数
892 function showEntriesAdd(entry, entryIndex) {
894 var stringBuffer = [];
897 var newIndex = entryIndex + 1;
898 stringBuffer.push('<div class="feedblog_drawpanel" id="feedblog_drawpanel');
899 stringBuffer.push(newIndex);
900 stringBuffer.push('"><div class="feedblog_drawitem" id="feedblog_drawitem');
901 stringBuffer.push(newIndex);
902 stringBuffer.push('"><\/div><\/div>');
905 $("#feedblog_writearea").html($("#feedblog_writearea").html() + stringBuffer.join(""));
906 generatePanel(entry, "feedblog_drawitem" + newIndex, "feedblog_drawpanel" + newIndex, false);