OSDN Git Service

Fixed bug not change title when you update diary.
[feedblog/feedblog_ext.git] / js / lunardial / feedblog_gen.js
1 /**
2  * FeedBlog Generator
3  *
4  * @copyright 2009 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)
5  * @author Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)
6  * @since 2009/06/03
7  * @version 3.0.0.0
8  */
9 // Feex XMLの<content>要素で、<br>を使用しているか?
10 var inputValidateMode = 1;
11 // 出力時に<content>要素に<br>を付加するか否かを格納する変数
12 var outputValidateMode = 1;
13 // ログのリストが書かれたXMLのファイルパスを記入してください
14 var logXmlUrl = "./xml/loglist.xml";
15
16 // フィードの基本情報を記録する変数
17 var feedInfo;
18 // 記事リストを格納する変数
19 var entryList;
20 // 現在編集中の記事の位置を示す変数
21 var editIndex;
22 // feedblogの設置アドレスを格納する変数
23 var pageAddr;
24 // コンボボックスの横幅を指定します
25 var comboWidth = 250;
26
27 /**
28  * 編集中の内容を反映し、画面に出力します
29  */
30 function applyChange(){
31     feedInfo = applyFeedinfo();
32     pageAddr = feedInfo.alternate;
33     
34     if (document.getElementById("entry_title").value == "" || document.getElementById("entry_stdin").value == "") {
35         if (confirm("タイトルか記事が空白です!FeedBlogでの表示時にエラーが出ますがよろしいですか?") == false) {
36             return;
37         }
38     }
39     
40     if (editIndex < 0) {
41         var entry = new Object();
42         var dateRfc3339 = getDate();
43         entry.id = pageAddr + "?" + dateRfc3339;
44         entry.title = document.getElementById("entry_title").value;
45         entry.summary = "";
46         entry.published = dateRfc3339;
47         entry.updated = dateRfc3339;
48         entry.link = pageAddr + "#" + entry.id;
49         entry.content = document.getElementById("entry_stdin").value.replace(/\r\n/g, "\n");
50         entryList.unshift(entry);
51         
52         // ログ一覧を更新する
53         refleshEntrylistBox();
54         
55         // 更新後、選択されている項目を、先刻追加した日記に移動する
56         document.getElementById("logBox").selectedIndex = 1;
57         editIndex = 0;
58     }
59     else {
60         entryList[editIndex].title = document.getElementById("entry_title").value;
61         entryList[editIndex].updated = getDate();
62         entryList[editIndex].content = document.getElementById("entry_stdin").value.replace(/\r\n/g, "\n");
63                 
64                 document.getElementById("logBox").options[editIndex + 1].text = entryList[editIndex].title;
65     }
66     
67     document.getElementById("stdout").value = toXml(feedInfo, entryList);
68     
69     // プレビューエリアにHTMLを表示します
70     document.getElementById("previewArea").innerHTML = entryList[editIndex].content.replace(/\n/g, "<br>");
71 }
72
73 /**
74  * 選択中の記事を削除します
75  * @param {int} index entryListから削除される記事のインデックス
76  */
77 function removeEntry(index){
78     if (editIndex == 0) {
79         entryList.splice(editIndex, 1);
80         refleshEntrylistBox();
81         editIndex = -1;
82         
83         document.getElementById("stdout").value = ""
84         document.getElementById("entry_title").value = "";
85         document.getElementById("entry_stdin").value = "";
86     }
87     if (editIndex > 0) {
88         var prevIndex = document.getElementById("logBox").selectedIndex - 1;
89         entryList.splice(editIndex, 1);
90         refleshEntrylistBox();
91         document.getElementById("logBox").selectedIndex = prevIndex;
92         editIndex = editIndex - 1;
93         
94         entryLoader(editIndex);
95     }
96     
97     // プレビューエリアをクリアします
98     document.getElementById("previewArea").innerHTML = "";
99 }
100
101 /**
102  * すべての記事を削除します
103  */
104 function allRemoveEntry(){
105     entryList = [];
106     
107     editIndex = -1;
108     refleshEntrylistBox();
109     
110     document.getElementById("stdout").value = ""
111     document.getElementById("entry_title").value = "";
112     document.getElementById("entry_stdin").value = "";
113 }
114
115 /**
116  * 全DOMが使用可能になり次第、自動的に呼ばれる関数
117  */
118 function initLoad(){
119     if (outputValidateMode == 1) {
120         document.getElementById("addContentBr").checked = true;
121     }
122     else {
123         document.getElementById("addContentBr").checked = false;
124     }
125     
126     logXMLLoader();
127 }
128
129 /**
130  * ログファイル選択用のコンボボックスをid名:logSelecterに生成します
131  */
132 function logXMLLoader(){
133     // ログ用のXMLを読み込みます
134     jQuery.ajax({
135         url: logXmlUrl,
136         method: "GET",
137         success: function(xmlData){
138             var separateTag = xmlData.getElementsByTagName("file");
139             var fileList = new Array(separateTag.length);
140             var initUrl;
141             
142             // 読み込んだ要素をStoreに格納して表示
143             var boxBuffer = [];
144             boxBuffer.push("<form name='logform'><select name='logbox' style='width: " + comboWidth + "px' onchange='xmlLoader(this.options[this.selectedIndex].value)'>");
145             for (var i = 0; i < separateTag.length; i++) {
146                 if (i == 0) {
147                     initUrl = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
148                 }
149                 boxBuffer.push("<option value='" + separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue + "'/>" + separateTag[i].getElementsByTagName("display")[0].firstChild.nodeValue + " (" + separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue + ")" + "</option>");
150             }
151             boxBuffer.push("</select></form>");
152             
153             // コンボボックス要素を生成
154             document.getElementById("logSelecter").innerHTML = boxBuffer.join("");
155             
156             // 最新の日記をローディングする
157             xmlLoader(initUrl);
158         },
159         error: showError
160     });
161 }
162
163 /**
164  * URLを指定し、指定されたFeedXmlを読み込み、解析を行います
165  * @param {String} url
166  */
167 function xmlLoader(url){
168     // 日記本体のデータをローディングする
169     var loader = new jQuery.ajax({
170         url: url,
171         method: "GET",
172         success: analyzeTargetXml,
173         error: showError
174     });
175 }
176
177 /**
178  * 引数に存在するXMLデータを解析し、画面に反映します
179  * @param {Object} xmlData
180  */
181 function analyzeTargetXml(xmlData){
182     var rootTag = xmlData.getElementsByTagName("feed");
183     var entryTag = xmlData.getElementsByTagName("entry");
184     
185     // グローバル変数を初期化
186     feedInfo = null;
187     entryList = [];
188     
189     feedInfo = new FeedInfo(rootTag[0]);
190     for (var i = 0; i < entryTag.length; i++) {
191         entryList.push(new Entry(entryTag[i]));
192     }
193     
194     feedinfoLoader(feedInfo);
195     pageAddr = feedInfo.alternate;
196     
197     refleshEntrylistBox();
198     document.getElementById("entry_title").value = "";
199     document.getElementById("entry_stdin").value = "";
200     document.getElementById("stdout").value = "";
201     editIndex = -1;
202     
203     // プレビューエリアをクリアします
204     document.getElementById("previewArea").innerHTML = "";
205 }
206
207 /**
208  * feedInfo変数の内容をHTMLに反映します
209  * @param {FeedInfo} finfo 反映するfeedInfo変数
210  */
211 function feedinfoLoader(finfo){
212     document.getElementById("feed_title").value = finfo.title;
213     document.getElementById("feed_subtitle").value = finfo.subtitle;
214     document.getElementById("feed_self").value = finfo.self;
215     document.getElementById("feed_alternate").value = finfo.alternate;
216     document.getElementById("feed_id").value = finfo.id;
217     document.getElementById("feed_rights").value = finfo.rights;
218     document.getElementById("feed_authorname").value = finfo.authorname;
219     document.getElementById("feed_authoremail").value = finfo.authoremail;
220 }
221
222 /**
223  * HTMLの内容をFeedInfoに変換します
224  */
225 function applyFeedinfo(){
226     var finfo = new Object();
227     finfo.title = document.getElementById("feed_title").value;
228     finfo.subtitle = document.getElementById("feed_subtitle").value;
229     finfo.self = document.getElementById("feed_self").value;
230     finfo.alternate = document.getElementById("feed_alternate").value;
231     finfo.id = document.getElementById("feed_id").value;
232     finfo.rights = document.getElementById("feed_rights").value;
233     finfo.authorname = document.getElementById("feed_authorname").value;
234     finfo.authoremail = document.getElementById("feed_authoremail").value;
235     
236     return finfo;
237 }
238
239 /**
240  * 指定したEntryList上のインデックスの記事をロードします
241  * @param {int} index
242  */
243 function entryLoader(index){
244     if (index < 0) {
245         document.getElementById("entry_title").value = "";
246         document.getElementById("entry_stdin").value = "";
247         editIndex = -1;
248     }
249     else {
250         document.getElementById("entry_title").value = entryList[index].title;
251         document.getElementById("entry_stdin").value = entryList[index].content;
252         editIndex = index;
253     }
254     
255     // プレビューエリアをクリアします
256     document.getElementById("previewArea").innerHTML = "";
257 }
258
259 /**
260  * 記事一覧の情報を表示するセレクトボックスにentryListの情報を反映させます
261  */
262 function refleshEntrylistBox(){
263     var stringBuffer = [];
264     stringBuffer.push("<form name='logform'><select id='logBox' style='width: " + comboWidth + "px' onchange='entryLoader(this.options[this.selectedIndex].value)'>");
265     stringBuffer.push("<option value='-1'>新規作成</option>");
266     for (var i = 0; i < entryList.length; i++) {
267         stringBuffer.push("<option value='" + i + "'/>" + entryList[i].title + "</option>");
268     }
269     stringBuffer.push("</select></form>");
270     // コンボボックス要素を生成
271     document.getElementById("entrySelect").innerHTML = stringBuffer.join("");
272 }
273
274 /**
275  * Feed基本情報保持クラス
276  * @param {Object} obj
277  */
278 function FeedInfo(obj){
279     this.title = $("title:first", obj).text();
280     this.subtitle = $("subtitle:first", obj).text();
281     this.self = $("link[rel=self]", obj).attr("href");
282     this.alternate = $("link[rel=alternate]", obj).attr("href");
283     this.updated = $("updated:first", obj).text();
284     this.id = $("id:first", obj).text();
285     this.rights = $("rights:first", obj).text();
286     this.authorname = $("author>name", obj).text();
287     this.authoremail = $("author>email", obj).text();
288 }
289
290 /**
291  * 記事クラス
292  * @param {Object} obj entry 要素の DOM オブジェクト
293  */
294 function Entry(obj){
295     this.id = $("id:first", obj).text();
296     this.title = $("title:first", obj).text();
297     this.summary = $("summary:first", obj).text();
298     this.published = $("published:first", obj).text();
299     this.updated = $("updated:first", obj).text();
300     this.link = $("link:first", obj).attr("href");
301     this.content = $("content:first", obj).text();
302     
303     if (inputValidateMode == 1) {
304         this.content = this.content.replace(/[\r\n]|\r\n/g, "");
305         this.content = this.content.replace(/<br[ \/]*>/ig, "\n");
306         this.content = this.content.replace(/^[ \t]*/mg, "");
307     }
308 }
309
310 /**
311  * グローバル変数からXMLを生成し、返却します
312  * @param {FeedInfo} finfo
313  * @param {Entry[]} elist
314  */
315 function toXml(finfo, elist){
316     var stringBuffer = [];
317     
318     stringBuffer.push('<?xml version="1.0" encoding="utf-8"?>');
319     stringBuffer.push('<feed xml:lang="ja-jp" xmlns="http://www.w3.org/2005/Atom">');
320     stringBuffer.push('');
321     
322     stringBuffer.push('<title type="text">' + finfo.title + '</title>');
323     stringBuffer.push('<subtitle type="text">' + finfo.subtitle + '</subtitle>');
324     stringBuffer.push('<link rel="self" type="application/atom+xml" href="' + finfo.self + '" />');
325     stringBuffer.push('<link rel="alternate" type="text/html" href="' + finfo.alternate + '" />');
326     stringBuffer.push('<updated>' + getDate() + '</updated>');
327     stringBuffer.push('<id>' + finfo.id + '</id>');
328     stringBuffer.push('<rights type="text">' + finfo.rights + '</rights>');
329     stringBuffer.push('<author>');
330     stringBuffer.push('    <name>' + finfo.authorname + '</name>');
331     stringBuffer.push('    <email>' + finfo.authoremail + '</email>');
332     stringBuffer.push('</author>');
333     stringBuffer.push('');
334     
335     for (var i = 0; i < elist.length; i++) {
336         var temp_content;
337         if (document.getElementById("addContentBr").checked) {
338             temp_content = xmlAttrContentEscape(convertContent(elist[i].content));
339         }
340         else {
341             temp_content = xmlAttrContentEscape(elist[i].content);
342         }
343         
344         stringBuffer.push('<entry>');
345         stringBuffer.push('<id>' + elist[i].id + '</id>');
346         stringBuffer.push('<title>' + elist[i].title + '</title>');
347         stringBuffer.push('<summary>' + elist[i].summary + '</summary>');
348         stringBuffer.push('<published>' + elist[i].published + '</published>');
349         stringBuffer.push('<updated>' + elist[i].updated + '</updated>');
350         stringBuffer.push('<link href="' + elist[i].link + '" />');
351         stringBuffer.push('<content type="html">' + temp_content + '</content>');
352         stringBuffer.push('</entry>');
353         stringBuffer.push('');
354     }
355     
356     stringBuffer.push('</feed>');
357     
358     return stringBuffer.join("\n");
359 }
360
361 /**
362  * <content>要素の変換を行います
363  * @param {String} content
364  */
365 function convertContent(content){
366     if (document.getElementById("addContentBr").checked) {
367         content = content.replace(/[\n\r]|\r\n/g, "<br>\n");
368     }
369     else {
370         content = content.replace(/<br>/ig, "\n");
371     }
372     
373     return content;
374 }
375
376 /**
377  * XMLのエスケープを行う関数
378  * @param {String} str エスケープを行う文字列
379  */
380 function xmlAttrContentEscape(str){
381     return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/^[ ]+/mg, "&nbsp;").replace(/^[\t]+/mg, "");
382 }
383
384 /**
385  * XMLの逆エスケープを行う関数
386  * @param {String} str 逆エスケープを行う文字列
387  */
388 function xmlAttrContentUnescape(str){
389     return str.replace(/^[\t]+/mg, "").replace(/^[ ]+/mg, "&nbsp;").replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
390 }
391
392 /**
393  * jQueryでのパネル開閉を制御します
394  * @param {String} id 開閉するオブジェクトのid
395  */
396 function closePanel(id){
397     $("#" + id).slideToggle();
398 }
399
400 /**
401  * エラー画面を表示します
402  */
403 function showError(){
404     alert("XMLファイルのローディング中にエラーが発生しました!");
405 }
406
407 /**
408  * RFC3339形式の日時を出力します
409  */
410 function getDate(){
411     var dNow = new Date();
412     var sYear = dNow.getFullYear();
413     var sMonth = dNow.getMonth() + 1;
414     var sDate = dNow.getDate();
415     var sHour = dNow.getHours();
416     var sMinute = dNow.getMinutes();
417     var sSecond = dNow.getSeconds();
418     
419     // 10以下の時は頭に"0"を挿入
420     if (sMonth < 10) 
421         sMonth = "0" + sMonth;
422     if (sDate < 10) 
423         sDate = "0" + sDate;
424     if (sHour < 10) 
425         sHour = "0" + sHour;
426     if (sMinute < 10) 
427         sMinute = "0" + sMinute;
428     if (sSecond < 10) 
429         sSecond = "0" + sSecond;
430     
431     return sYear + "-" + sMonth + "-" + sDate + "T" + sHour + ":" + sMinute + ":" + sSecond + "+09:00";
432 }