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