OSDN Git Service

add "Feed convert to mixi-style" script.
[feedblog/feedblog_ext.git] / js / lunardial / feedblog_mixi.js
diff --git a/js/lunardial/feedblog_mixi.js b/js/lunardial/feedblog_mixi.js
new file mode 100644 (file)
index 0000000..9447990
--- /dev/null
@@ -0,0 +1,486 @@
+/**
+ * FeedBlog CoreScript Ext Version
+ *
+ * @copyright 2009 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)
+ * @author Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)
+ * @since 2008/10/16
+ * @version 2.1.0.0
+ */
+// ブログ本体のHTMLファイルの名前を記入してください
+var blogUrl = "./index.html"
+
+// 最新の日記を示すパスへの文字列です。最新の日記を置く場所を変えたいときは変更してください。
+var latestXml = "./xml/diary.xml";
+
+// ログのリストが書かれたXMLのファイルパスを記入してください
+var logXmlUrl = "./xml/loglist.xml";
+
+// Ext jsパネルのサイズを記述してください
+var extPanelWidth = 580;
+
+// ログを表示するコンボボックスのサイズを記述してください
+var extComboWidth = 150;
+
+// 日記間のスパン(間隔)をPIXEL単位で記述してください
+var entrySpan = 3;
+
+// 一画面あたりの表示日記数です
+var showLength = 3;
+
+// 検索結果をメモリ上に保持する変数です
+var loadedEntries;
+
+/**
+ * XMLファイルから読み込んだファイルのバリデートモードを選択します。
+ * 0 = 改行コード部分に<br/>を挿入
+ * 1 = 改行コード部分に<br/>を挿入しない
+ */
+var validateMode = "0";
+
+/**
+ * Ext jsパネルを実際に生成します。この部分を編集することでデザインを変更可能です。
+ * @param {String} title パネルのタイトル部分に表示する文字列
+ * @param {String} drawitem パネルの本文を格納したDIV要素のid
+ * @param {String} renderto 「タイトル・更新日時・本文」の1日分の日記データを焼き付けるDIV要素のid
+ * @param {String} closed (Ext jsパネルオプション)日記をクローズ状態で生成するか否か
+ */
+function generatePanel(title, drawitem, renderto, closed){
+    // Ext jsパネルを生成する
+    new Ext.Panel({
+        contentEl: drawitem,
+        width: extPanelWidth,
+        title: title,
+        hideCollapseTool: false,
+        titleCollapse: true,
+        collapsible: true,
+        collapsed: closed,
+        renderTo: renderto
+    });
+}
+
+/**
+ * Extへのイベント登録です。すべてのDOMが利用可能になった時点で実行されます。
+ */
+$(document).ready(function(){
+    // 特定の過去ログの探索モードか否かを判別するためにハッシュを取得する
+    var urlhash = "" + location.hash.substring(1);
+    
+    // ハッシュが空か、ハッシュ形式の正規表現に一致しないようなら通常モードで実行
+    if (urlhash.length == 0) {
+        xmlLoader(latestXml);
+        logXMLLoader();
+    }
+    // ハッシュ形式の正規表現に一致したら探索モード
+    else {
+        searchMode(urlhash);
+        logXMLLoader();
+    }
+});
+
+/**
+ * 記事クラス
+ * @param {Object} obj entry 要素の DOM オブジェクト
+ */
+function Entry(obj){
+    this.title = $("title:first", obj).text();
+    if (this.title == "") 
+        requiredElementError(obj, "title");
+    this.title = "<span>" + validateText(this.title) + "</span>";
+    this.content = $("content:first", obj).text();
+    this.content = "<span>" + validateText(this.content) + "</span>";
+    this.id = $("id:first", obj).text();
+    if (this.id == "") 
+        requiredElementError(obj, "id");
+    this.date = $("updated:first", obj).text();
+    if (this.date == "") 
+        requiredElementError(obj, "updated");
+    this.date = validateData(this.date);
+}
+
+/**
+ * 呼び出すとDIV:id名:writeArea上のHTMLを削除し、ロードエフェクトを表示します
+ */
+function loadingEffect(){
+    document.getElementById("writeArea").innerHTML = '<br/><br/><div id="drawPanel"><div id="drawItem" class="code" style="text-align: center;"><\/div><\/div>';
+    document.getElementById("drawItem").innerHTML = '<br/><img src="./js/ext/resources/images/default/shared/blue-loading.gif"><br/>長時間画面が切り替わらない場合はページをリロードしてください。<br/><br/>';
+    
+    // ロード表示用のパネルを生成
+    generatePanel("Now Loading .....", "drawItem", "drawPanel", false);
+}
+
+/**
+ * 日記データのエラー時の処理を行います
+ */
+function requiredElementError(parent, name){
+    Ext.Msg.alert("Error!", parent.ownerDocument.URL + ": 必須な要素 " +
+    name +
+    " が存在しないか空な " +
+    parent.tagName +
+    " 要素が存在します");
+}
+
+function xmlAttrContentEscape(str){
+    return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+}
+
+/**
+ * 日付のHTML表示用バリデーション処理を行います
+ * @param {String} data RFC3339形式のdate-time文字列
+ */
+function validateData(data){
+    var regT = new RegExp("T", "gm");
+    data = data.replace(regT, " ");
+    
+    // 秒数の小数点以下の部分はカットする
+    data = data.substring(0, 19);
+    
+    return data;
+}
+
+/**
+ * 日記本文のバリデーション処理を行います
+ * @param {String} contents 日記の本文が格納されている文字列
+ */
+function validateText(contents){
+
+    // Aタグを変換する
+    while (contents.match(/<a[^>]*>/)) {
+               // 置換対象のAタグを抽出する
+               var a_tag_str = contents.match(/<a[^>]*>/);
+               // href="..."の部分のみを抜き出す
+               var a_tag_link = a_tag_str[0].match(/href=["'][^"']*["']/);
+               // Aタグ全体をURIで置換し、再度Aタグのマッチングを行う
+               contents = contents.replace(a_tag_str, " [ " + a_tag_link[0].replace(/href=|["']/g, "") + " ] ");
+       }
+    // 通常のタグすべてを削除する
+    contents = contents.replace(/<[^>]*>|<\/[^>]*>/ig, "");
+    
+    // <br/>タグを挿入する
+    if (validateMode == 0) {
+        contents = contents.replace(/[\n\r]|\r\n/g, "<br />");
+    }
+    
+    return contents;
+}
+
+/**
+ * 日記本文に日付を付加します
+ * @param {String} contents 日記の本文が格納されている文字列
+ * @param {String} id 日記の初公開日を示す日付文字列
+ */
+function contentsWithid(contents, id){
+    // リンク用文末作成
+    var hashTag = '<br/><div style="text-align: right;"><a href="' +
+    xmlAttrContentEscape(blogUrl) +
+    '#' +
+    xmlAttrContentEscape(id) +
+    '" target="_blank">- この日の記事にリンクする -<\/a><\/span>';
+    return contents + hashTag;
+}
+
+/**
+ * ログファイル選択用のコンボボックスをid名:logSelecterに生成します
+ */
+function logXMLLoader(){
+    // レコード構造を定義します
+    var PathRecord = new Ext.data.Record.create([{
+        name: "display",
+        type: "string"
+    }, {
+        name: "path",
+        type: "string"
+    }]);
+    
+    // ログ用のXMLを読み込みます
+    var logXMLData = new Ext.data.Store();
+    jQuery.ajax({
+        url: logXmlUrl,
+        method: "GET",
+        error: showError,
+        success: function(xmlData){
+            var separateTag = xmlData.getElementsByTagName("file");
+            
+            // 読み込んだ要素をStoreに格納して表示
+            for (var i = 0; i < separateTag.length; i++) {
+                // レコードに登録する
+                var record = new PathRecord({
+                    path: separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue,
+                    display: separateTag[i].getElementsByTagName("display")[0].firstChild.nodeValue
+                });
+                logXMLData.add(record);
+            }
+            
+            // コンボボックス要素を生成
+            document.getElementById("logSelecter").innerHTML = "<input type='text' id='logbox' style='width: " + extComboWidth + "px'/>";
+            
+            // コンボボックスを生成
+            var comboBox = new Ext.form.ComboBox({
+                store: logXMLData,
+                applyTo: "logbox",
+                displayField: "display",
+                valueField: "path",
+                mode: "local",
+                triggerAction: "all",
+                emptyText: "ログを選択してください..."
+            });
+            
+            // コンボボックスのイベント登録
+            comboBox.on("change", function(){
+                xmlLoader("" + comboBox.getValue());
+            });
+        }
+    });
+}
+
+/**
+ * 日記のデータが記述されたXMLデータを読み込むロジックを生成します
+ * @param {String} fileName 読み込み日記のデータが記述されているXMLファイルのパス
+ */
+function xmlLoader(fileName){
+    // ロードエフェクトに切り替え
+    loadingEffect()
+    
+    var url = fileName;
+    
+    // 日記をロードします
+    var loader = new jQuery.ajax({
+        url: url,
+        method: "POST",
+        success: writeHtml,
+        error: showError
+    });
+}
+
+/**
+ * 日記データのエラー時の処理を行います
+ */
+function showError(){
+    document.getElementById("writeArea").innerHTML = '<div id="drawPanel"><div id="drawItem" class="code" style="text-align: center;"><\/div><\/div>';
+    document.getElementById("drawItem").innerHTML = '<br/>日記ファイルのロードに失敗しました!<br/><br/>';
+    
+    // エラー内容をパネルに描画
+    generatePanel("Error!", "drawItem", "drawPanel", false);
+    
+    Ext.Msg.alert("Error!", "日記ファイルが読み込めません!");
+}
+
+/**
+ * 渡された文字列と一致するfeed1.0:updated要素を持った日記を検索し、表示します
+ * @param {String} urlhash feed1.0:updated要素と一致する文字列
+ */
+function searchMode(urlhash){
+    // ロードエフェクト表示
+    loadingEffect();
+    
+    // ログXMLファイルを読み込む
+    var loader = new jQuery.ajax({
+        url: logXmlUrl,
+        method: "POST",
+        error: showError,
+        success: function(xmlData){
+            // ファイルパスの要素のみを抽出する
+            var separateTag = xmlData.getElementsByTagName("file");
+            var filelist = new Array(separateTag.length);
+            
+            // すべてのファイルパスを配列に格納する
+            for (var i = 0; i < separateTag.length; i++) {
+                // "path"ノードの値を格納
+                filelist[i] = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
+            }
+            
+            // ファイルパス配列に格納されているすべての日記に対し、探索を開始する
+            for (var i = 0; i < separateTag.length; i++) {
+                // ファイルパス配列の要素からリクエストを生成し、対象データをロードする
+                var searchlog = new jQuery.ajax({
+                    url: filelist[i],
+                    method: "POST",
+                    success: function(xmlData){
+                        // entry要素のみを切り出す
+                        var searchSeparateTag = xmlData.getElementsByTagName("entry");
+                        
+                        for (var j = 0; j < searchSeparateTag.length; j++) {
+                            // entryタグ内部のidノードの値のみ抽出し、入力されたhashと比較を行う
+                            var id = searchSeparateTag[j].getElementsByTagName("id")[0].firstChild.nodeValue;
+                            
+                            // idの値と比較を行う
+                            if (urlhash == id) {
+                                var entry = new Entry(searchSeparateTag[j]);
+                                
+                                document.getElementById("writeArea").innerHTML = '<div><table class="pager" width="' + extPanelWidth + '" cellspacing="1"><tbody>' +
+                                '<tr><td class="pager" colspan="3">1件~1件(全1件)目の記事を表示中<br/></td></tr>' +
+                                '<tr><td align="left"><<< 前の3件を表示</td><td align="center">[ 0 ]</td><td align="right">次の3件を表示 >>></td></tr></tbody></table></div>' +
+                                '<div style="line-height: ' +
+                                entrySpan +
+                                'px;"><br/></div>' +
+                                '<div id="drawPanel"><div id="drawItem" class="code"><\/div><\/div>' +
+                                '<div style="line-height: ' +
+                                entrySpan +
+                                'px;"><br/></div>' +
+                                '<div><table class="pager" width="' +
+                                extPanelWidth +
+                                '" cellspacing="1"><tbody>' +
+                                '<tr><td align="left"><<< 前の3件を表示</td><td align="center">[ 0 ]</td><td align="right">次の3件を表示 >>></td></tr>' +
+                                '<tr><td class="pager" colspan="3">1件~1件(全1件)目の記事を表示中<br/></td></tr></tbody></table></div>';
+                                document.getElementById("drawItem").innerHTML = contentsWithid(entry.content, entry.id);
+                                
+                                // 探索されたパネルはオープン状態で展開する
+                                generatePanel(entry.title + " / " + entry.date, "drawItem", "drawPanel", false);
+                                
+                                break;
+                            }
+                        }
+                    }
+                });
+            }
+            // ファイルパス配列から日記が見つからなかった場合の処理
+            document.getElementById("writeArea").innerHTML = '<br/><br/><div id="drawPanel"><div id="drawItem" class="code"><\/div><\/div>';
+            document.getElementById("drawItem").innerHTML = "指定された日記は存在しません。";
+            
+            // エラー内容を表示する
+            generatePanel("Search Failed.", "drawItem", "drawPanel", false);
+        }
+    });
+}
+
+/**
+ * 検索結果を分割して表示します
+ * @param {int} showLength 一回の画面に表示する記事数
+ * @param {int} startIndex 表示を開始する日記のインデックス
+ */
+function showEntriesRange(showLength, startIndex){
+    // メモリ上から日記データをロード
+    var entries = loadedEntries;
+    
+    // 表示インデックスが範囲外の場合はエラーパネルを表示して終了
+    if (startIndex < 0 || (entries.length <= startIndex && entries.length != 0)) {
+        showError();
+        return;
+    }
+    
+    var stringBuffer = [];
+    
+    // リミッターを設定する
+    var loopLimit = (showLength + startIndex > entries.length) ? entries.length : showLength + startIndex;
+    var indexShowEntries = loopLimit + 1;
+    
+    // 情報メニュー表示用バッファです
+    var menuInfoBuffer = [];
+    menuInfoBuffer.push("<tr><td colspan='3' class='pager'>");
+    var viewStartIndex = 0;
+    entries.length == 0 ? viewStartIndex = 0 : viewStartIndex = startIndex + 1
+    menuInfoBuffer.push(viewStartIndex + "件~" + loopLimit + "件(全" + entries.length + "件)目の記事を表示中<br/>");
+    menuInfoBuffer.push("</td></tr>");
+    
+    // ページ移動メニュー表示用バッファです
+    var menuMoveBuffer = [];
+    menuMoveBuffer.push("<tr>");
+    // 左パネルの表示制御
+    if (startIndex - showLength >= 0) {
+        menuMoveBuffer.push("\<td align='left'><a href='' onclick='showEntriesRange(" +
+        showLength +
+        ", " +
+        (startIndex - showLength) +
+        "); return false;'>\<\<\< 前の" +
+        showLength +
+        "件を表示</a\></td>");
+    }
+    else {
+        menuMoveBuffer.push("\<td align='left'>\<\<\< 前の" +
+        showLength +
+        "件を表示</a\></td>");
+    }
+    
+    // 中央のパネルの表示制御
+    menuMoveBuffer.push("<td align='center'>[ ");
+    var menuNumbers = Math.ceil(entries.length / showLength);
+    for (i = 0; i < menuNumbers; i++) {
+        if (startIndex / showLength == i) {
+            menuMoveBuffer.push(i + " ");
+        }
+        else {
+            menuMoveBuffer.push("<a href='' onclick='showEntriesRange(" +
+            showLength +
+            ", " +
+            (i * showLength) +
+            "); return false;'>");
+            menuMoveBuffer.push(i);
+            menuMoveBuffer.push("</a> ");
+        }
+    }
+    menuMoveBuffer.push("]</td>");
+    
+    // 右パネルの表示制御
+    if (entries.length > startIndex + showLength) {
+        menuMoveBuffer.push("\<td align='right'><a href='' onclick='showEntriesRange(" +
+        showLength +
+        ", " +
+        (startIndex + showLength) +
+        "); return false;'>\次の" +
+        showLength +
+        "件を表示 \>\>\></a\></td>");
+    }
+    else {
+        menuMoveBuffer.push("\<td align='right'>次の" +
+        showLength +
+        "件を表示 \>\>\></a\></td>");
+    }
+    menuMoveBuffer.push("</tr>");
+    
+    // メニューを結合してパネル(前方)に組み込みます
+    stringBuffer.push("<div><table cellspacing='1' width='" +
+    extPanelWidth +
+    "px' class='pager'><tbody>");
+    stringBuffer.push(menuInfoBuffer.join(""));
+    stringBuffer.push(menuMoveBuffer.join(""));
+    stringBuffer.push("</tbody></table></div>");
+    
+    stringBuffer.push('<div style="line-height: ' + entrySpan + 'px;"><br/></div>');
+    
+    // 日記描画部分のパネルを生成します
+    for (var i = startIndex; i < loopLimit; i++) {
+        stringBuffer.push('<div id="drawPanel');
+        stringBuffer.push(i);
+        stringBuffer.push('"><div id="drawItem');
+        stringBuffer.push(i);
+        stringBuffer.push('" class="code"><\/div><\/div><div style="line-height: ' + entrySpan + 'px;"><br/></div>')
+    }
+    
+    // メニューを結合してパネル(後方)に組み込みます
+    stringBuffer.push("<div><table cellspacing='1' width='" +
+    extPanelWidth +
+    "px' class='pager'><tbody>");
+    stringBuffer.push(menuMoveBuffer.join(""));
+    stringBuffer.push(menuInfoBuffer.join(""));
+    stringBuffer.push("</tbody></table></div>");
+    
+    document.getElementById("writeArea").innerHTML = stringBuffer.join("");
+    
+    for (var i = startIndex; i < loopLimit; i++) {
+        // 各要素をオブジェクトに格納します
+        var entry = entries[i];
+        document.getElementById("drawItem" + i).innerHTML = contentsWithid(entry.content, entry.id);
+        
+        // すべてのパネルをオープン状態で生成します
+        generatePanel(entry.title + " / " + entry.date, "drawItem" + i, "drawPanel" + i, false);
+    }
+}
+
+/**
+ * 日記のログファイルデータが記述されているXMLファイルを読み込んで表示します。DIV:id名:writeArea上に読み込んだ日記の内容を表示します
+ * @param {Object} xmlData 日記が記述されたXMLファイル(feed 1.0準拠)
+ */
+function writeHtml(xmlData){
+    var separateTag = xmlData.getElementsByTagName("entry");
+    var stringBuffer = [];
+    // メモリ上での保持変数を初期化します
+    loadedEntries = [];
+    
+    // メモリ上の変数に全ての日記要素を格納します
+    for (var i = 0; i < separateTag.length; i++) {
+        loadedEntries.push(new Entry(separateTag[i]));
+    }
+    
+    // 表示ロジック呼び出し
+    showEntriesRange(showLength, 0);
+}
+