OSDN Git Service

- add jquery-te editor to generator.
[feedblog/feedblog.git] / js / lunardial / feedblog_generator.js
1 /**\r
2  * FeedBlog Generator\r
3  *\r
4  * @copyright 2009 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)\r
5  * @author Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)\r
6  * @since 2009/06/03\r
7  * @version 4.2.0.0\r
8  */\r
9 \r
10 // Feex XMLの<content>要素で、<br>を使用しているか?\r
11 var inputValidateMode = 1;\r
12 // 出力時に<content>要素に<br>を付加するか否かを格納する変数\r
13 var outputValidateMode = 1;\r
14 // ログのリストが書かれたXMLのファイルパスを記入してください\r
15 var logXmlUrl;\r
16 \r
17 // フィードの基本情報を記録する変数\r
18 var feedInfo;\r
19 // 記事リストを格納する変数\r
20 var entryList;\r
21 // 現在編集中の記事の位置を示す変数\r
22 var editIndex;\r
23 // feedblogの設置アドレスを格納する変数\r
24 var pageAddr;\r
25 \r
26 /**\r
27  * 編集中の内容を反映し、画面に出力します\r
28  */\r
29 function applyChange() {\r
30         feedInfo = applyFeedinfo();\r
31         pageAddr = feedInfo.alternate;\r
32 \r
33         if (document.getElementById("entry_title").value == "" || document.getElementById("entry_stdin").value == "") {\r
34                 if (confirm("タイトルか記事が空白です!FeedBlogでの表示時にエラーが出ますがよろしいですか?") == false) {\r
35                         return;\r
36                 }\r
37         }\r
38 \r
39         if (editIndex < 0) {\r
40                 var entry = new Object();\r
41                 var dateRfc3339 = getDate();\r
42                 entry.id = pageAddr + "?" + dateRfc3339;\r
43                 entry.title = document.getElementById("entry_title").value;\r
44                 entry.summary = "";\r
45                 entry.published = dateRfc3339;\r
46                 entry.updated = dateRfc3339;\r
47                 entry.link = pageAddr + "#" + entry.id;\r
48                 entry.content = document.getElementById("entry_stdin").value.replace(/\r\n/g, "\n");\r
49                 entry.category = getTags();\r
50                 entryList.unshift(entry);\r
51 \r
52                 // ログ一覧を更新する\r
53                 refleshEntrylistBox();\r
54 \r
55                 // 更新後、選択されている項目を、先刻追加した日記に移動する\r
56                 document.getElementById("logBox").selectedIndex = 1;\r
57                 editIndex = 0;\r
58         } else {\r
59                 entryList[editIndex].title = document.getElementById("entry_title").value;\r
60                 entryList[editIndex].updated = getDate();\r
61                 entryList[editIndex].content = document.getElementById("entry_stdin").value.replace(/\r\n/g, "\n");\r
62                 entryList[editIndex].category = getTags();\r
63 \r
64                 document.getElementById("logBox").options[parseInt(editIndex) + 1].text = entryList[editIndex].title;\r
65         }\r
66 \r
67         document.getElementById("stdout").value = toXml(feedInfo, entryList);\r
68 \r
69         // プレビューエリアにHTMLを表示します\r
70         document.getElementById("previewArea").innerHTML = entryList[editIndex].content.replace(/\n/g, "<br>");\r
71 }\r
72 \r
73 /**\r
74  * mixi用に記事を変換し、ウインドウを立ち上げて表示します\r
75  */\r
76 function openMixiWindow() {\r
77         // 日記が選択されていない場合は何もしない\r
78         if (editIndex < 0) {\r
79                 return;\r
80         }\r
81 \r
82         // HTMLを生成します\r
83         var window_str = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>FeedBlog Mixi用変換</title><style type="text/css">body {font-size: 12px;line-height: 18px;color: #004488;margin-top: 10px; margin-bottom: 10px;}td.default {font-size: 12px;line-height: 18px;color: #004488;border: 1px solid #8888ff;text-align: left;vertical-align: top;}div {text-align: left;}div.code {background: #f8f8ff;border: 1px solid #c8c8ff;padding: 10px;margin: 10px;margin-left: 0px;border-left: 5px solid #e8e8ff;font-size: 12px;line-height: 18px;}table.pager {padding: 0px;margin: 0px;border: 1px solid #8888ff;}td.pager {border: 1px solid #8888ff;padding-left: 3px;}td.formheader {font-size: 9pt;line-height: 13pt;font-family: sans-serif;font-weight: bold;padding: 3px;border: 1px solid #C5C5DE;background-color: #FAFAFF;}td.forminput {font-size: 9pt;line-height: 13pt;font-family: sans-serif;padding: 5px;border: 1px dotted #C5C5DE;}input {font-size: 9pt;line-height: 13pt;font-family: sans-serif;color: #1E4080;border: 1px dotted #BABAFE;background-color: #F5F5FF;}textarea {font-size: 9pt;line-height: 13pt;font-family: sans-serif;color: #1E4080;border: 1px dotted #BABAFE;background-color: #F5F5FF;}</style></head><body><center><table align="center" style="width: 800px;"><tbody><tr><td class="default" colspan="2" style="padding: 5px; text-align: center; vertical-align: bottom;"><table style="width: 100%"><tbody><tr><td class="formheader" style="text-align: center; width: 100px;">タイトル</td><td class="forminput" style="padding: 0px 5px 0px 3px;"><input type="text" id="entry_title" style="width: 100%" value="' + entryList[editIndex].title + '"></td></tr><tr><td class="formheader" style="text-align: center;">本文</td><td class="forminput" style="padding: 0px 5px 0px 3px;"><textarea id="entry_stdin" rows="20" style="width: 100%">' + mixiWrapper(entryList[editIndex].content) + '</textarea></td></tr></tbody></table></td></tr></tbody></table><br><input type="button" value="ウインドウを閉じる" onclick="javascript: window.close();"></center></body></html>';\r
84 \r
85         // ウインドウに書き出します\r
86         var mixi_win = window.open('', 'feedblog_mixi_wrapper', 'width = 850, height = 490, scrollbars=yes');\r
87         mixi_win.document.open();\r
88         mixi_win.document.write(window_str);\r
89         mixi_win.document.close();\r
90 }\r
91 \r
92 /**\r
93  * mixi用に通常のHTMLを変換します\r
94  * @param {String} contents 日記の本文が格納されている文字列\r
95  */\r
96 function mixiWrapper(contents) {\r
97         // 置換に使用する変数\r
98         var target_tag;\r
99         var target_element;\r
100 \r
101         // ニコニコ動画のタグを置換\r
102         while ( target_tag = contents.match(/<iframe[^>]*src=["']http:\/\/ext.nicovideo.jp\/thumb\/[A-Za-z]*\d*["'][^>]*>[^<]*<\/iframe>/i)) {\r
103                 // src="..."の部分だけ抜き出す\r
104                 target_element = target_tag[0].match(/src=["'][^"']*["']/i);\r
105                 target_element = '&lt;externalvideo src=&quot;NC:' + target_element[0].replace(/src=["']http:\/\/ext.nicovideo.jp\/thumb\/|["']/ig, "") + ':D&quot;&gt;';\r
106                 // iframeタグ全体を置換する\r
107                 contents = contents.replace(target_tag, target_element);\r
108         }\r
109 \r
110         // Aタグを変換する\r
111         while (contents.match(/<a[^>]*>/)) {\r
112                 // 置換対象のAタグを抽出する\r
113                 target_tag = contents.match(/<a[^>]*>/i);\r
114                 // href="..."の部分のみを抜き出す\r
115                 target_element = target_tag[0].match(/href=["'][^"']*["']/i);\r
116                 // 相対URIが検出された場合、フルに置換する\r
117                 var baseUri = document.location.href.replace(/[^\/]+$/, '');\r
118                 target_element = target_element[0].replace(/\.\//, baseUri).replace(/\.\.\//g, "");\r
119                 // Aタグ全体を消去し、再度Aクローズタグの置換を行う\r
120                 contents = contents.replace(target_tag, "");\r
121                 contents = contents.replace(/<\/a>/i, " ( " + target_element.replace(/href=|["']/g, "") + " ) ");\r
122         }\r
123 \r
124         // ブロック要素のタグが存在した場合、改行をその後に挿入します。\r
125         if (document.getElementById("isCoverBlockTag").checked) {\r
126                 contents = contents.replace(/<(div|h\d)[^>]*>/ig, "-----------------------------------------------------------------------------\n");\r
127                 contents = contents.replace(/(\n|)<\/(div|h\d)>/ig, "\n-----------------------------------------------------------------------------\n");\r
128         } else {\r
129                 contents = contents.replace(/<\/(div|h\d|p)>/ig, "\n");\r
130         }\r
131 \r
132         // li要素を置換する\r
133         contents = contents.replace(/<[\/]{0,1}ul>/ig, "");\r
134         contents = contents.replace(/<li>/ig, "・");\r
135         contents = contents.replace(/<\/li>/ig, "\n");\r
136 \r
137         // 通常のタグすべてを削除する\r
138         contents = contents.replace(/<[^>]*>|<\/[^>]*>/ig, "");\r
139 \r
140         // 通常のタグ置換後、ニコニコ動画のタグを元に戻す\r
141         contents = contents.replace(/&lt;externalvideo src=&quot;NC:/g, "<externalvideo src='NC:");\r
142         contents = contents.replace(/:D&quot;&gt;/, ":D'>");\r
143 \r
144         // 半角を置換する\r
145         contents = contents.replace(/&nbsp;/g, " ");\r
146 \r
147         return contents;\r
148 }\r
149 \r
150 /**\r
151  * 選択中の記事を削除します\r
152  * @param {int} index entryListから削除される記事のインデックス\r
153  */\r
154 function removeEntry(index) {\r
155         if (editIndex == 0) {\r
156                 entryList.splice(editIndex, 1);\r
157                 refleshEntrylistBox();\r
158                 editIndex = -1;\r
159 \r
160                 document.getElementById("stdout").value = "";\r
161                 document.getElementById("entry_title").value = "";\r
162                 $("#entry_stdin").jqte();\r
163                 document.getElementById("entry_stdin").value = "";\r
164                 $("#entry_stdin").jqte();\r
165         }\r
166         if (editIndex > 0) {\r
167                 var prevIndex = document.getElementById("logBox").selectedIndex - 1;\r
168                 entryList.splice(editIndex, 1);\r
169                 refleshEntrylistBox();\r
170                 document.getElementById("logBox").selectedIndex = prevIndex;\r
171                 editIndex = editIndex - 1;\r
172 \r
173                 entryLoader(editIndex);\r
174         }\r
175 \r
176         // プレビューエリアをクリアします\r
177         document.getElementById("previewArea").innerHTML = "";\r
178 }\r
179 \r
180 /**\r
181  * すべての記事を削除します\r
182  */\r
183 function allRemoveEntry() {\r
184         entryList = [];\r
185 \r
186         editIndex = -1;\r
187         refleshEntrylistBox();\r
188 \r
189         document.getElementById("stdout").value = "";\r
190         document.getElementById("entry_title").value = "";\r
191         $("#entry_stdin").jqte();\r
192         document.getElementById("entry_stdin").value = "";\r
193         $("#entry_stdin").jqte();\r
194 }\r
195 \r
196 /**\r
197  * 全ての定数を取得・セットします\r
198  */\r
199 function initialize() {\r
200         inputValidateMode = $("#feedblog_inputvalidatemode").val();\r
201         outputValidateMode = $("#feedblog_outputvalidatemode").val();\r
202         logXmlUrl = $("#feedblog_loglistxmlurl").val();\r
203 \r
204         if (outputValidateMode == "1") {\r
205                 document.getElementById("feedblog_addcontentbr").checked = true;\r
206         } else {\r
207                 document.getElementById("feedblog_addcontentbr").checked = false;\r
208         }\r
209 }\r
210 \r
211 /**\r
212  * 全DOMが使用可能になり次第、自動的に呼ばれる関数\r
213  */\r
214 $(document).ready(function() {\r
215         // 初期処理を実施\r
216         initialize();\r
217 \r
218         // jquery-teを初期として適用します\r
219         $("#entry_stdin").jqte();\r
220 \r
221         // ログ一覧のXMLをロードします\r
222         logXMLLoader();\r
223 });\r
224 \r
225 /**\r
226  * ログファイル選択用のコンボボックスをid名:feedblog_logselecterに生成します\r
227  */\r
228 function logXMLLoader() {\r
229         // ログ用のXMLを読み込みます\r
230         jQuery.ajax({\r
231                 url : logXmlUrl + "?time=" + (+new Date()),\r
232                 method : "GET",\r
233                 success : function(xmlData) {\r
234                         var separateTag = xmlData.getElementsByTagName("file");\r
235                         var urls = new Array(separateTag.length);\r
236                         var initUrl;\r
237 \r
238                         // 読み込んだ要素をStoreに格納して表示\r
239                         var boxBuffer = [];\r
240                         boxBuffer.push("<form name='logform'><select name='logbox' onchange='xmlLoader(this.options[this.selectedIndex].value)'>");\r
241                         for (var i = 0; i < separateTag.length; i++) {\r
242                                 if (i == 0) {\r
243                                         initUrl = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;\r
244                                 }\r
245                                 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>");\r
246                         }\r
247                         boxBuffer.push("</select></form>");\r
248 \r
249                         // コンボボックス要素を生成\r
250                         document.getElementById("feedblog_logselecter").innerHTML = boxBuffer.join("");\r
251 \r
252                         // 最新の日記をローディングする\r
253                         xmlLoader(initUrl);\r
254                 },\r
255                 error : showError\r
256         });\r
257 }\r
258 \r
259 /**\r
260  * URLを指定し、指定されたFeedXmlを読み込み、解析を行います\r
261  * @param {String} url\r
262  */\r
263 function xmlLoader(url) {\r
264         // 記事本体のデータをローディングする\r
265         var loader = new jQuery.ajax({\r
266                 url : url + "?time=" + (+new Date()),\r
267                 method : "GET",\r
268                 success : analyzeTargetXml,\r
269                 error : showError\r
270         });\r
271 }\r
272 \r
273 /**\r
274  * 引数に存在するXMLデータを解析し、画面に反映します\r
275  * @param {Object} xmlData\r
276  */\r
277 function analyzeTargetXml(xmlData) {\r
278         var rootTag = xmlData.getElementsByTagName("feed");\r
279         var entryTag = xmlData.getElementsByTagName("entry");\r
280 \r
281         // グローバル変数を初期化\r
282         feedInfo = null;\r
283         entryList = [];\r
284 \r
285         feedInfo = new FeedInfo(rootTag[0]);\r
286         for (var i = 0; i < entryTag.length; i++) {\r
287                 entryList.push(new Entry(entryTag[i]));\r
288         }\r
289 \r
290         feedinfoLoader(feedInfo);\r
291         pageAddr = feedInfo.alternate;\r
292 \r
293         refleshEntrylistBox();\r
294         document.getElementById("entry_title").value = "";\r
295         $("#entry_stdin").jqte();\r
296         document.getElementById("entry_stdin").value = "";\r
297         $("#entry_stdin").jqte();\r
298         document.getElementById("entry_category").innerHTML = "";\r
299         document.getElementById("stdout").value = "";\r
300         editIndex = -1;\r
301 \r
302         // プレビューエリアをクリアします\r
303         document.getElementById("previewArea").innerHTML = "";\r
304 }\r
305 \r
306 /**\r
307  * feedInfo変数の内容をHTMLに反映します\r
308  * @param {FeedInfo} finfo 反映するfeedInfo変数\r
309  */\r
310 function feedinfoLoader(finfo) {\r
311         document.getElementById("feed_title").value = finfo.title;\r
312         document.getElementById("feed_subtitle").value = finfo.subtitle;\r
313         document.getElementById("feed_self").value = finfo.self;\r
314         document.getElementById("feed_alternate").value = finfo.alternate;\r
315         document.getElementById("feed_id").value = finfo.id;\r
316         document.getElementById("feed_rights").value = finfo.rights;\r
317         document.getElementById("feed_authorname").value = finfo.authorname;\r
318         document.getElementById("feed_authoremail").value = finfo.authoremail;\r
319 }\r
320 \r
321 /**\r
322  * HTMLの内容をFeedInfoに変換します\r
323  */\r
324 function applyFeedinfo() {\r
325         var finfo = new Object();\r
326         finfo.title = document.getElementById("feed_title").value;\r
327         finfo.subtitle = document.getElementById("feed_subtitle").value;\r
328         finfo.self = document.getElementById("feed_self").value;\r
329         finfo.alternate = document.getElementById("feed_alternate").value;\r
330         finfo.id = document.getElementById("feed_id").value;\r
331         finfo.rights = document.getElementById("feed_rights").value;\r
332         finfo.authorname = document.getElementById("feed_authorname").value;\r
333         finfo.authoremail = document.getElementById("feed_authoremail").value;\r
334 \r
335         return finfo;\r
336 }\r
337 \r
338 /**\r
339  * 指定したEntryList上のインデックスの記事をロードします\r
340  * @param {int} index\r
341  */\r
342 function entryLoader(index) {\r
343         if (index < 0) {\r
344                 document.getElementById("entry_title").value = "";\r
345                 $("#entry_stdin").jqte();\r
346                 document.getElementById("entry_stdin").value = "";\r
347                 $("#entry_stdin").jqte();\r
348                 addTagSelectBoxFromCategory([]);\r
349                 editIndex = -1;\r
350         } else {\r
351                 document.getElementById("entry_title").value = entryList[index].title;\r
352                 $("#entry_stdin").jqte();\r
353                 document.getElementById("entry_stdin").value = entryList[index].content;\r
354                 $("#entry_stdin").jqte();\r
355                 addTagSelectBoxFromCategory(entryList[index].category);\r
356                 editIndex = index;\r
357         }\r
358 \r
359         // プレビューエリアをクリアします\r
360         document.getElementById("previewArea").innerHTML = "";\r
361 }\r
362 \r
363 /**\r
364  * 記事一覧の情報を表示するセレクトボックスにentryListの情報を反映させます\r
365  */\r
366 function refleshEntrylistBox() {\r
367         var stringBuffer = [];\r
368         stringBuffer.push("<form name='logform'><select id='logBox' onchange='entryLoader(this.options[this.selectedIndex].value)'>");\r
369         stringBuffer.push("<option value='-1'>新規作成</option>");\r
370         for (var i = 0; i < entryList.length; i++) {\r
371                 stringBuffer.push("<option value='" + i + "'/>" + entryList[i].title + "</option>");\r
372         }\r
373         stringBuffer.push("</select></form>");\r
374         // コンボボックス要素を生成\r
375         document.getElementById("feedblog_entryselect").innerHTML = stringBuffer.join("");\r
376 }\r
377 \r
378 /**\r
379  * Feed基本情報保持クラス\r
380  * @param {Object} obj\r
381  */\r
382 function FeedInfo(obj) {\r
383         this.title = $("title:first", obj).text();\r
384         this.subtitle = $("subtitle:first", obj).text();\r
385         this.self = $("link[rel=self]", obj).attr("href");\r
386         this.alternate = $("link[rel=alternate]", obj).attr("href");\r
387         this.updated = $("updated:first", obj).text();\r
388         this.id = $("id:first", obj).text();\r
389         this.rights = $("rights:first", obj).text();\r
390         this.authorname = $("author>name", obj).text();\r
391         this.authoremail = $("author>email", obj).text();\r
392 }\r
393 \r
394 /**\r
395  * 記事クラス\r
396  * @param {Object} obj entry 要素の DOM オブジェクト\r
397  */\r
398 function Entry(obj) {\r
399         this.id = $("id:first", obj).text();\r
400         this.title = $("title:first", obj).text();\r
401         this.summary = $("summary:first", obj).text();\r
402         this.published = $("published:first", obj).text();\r
403         this.updated = $("updated:first", obj).text();\r
404         this.link = $("link:first", obj).attr("href");\r
405         this.content = $("content:first", obj).text();\r
406 \r
407         var categoryList = [];\r
408         var categories = $("category", obj);\r
409         var tempCategory = {};\r
410         for (var i = 0; i < categories.length; i++) {\r
411                 tempCategory = {\r
412                         "term" : categories.eq(i).attr("term"),\r
413                         "label" : categories.eq(i).attr("label")\r
414                 };\r
415                 categoryList.push(tempCategory);\r
416         }\r
417         this.category = categoryList;\r
418 \r
419         if (inputValidateMode == 1) {\r
420                 this.content = this.content.replace(/[\r\n]|\r\n/g, "");\r
421                 this.content = this.content.replace(/<br[ \/]*>/ig, "\n");\r
422                 this.content = this.content.replace(/^[ \t]*/mg, "");\r
423         }\r
424 }\r
425 \r
426 /**\r
427  * グローバル変数からXMLを生成し、返却します\r
428  * @param {FeedInfo} finfo\r
429  * @param {Entry[]} elist\r
430  */\r
431 function toXml(finfo, elist) {\r
432         var stringBuffer = [];\r
433 \r
434         stringBuffer.push('<?xml version="1.0" encoding="utf-8"?>');\r
435         stringBuffer.push('<feed xml:lang="ja-jp" xmlns="http://www.w3.org/2005/Atom">');\r
436         stringBuffer.push('');\r
437 \r
438         stringBuffer.push('<title type="text">' + finfo.title + '</title>');\r
439         stringBuffer.push('<subtitle type="text">' + finfo.subtitle + '</subtitle>');\r
440         stringBuffer.push('<link rel="self" type="application/atom+xml" href="' + finfo.self + '" />');\r
441         stringBuffer.push('<link rel="alternate" type="text/html" href="' + finfo.alternate + '" />');\r
442         stringBuffer.push('<updated>' + getDate() + '</updated>');\r
443         stringBuffer.push('<id>' + finfo.id + '</id>');\r
444         stringBuffer.push('<rights type="text">' + finfo.rights + '</rights>');\r
445         stringBuffer.push('<author>');\r
446         stringBuffer.push('    <name>' + finfo.authorname + '</name>');\r
447         stringBuffer.push('    <email>' + finfo.authoremail + '</email>');\r
448         stringBuffer.push('</author>');\r
449         stringBuffer.push('');\r
450 \r
451         for (var i = 0; i < elist.length; i++) {\r
452                 var temp_content;\r
453                 if (document.getElementById("feedblog_addcontentbr").checked) {\r
454                         temp_content = xmlAttrContentEscape(convertContent(elist[i].content));\r
455                 } else {\r
456                         temp_content = xmlAttrContentEscape(elist[i].content);\r
457                 }\r
458 \r
459                 stringBuffer.push('<entry>');\r
460                 stringBuffer.push('<id>' + elist[i].id + '</id>');\r
461                 stringBuffer.push('<title>' + elist[i].title + '</title>');\r
462                 stringBuffer.push('<summary>' + elist[i].summary + '</summary>');\r
463                 stringBuffer.push('<published>' + elist[i].published + '</published>');\r
464                 stringBuffer.push('<updated>' + elist[i].updated + '</updated>');\r
465                 stringBuffer.push('<link href="' + elist[i].link + '" />');\r
466                 stringBuffer.push('<content type="html">' + temp_content + '</content>');\r
467 \r
468                 for (var j = 0; j < elist[i].category.length; j++) {\r
469                         var tmpElist = elist[i].category[j];\r
470                         stringBuffer.push('<category term="' + tmpElist["term"] + '" label="' + tmpElist["label"] + '"/>');\r
471                 }\r
472 \r
473                 stringBuffer.push('</entry>');\r
474                 stringBuffer.push('');\r
475         }\r
476 \r
477         stringBuffer.push('</feed>');\r
478 \r
479         return stringBuffer.join("\n");\r
480 }\r
481 \r
482 /**\r
483  * <content>要素の変換を行います\r
484  * @param {String} content\r
485  */\r
486 function convertContent(content) {\r
487         if (document.getElementById("feedblog_addcontentbr").checked) {\r
488                 content = content.replace(/[\n\r]|\r\n/g, "<br>\n");\r
489         } else {\r
490                 content = content.replace(/<br>/ig, "\n");\r
491         }\r
492 \r
493         return content;\r
494 }\r
495 \r
496 /**\r
497  * XMLのエスケープを行う関数\r
498  * @param {String} str エスケープを行う文字列\r
499  */\r
500 function xmlAttrContentEscape(str) {\r
501         return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/^[ ]+/mg, "&nbsp;").replace(/^[\t]+/mg, "");\r
502 }\r
503 \r
504 /**\r
505  * XMLの逆エスケープを行う関数\r
506  * @param {String} str 逆エスケープを行う文字列\r
507  */\r
508 function xmlAttrContentUnescape(str) {\r
509         return str.replace(/^[\t]+/mg, "").replace(/^[ ]+/mg, "&nbsp;").replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");\r
510 }\r
511 \r
512 /**\r
513  * jQueryでのパネル開閉を制御します\r
514  * @param {String} id 開閉するオブジェクトのid\r
515  */\r
516 function closePanel(id) {\r
517         $("#" + id).slideToggle();\r
518 }\r
519 \r
520 /**\r
521  * エラー画面を表示します\r
522  */\r
523 function showError() {\r
524         alert("XMLファイルのローディング中にエラーが発生しました!");\r
525 }\r
526 \r
527 /**\r
528  * RFC3339形式の日時を出力します\r
529  */\r
530 function getDate() {\r
531         var dNow = new Date();\r
532         var sYear = dNow.getFullYear();\r
533         var sMonth = dNow.getMonth() + 1;\r
534         var sDate = dNow.getDate();\r
535         var sHour = dNow.getHours();\r
536         var sMinute = dNow.getMinutes();\r
537         var sSecond = dNow.getSeconds();\r
538 \r
539         // 10以下の時は頭に"0"を挿入\r
540         if (sMonth < 10)\r
541                 sMonth = "0" + sMonth;\r
542         if (sDate < 10)\r
543                 sDate = "0" + sDate;\r
544         if (sHour < 10)\r
545                 sHour = "0" + sHour;\r
546         if (sMinute < 10)\r
547                 sMinute = "0" + sMinute;\r
548         if (sSecond < 10)\r
549                 sSecond = "0" + sSecond;\r
550 \r
551         return sYear + "-" + sMonth + "-" + sDate + "T" + sHour + ":" + sMinute + ":" + sSecond + "+09:00";\r
552 }\r
553 \r
554 /**\r
555  * タグ情報一覧を返却する関数です\r
556  */\r
557 function getTags() {\r
558         var tagList = [];\r
559         var tagListHtml = $("*[name=tag]");\r
560         var tagTemp = {};\r
561         for (var i = 0; i < tagListHtml.length; i++) {\r
562                 // 各tag要素を取得して配列に格納\r
563                 if (tagListHtml.eq(i).val() != "") {\r
564                         tagTemp = {\r
565                                 "term" : tagListHtml.eq(i).val(),\r
566                                 "label" : tagListHtml.eq(i).find(":selected").text()\r
567                         };\r
568                         tagList.push(tagTemp);\r
569                 }\r
570         }\r
571 \r
572         return tagList;\r
573 }\r
574 \r
575 /**\r
576  * デフォルトのタグ一覧を取得する関数です\r
577  */\r
578 function getDefaultTags() {\r
579         // デフォルトのタグ一覧を取得\r
580         // $term1,$label1|$term2,$label2 ... で定義されている\r
581         var plainTagText = $("#feedblog_tagdefine").val();\r
582         var tagList = [];\r
583         var tagTemp = {};\r
584         // 値が空のタグを初期値として先頭に追加\r
585         tagList.push({\r
586                 "term" : "",\r
587                 "label" : "タグを選択してください"\r
588         });\r
589         for (var i = 0; i < plainTagText.split('|').length; i++) {\r
590                 // 各tag要素を取得して配列に格納\r
591                 tagTemp = {\r
592                         "term" : plainTagText.split('|')[i].split(',')[0],\r
593                         "label" : plainTagText.split('|')[i].split(',')[1]\r
594                 };\r
595                 tagList.push(tagTemp);\r
596         }\r
597 \r
598         return tagList;\r
599 }\r
600 \r
601 /**\r
602  * HTMLにタグ選択用のセレクトボックスを追加します\r
603  */\r
604 function addTagSelectBox() {\r
605         var tagList = getDefaultTags();\r
606         var addHtml = [];\r
607 \r
608         addHtml.push('<select name="tag">');\r
609         for (var i = 0; i < tagList.length; i++) {\r
610                 addHtml.push('<option value="' + tagList[i]["term"] + '">' + tagList[i]["label"] + '</option>');\r
611         }\r
612         addHtml.push('</select>');\r
613 \r
614         $("#entry_category").append(addHtml.join('') + "<br>");\r
615 }\r
616 \r
617 /**\r
618  * 現在のカテゴリーオブジェクトに従いセレクトボックスを追加します\r
619  */\r
620 function addTagSelectBoxFromCategory(categoryList) {\r
621         $("#entry_category").html("");\r
622         for (var j = 0; j < categoryList.length; j++) {\r
623                 // 選択対象を取得\r
624                 var selectedTagTerm = categoryList[j]["term"];\r
625                 var selectedTagLabel = categoryList[j]["label"];\r
626                 var selectedTagSetFlag = false;\r
627 \r
628                 var tagList = getDefaultTags();\r
629                 var addHtml = [];\r
630                 addHtml.push('<select name="tag">');\r
631                 for (var i = 0; i < tagList.length; i++) {\r
632                         if (tagList[i]["term"] == selectedTagTerm && tagList[i]["label"] == selectedTagLabel) {\r
633                                 addHtml.push('<option value="' + tagList[i]["term"] + '" selected="selected">' + tagList[i]["label"] + '</option>');\r
634                                 selectedTagSetFlag = true;\r
635                         } else {\r
636                                 addHtml.push('<option value="' + tagList[i]["term"] + '">' + tagList[i]["label"] + '</option>');\r
637                         }\r
638                 }\r
639 \r
640                 if (!selectedTagSetFlag) {\r
641                         addHtml.push('<option value="' + selectedTagTerm + '" selected="selected">' + selectedTagLabel + '</option>');\r
642                 }\r
643 \r
644                 addHtml.push('</select>');\r
645                 $("#entry_category").append(addHtml.join('') + "<br>");\r
646         }\r
647 }\r