]> gitweb @ CieloNegro.org - Rakka.git/blob - js/editPage.js
Global JavaScript
[Rakka.git] / js / editPage.js
1 (function () {
2
3     var $previewHeader = null;
4     var $previewArea   = null;
5
6     Rakka.editPage = function (pageName) {
7         var $area = Rakka.switchScreen();
8
9         Rakka.displayWaitingMessage("Loading... please wait.");
10
11         // XML 版のページを取得する。
12         $.ajax({
13             url    : Rakka.baseURI + pageName + ".xml",
14             success: function (pageXml) {
15                 Rakka.hideWaitingMessage();
16
17                 if (pageXml.documentElement.tagName == "page") {
18                     var $page       = $(pageXml).find("page");
19                     var oldRevision = $page.attr("revision");
20                     var defaultType
21                         = $page.attr("isBinary") == "yes"             ? "binary"
22                         : $page.attr("type")     == "text/x-rakka"    ? "rakka"
23                         : $page.attr("type")     == "text/css"        ? "css"
24                         : $page.attr("type")     == "text/javascript" ? "js"
25                         : $page.attr("redirect") != null              ? "redirect"
26                         :                                               "unknown"
27                         ;
28                     var lang        = $page.attr("lang");
29                     var isLocked    = $page.attr("isLocked") == "yes";
30                     var otherLangs  = (function () {
31                         var obj = {};
32                         $page.find("otherLang > link").each(function () {
33                             obj[this.getAttribute("lang")] = this.getAttribute("page");
34                         });
35                         return obj;
36                     })();
37                     var source
38                         = $page.attr("redirect") != null ? $page.attr("redirect")
39                         : $page.find("textData").text()
40                         ;
41                     var summary     = $page.find("summary").text();
42
43                     displayPageEditor(pageName, oldRevision, defaultType, lang, isLocked, otherLangs, source, summary);
44                 }
45                 else {
46                     displayPageEditor(pageName, null, "rakka", null, false, {}, null, "");
47                 }
48             },
49             error  : function (req) {
50                 Rakka.hideWaitingMessage();
51
52                 if (req.status == 404) {
53                     displayPageEditor(pageName, null, "rakka", null, false, {}, null, "");
54                 }
55                 else {
56                     $area.text("Error: " + req.status + " " + req.statusText);
57                 }
58             }
59         });
60     };
61
62     Rakka.newPage = function () {
63         displayPageEditor("", null, "rakka", null, false, {}, null, "");
64     };
65
66     var displayPageEditor = function (pageName, oldRevision, defaultType, lang, isLocked, otherLangs, source, summary) {
67         var $area = Rakka.switchScreen();
68
69         $previewHeader = $( $.H1({}, "Preview") );
70         $area.append($previewHeader);
71         $previewHeader.hide();
72
73         $previewArea = $( $.DIV({className: "preview"}) );
74         $area.append($previewArea);
75         $previewArea.hide();
76
77         $area.append($.H1({}, pageName == "" ? "Create page" : "Edit page"));
78
79         var isDirty = null;
80         var makeDirty = function () {
81             isDirty = true;
82         };
83
84         var fldPageName
85             = $.INPUT({type : "text", value: pageName});
86
87         $(fldPageName).change(makeDirty);
88
89         var chkIsLocked
90             = $.INPUT({type    : "checkbox",
91                        checked : (isLocked ? "checked" : "")});
92
93         $(chkIsLocked).change(makeDirty);
94
95         var trIsLocked
96             = $.TR({},
97                    $.TH({}, "Page lock"),
98                    $.TD({},
99                         $.LABEL({},
100                                 chkIsLocked,
101                                 "Disallow anonymous users to edit or delete this page")));
102
103         var btnTypeRakka
104             = $.INPUT({type   : "radio",
105                        name   : "type",
106                        checked: (defaultType == "rakka"    ? "checked" : "")});
107
108         $(btnTypeRakka).change(makeDirty);
109
110         var btnTypeCSS
111             = $.INPUT({type   : "radio",
112                        name   : "type",
113                        checked: (defaultType == "css"      ? "checked" : "")});
114
115         $(btnTypeCSS).change(makeDirty);
116
117         var btnTypeJS
118             = $.INPUT({type   : "radio",
119                        name   : "type",
120                        checked: (defaultType == "js"       ? "checked" : "")});
121         $(btnTypeJS).change(makeDirty);
122
123         var btnTypeBinary
124             = $.INPUT({type   : "radio",
125                        name   : "type",
126                        checked: (defaultType == "binary"   ? "checked" : "")});
127
128         $(btnTypeBinary).change(makeDirty);
129
130         var btnTypeRedirect
131             = $.INPUT({type   : "radio",
132                        name   : "type",
133                        checked: (defaultType == "redirect" ? "checked" : "")});
134
135         $(btnTypeRedirect).change(makeDirty);
136
137         var selPageLang
138             = $.SELECT({},
139                        $.OPTION({value: ""}, "(unspecified)"),
140                        (function () {
141                            var options = [];
142
143                            $.each(Rakka.getSystemConfig().languages, function (tag, name) {
144                                options.push(
145                                    $.OPTION({value: tag}, name));
146                            });
147
148                            return options;
149                        })());
150
151         $(selPageLang).change(makeDirty);
152
153         if (lang == null || lang == "") {
154             $(selPageLang).val($("html").attr("xml:lang"));
155         }
156         else {
157             $(selPageLang).val(lang);
158         }
159
160         var trPageLang
161             = $.TR({},
162                    $.TH({}, "Page language"),
163                    $.TD({}, selPageLang));
164
165         var trOtherLangs = (function () {
166             var options = [];
167
168             $.each(Rakka.getSystemConfig().languages, function (tag, name) {
169                 options.push(
170                     $.OPTION({value: tag}, name));
171             });
172
173             var selLang = $.SELECT({}, options);
174             var fldLink = $.INPUT({type: "text", className: "smallField"});
175
176             $(selLang).change(function () {
177                 var pageName = otherLangs[$(selLang).val()];
178                 $(fldLink).val(
179                     pageName == null ? "" : pageName
180                 );
181             }).trigger("change");
182
183             var onLinkChanged = function () {
184                 isDirty = true;
185
186                 var lang     = $(selLang).val();
187                 var pageName = $(this).val();
188
189                 if (pageName == "") {
190                     delete otherLangs[lang];
191                 }
192                 else {
193                     otherLangs[lang] = pageName;
194                 }
195             };
196             $(fldLink).change(onLinkChanged).keyup(onLinkChanged);
197
198             return $.TR({},
199                         $.TH({}, "Language links"),
200                         $.TD({}, selLang, fldLink));
201         })();
202
203         var fldSummary
204             = $.TEXTAREA({className: "summary"}, summary);
205
206         $(fldSummary).change(makeDirty);
207
208         var trSummary
209             = $.TR({},
210                    $.TH({}, "Summary"),
211                    $.TD({}, fldSummary));
212
213         var fldRakkaSource
214             = $.TEXTAREA({className: "source"},
215                          (defaultType == "rakka" && source != null ? source : ""));
216
217         $(fldRakkaSource).change(makeDirty);
218
219         var fldCSSSource
220             = $.TEXTAREA({className: "source"},
221                          (defaultType == "css"   && source != null ? source : ""));
222
223         $(fldCSSSource).change(makeDirty);
224
225         var fldJSSource
226             = $.TEXTAREA({className: "source"},
227                          (defaultType == "js"    && source != null ? source : ""));
228
229         $(fldJSSource).change(makeDirty);
230
231         var fldUploadFile
232             = $.INPUT({type: "file"});
233
234         $(fldUploadFile).change(makeDirty);
235
236         var fldRedirect
237             = $.INPUT({type: "text", value: (defaultType == "redirect" ? source : "")});
238
239         $(fldRedirect).change(makeDirty);
240
241         var trContent
242             = $.TR({},
243                    $.TH({}),
244                    $.TD({})
245                   );
246
247         var btnPreview
248             = $.INPUT({type: "button", value: "Preview page"});
249
250         $(btnPreview).click(function () {
251             if (btnTypeRakka.checked) {
252                 previewRakkaPage(
253                     fldPageName.value, fldRakkaSource.value);
254             }
255             else if (btnTypeBinary.checked) {
256                 if (fldUploadFile.value != "") {
257                     previewBinaryPage(
258                         fldPageName.value, fldUploadFile.value);
259                 }
260             }
261         });
262
263         var btnSubmit
264             = $.INPUT({type: "button", value: "Submit page"});
265
266         $(btnSubmit).click(function () {
267             if (btnTypeRakka.checked) {
268                 submitTextPage(
269                     pageName,
270                     oldRevision,
271                     fldPageName.value,
272                     chkIsLocked.checked,
273                     "text/x-rakka",
274                     $(selPageLang).val(),
275                     otherLangs,
276                     fldSummary.value,
277                     fldRakkaSource.value);
278             }
279             else if (btnTypeCSS.checked) {
280                 submitTextPage(
281                     pageName,
282                     oldRevision,
283                     fldPageName.value,
284                     chkIsLocked.checked,
285                     "text/css",
286                     $(selPageLang).val(),
287                     otherLangs,
288                     fldSummary.value,
289                     fldCSSSource.value);
290             }
291             else if (btnTypeJS.checked) {
292                 submitTextPage(
293                     pageName,
294                     oldRevision,
295                     fldPageName.value,
296                     chkIsLocked.checked,
297                     "text/javascript",
298                     $(selPageLang).val(),
299                     otherLangs,
300                     fldSummary.value,
301                     fldJSSource.value);
302             }
303             else if (btnTypeBinary.checked) {
304                 if (fldUploadFile.value != "") {
305                     submitBinaryPage(
306                         pageName,
307                         oldRevision,
308                         fldPageName.value,
309                         chkIsLocked.checked,
310                         $(selPageLang).val(),
311                         otherLangs,
312                         fldSummary.value,
313                         fldUploadFile.value);
314                 }
315             }
316             else if (btnTypeRedirect.checked) {
317                 submitRedirection(
318                     pageName,
319                     oldRevision,
320                     fldPageName.value,
321                     chkIsLocked.checked,
322                     fldRedirect.value);
323             }
324         });
325
326         var btnDelete
327             = $.INPUT({type: "button", value: "Delete this page"});
328
329         $(btnDelete).click(function () {
330             if (window.confirm("Do you really want to delete this page?")) {
331                 deletePage(pageName);
332             }
333         });
334
335         var btnCancel
336             = $.INPUT({type: "button", value: "Cancel editing"});
337
338         $(btnCancel).click(function () {
339             if (isDirty) {
340                 if (window.confirm("Do you really want to discard changes?")) {
341                     Rakka.restoreScreen();
342                 }
343             }
344             else {
345                 Rakka.restoreScreen();
346             }
347         });
348
349         var updateTRContent = function () {
350             if (btnTypeRakka.checked) {
351                 $(trPageLang).show();
352                 $(trOtherLangs).show();
353                 $(trSummary).show();
354                 $(trContent).find("th").text("Wiki source");
355                 $(trContent).find("td").empty().append(fldRakkaSource);
356                 $(btnPreview).show();
357             }
358             else if (btnTypeCSS.checked) {
359                 $(trPageLang).show();
360                 $(trOtherLangs).show();
361                 $(trSummary).show();
362                 $(trContent).find("th").text("CSS source");
363                 $(trContent).find("td").empty().append(fldCSSSource);
364                 $(btnPreview).hide();
365             }
366             else if (btnTypeJS.checked) {
367                 $(trPageLang).show();
368                 $(trOtherLangs).show();
369                 $(trSummary).show();
370                 $(trContent).find("th").text("JavaScript source");
371                 $(trContent).find("td").empty().append(fldJSSource);
372                 $(btnPreview).hide();
373             }
374             else if (btnTypeBinary.checked) {
375                 $(trPageLang).show();
376                 $(trOtherLangs).show();
377                 $(trSummary).show();
378                 $(trContent).find("th").text("File");
379                 $(trContent).find("td").empty().append(fldUploadFile);
380                 $(btnPreview).show();
381             }
382             else if (btnTypeRedirect.checked) {
383                 $(trPageLang).hide();
384                 $(trOtherLangs).hide();
385                 $(trSummary).hide();
386                 $(trContent).find("th").text("Destination Page");
387                 $(trContent).find("td").empty().append(fldRedirect);
388                 $(btnPreview).hide();
389             }
390         };
391         $(btnTypeRakka   ).change(updateTRContent);
392         $(btnTypeCSS     ).change(updateTRContent);
393         $(btnTypeJS      ).change(updateTRContent);
394         $(btnTypeBinary  ).change(updateTRContent);
395         $(btnTypeRedirect).change(updateTRContent);
396         updateTRContent();
397
398         var pageEditor
399             = $.TABLE({className: "pageEditor"},
400                       $.TBODY({},
401                               $.TR({},
402                                    $.TH({}, "Page name"),
403                                    $.TD({}, fldPageName)
404                                   ),
405                               trIsLocked,
406                               $.TR({},
407                                    $.TH({}, "Page type"),
408                                    $.TD({},
409                                         $.UL({},
410                                              $.LI({},
411                                                   $.LABEL({},
412                                                           btnTypeRakka,
413                                                           "Wiki page"
414                                                          )
415                                                  ),
416                                              $.LI({},
417                                                   $.LABEL({},
418                                                           btnTypeCSS,
419                                                           "Style sheet"
420                                                          )
421                                                  ),
422                                              $.LI({},
423                                                   $.LABEL({},
424                                                           btnTypeJS,
425                                                           "JavaScript"
426                                                          )
427                                                  ),
428                                              $.LI({},
429                                                   $.LABEL({},
430                                                           btnTypeBinary,
431                                                           "Binary file"
432                                                          )
433                                                  ),
434                                              $.LI({},
435                                                   $.LABEL({},
436                                                           btnTypeRedirect,
437                                                           "Redirection"
438                                                          )
439                                                  )
440                                             )
441                                        )
442                                   ),
443                               trPageLang,
444                               trOtherLangs,
445                               trSummary,
446                               trContent,
447                               $.TR({},
448                                    $.TH({}),
449                                    $.TD({}, btnPreview, btnSubmit, btnDelete, btnCancel)
450                                   )
451                              )
452                      );
453
454         var validate = function () {
455             var isValid = (function () {
456                 if (fldPageName.value.match(Rakka.rePageName) == null) {
457                     return false;
458                 }
459
460                 if (btnTypeRedirect.checked) {
461                     if (fldRedirect.value.match(Rakka.rePageName) == null) {
462                         return false;
463                     }
464                 }
465                 else {
466                     for (var tag in otherLangs) {
467                         if (otherLangs[tag].match(Rakka.rePageName) == null) {
468                             return false;
469                         }
470                     }
471
472                     if (btnTypeBinary.checked) {
473                         if (fldUploadFile.value == "") {
474                             return false;
475                         }
476                     }
477                 }
478
479                 return true;
480             })();
481
482             $(btnSubmit).attr({disabled: (isValid ? "" : "disabled")});
483         };
484         $(fldPageName)
485             .add(btnTypeRakka)
486             .add(btnTypeCSS)
487             .add(btnTypeJS)
488             .add(btnTypeBinary)
489             .add(btnTypeRedirect)
490             .add($(trOtherLangs).find("input"))
491             .add(fldUploadFile)
492             .add(fldRedirect)
493             .change(validate)
494             .keyup(validate);
495         validate();
496
497         if (oldRevision == null || oldRevision == 0) {
498             // 削除不可
499             $(btnDelete).hide();
500         }
501
502         $area.append(pageEditor);
503
504         if (!Rakka.isLoggedIn() || Rakka.isGlobalLocked) {
505             $(trIsLocked).hide();
506         }
507     };
508
509     var previewRakkaPage = function (pageName, source) {
510         Rakka.displayWaitingMessage("Loading... please wait.");
511
512         var url = Rakka.baseURI + "render/" + encodeURI(pageName);
513         $.ajax({
514             type       : "POST",
515             url        : url,
516             contentType: "text/x-rakka",
517             data       : source,
518             processData: false,
519             success    : function (resultDoc) {
520                 Rakka.hideWaitingMessage();
521                 showPreview(resultDoc);
522             },
523             error      : function (req) {
524                 Rakka.hideWaitingMessage();
525                 alert("Error: " + req.status + " " + req.statusText);
526             }
527         });
528     };
529
530     var previewBinaryPage = function (pageName, path) {
531         Rakka.displayWaitingMessage("Loading... please wait.");
532
533         /* Firefox でバイナリを送らうとすると 0x00 の位置で切れてしまふ。*/
534         var bin = Rakka.loadLocalBinaryFile(path);
535         var url = Rakka.baseURI + "render/" + encodeURI(pageName);
536         $.ajax({
537             type       : "POST",
538             url        : url,
539             contentType: "application/x-rakka-base64-stream",
540             data       : Rakka.encodeBase64(bin),
541             processData: false,
542             success    : function (resultDoc) {
543                 Rakka.hideWaitingMessage();
544                 showPreview(resultDoc);
545             },
546             error      : function (req) {
547                 Rakka.hideWaitingMessage();
548                 alert("Error: " + req.status + " " + req.statusText);
549             }
550         });
551     };
552
553     var showPreview = function (doc) {
554         $previewArea.empty();
555
556         $previewHeader.show();
557         $previewArea.show();
558
559         var root  = doc.documentElement;
560         var child = root.firstChild;
561         do {
562             if (child.nodeType == 1) {
563                 // 要素だったので複製
564                 $previewArea.append(child.cloneNode(true));
565             }
566         } while (child = child.nextSibling);
567
568         Rakka.scrollToTopLeft();
569     };
570
571     var submitTextPage
572       = function (pageName, oldRevision, givenPageName, isLocked, mimeType, lang, otherLangs, summary, text) {
573          var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
574          var doc  = document.implementation.createDocument(NS, "page", null);
575          var page = doc.documentElement;
576
577         if (oldRevision != null) {
578             // ページ書換時
579             var updateInfo = doc.createElementNS(NS, "updateInfo");
580             updateInfo.setAttribute("oldRevision", oldRevision);
581
582             if (pageName != givenPageName) {
583                 var move = doc.createElementNS(NS, "move");
584                 move.setAttribute("from", pageName);
585                 updateInfo.appendChild(move);
586             }
587
588             page.appendChild(updateInfo);
589         }
590
591         page.setAttribute("isLocked", isLocked ? "yes" : "no");
592         page.setAttribute("type", mimeType);
593
594         if (lang != null && lang != "") {
595             page.setAttribute("lang", lang);
596         }
597
598         if (summary != null && summary != "") {
599             var s = doc.createElementNS(NS, "summary");
600             s.appendChild(
601                 doc.createTextNode(summary));
602             page.appendChild(s);
603         }
604
605         var oLang = doc.createElementNS(NS, "otherLang");
606         for (var tag in otherLangs) {
607             var link = doc.createElementNS(NS, "link");
608             link.setAttribute("lang", tag);
609             link.setAttribute("page", otherLangs[tag]);
610             oLang.appendChild(link);
611         }
612         page.appendChild(oLang);
613
614         var textData = doc.createElementNS(NS, "textData");
615         textData.appendChild(
616             doc.createTextNode(text));
617
618         page.appendChild(textData);
619
620         Rakka.displayWaitingMessage("Submitting... please wait.");
621
622         var url = Rakka.baseURI + encodeURI(givenPageName);
623         $.ajax({
624             type       : "PUT",
625             url        : url,
626             contentType: "text/xml",
627             data       : doc,
628             processData: false,
629             beforeSend : function (req) {
630                 Rakka.setAuthorization(req);
631             },
632             success    : function () {
633                 window.location.replace(url);
634             },
635             error      : function (req) {
636                 Rakka.hideWaitingMessage();
637
638                 var $area = Rakka.switchScreen();
639                 $area.text("Error: " + req.status + " " + req.statusText);
640             }
641         });
642     };
643
644     var submitBinaryPage = function (pageName, oldRevision, givenPageName, isLocked, lang, otherLangs, summary, path) {
645         var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
646         var doc  = document.implementation.createDocument(NS, "page", null);
647         var page = doc.documentElement;
648
649         if (oldRevision != null) {
650             // ページ書換時
651             var updateInfo = doc.createElementNS(NS, "updateInfo");
652             updateInfo.setAttribute("oldRevision", oldRevision);
653
654             if (pageName != givenPageName) {
655                 var move = doc.createElementNS(NS, "move");
656                 move.setAttribute("from", pageName);
657                 updateInfo.appendChild(move);
658             }
659
660             page.appendChild(updateInfo);
661         }
662
663         page.setAttribute("isLocked", isLocked ? "yes" : "no");
664         page.setAttribute("type", "");
665
666         if (lang != null && lang != "") {
667             page.setAttribute("lang", lang);
668         }
669
670         if (summary != null) {
671             var s = doc.createElementNS(NS, "summary");
672             s.appendChild(
673                 doc.createTextNode(summary));
674             page.appendChild(s);
675         }
676
677         var oLang = doc.createElementNS(NS, "otherLang");
678         for (var tag in otherLangs) {
679             var link = doc.createElementNS(NS, "link");
680             link.setAttribute("lang", tag);
681             link.setAttribute("page", otherLangs[tag]);
682             oLang.appendChild(link);
683         }
684         page.appendChild(oLang);
685
686         var bin = Rakka.loadLocalBinaryFile(path);
687         var b64 = Rakka.encodeBase64(bin);
688
689         var binaryData = doc.createElementNS(NS, "binaryData");
690         binaryData.appendChild(
691             doc.createTextNode(b64));
692
693         page.appendChild(binaryData);
694
695         Rakka.displayWaitingMessage("Submitting... please wait.");
696
697         var url = Rakka.baseURI + encodeURI(givenPageName);
698         $.ajax({
699             type       : "PUT",
700             url        : url,
701             contentType: "text/xml",
702             data       : doc,
703             processData: false,
704             beforeSend : function (req) {
705                 Rakka.setAuthorization(req);
706             },
707             success    : function () {
708                 window.location.replace(url);
709             },
710             error      : function (req) {
711                 Rakka.hideWaitingMessage();
712
713                 var $area = Rakka.switchScreen();
714                 $area.text("Error: " + req.status + " " + req.statusText);
715             }
716         });
717     };
718
719     var submitRedirection = function (pageName, oldRevision, givenPageName, isLocked, destination) {
720         var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
721         var doc  = document.implementation.createDocument(NS, "page", null);
722         var page = doc.documentElement;
723
724         if (oldRevision != null) {
725             // ページ書換時
726             var updateInfo = doc.createElementNS(NS, "updateInfo");
727             updateInfo.setAttribute("oldRevision", oldRevision);
728
729             if (pageName != givenPageName) {
730                 var move = doc.createElementNS(NS, "move");
731                 move.setAttribute("from", pageName);
732                 updateInfo.appendChild(move);
733             }
734
735             page.appendChild(updateInfo);
736         }
737
738         page.setAttribute("isLocked", isLocked ? "yes" : "no");
739         page.setAttribute("redirect", destination);
740
741         Rakka.displayWaitingMessage("Submitting... please wait.");
742
743         var url = Rakka.baseURI + encodeURI(givenPageName);
744         $.ajax({
745             type       : "PUT",
746             url        : url,
747             contentType: "text/xml",
748             data       : doc,
749             processData: false,
750             beforeSend : function (req) {
751                 Rakka.setAuthorization(req);
752             },
753             success    : function () {
754                 window.location.replace(url);
755             },
756             error      : function (req) {
757                 Rakka.hideWaitingMessage();
758
759                 var $area = Rakka.switchScreen();
760                 $area.text("Error: " + req.status + " " + req.statusText);
761             }
762         });
763     };
764
765     var deletePage = function (pageName) {
766         var url = Rakka.baseURI + encodeURI(pageName);
767         $.ajax({
768             type       : "DELETE",
769             url        : url,
770             beforeSend : function (req) {
771                 Rakka.setAuthorization(req);
772             },
773             success    : function () {
774                 window.location.replace(url);
775             },
776             error      : function (req) {
777                 Rakka.hideWaitingMessage();
778
779                 var $area = Rakka.switchScreen();
780                 $area.text("Error: " + req.status + " " + req.statusText);
781             }
782         });
783     };
784
785 })();