]> gitweb @ CieloNegro.org - Rakka.git/blob - js/editPage.js
e4483a1e3520104e5372401ae8f6f12a13dfd489
[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: "text", disabled: true});
233         var btnSelectFile
234             = $.INPUT({type: "button", value: "Select File"});
235
236         $(btnSelectFile).click(function () {
237                                    var path = Rakka.selectFile("Select a binary file to upload", "open");
238                                    if (path != null) {
239                                        fldUploadFile.value = path;
240                                        makeDirty();
241                                    }
242                                });
243
244         var fldRedirect
245             = $.INPUT({type: "text", value: (defaultType == "redirect" ? source : "")});
246
247         $(fldRedirect).change(makeDirty);
248
249         var trContent
250             = $.TR({},
251                    $.TH({}),
252                    $.TD({})
253                   );
254
255         var btnPreview
256             = $.INPUT({type: "button", value: "Preview page"});
257
258         $(btnPreview).click(function () {
259             if (btnTypeRakka.checked) {
260                 previewRakkaPage(
261                     fldPageName.value, fldRakkaSource.value);
262             }
263             else if (btnTypeBinary.checked) {
264                 if (fldUploadFile.value != "") {
265                     previewBinaryPage(
266                         fldPageName.value, fldUploadFile.value);
267                 }
268             }
269         });
270
271         var btnSubmit
272             = $.INPUT({type: "button", value: "Submit page"});
273
274         $(btnSubmit).click(function () {
275             if (btnTypeRakka.checked) {
276                 submitTextPage(
277                     pageName,
278                     oldRevision,
279                     fldPageName.value,
280                     chkIsLocked.checked,
281                     "text/x-rakka",
282                     $(selPageLang).val(),
283                     otherLangs,
284                     fldSummary.value,
285                     fldRakkaSource.value);
286             }
287             else if (btnTypeCSS.checked) {
288                 submitTextPage(
289                     pageName,
290                     oldRevision,
291                     fldPageName.value,
292                     chkIsLocked.checked,
293                     "text/css",
294                     $(selPageLang).val(),
295                     otherLangs,
296                     fldSummary.value,
297                     fldCSSSource.value);
298             }
299             else if (btnTypeJS.checked) {
300                 submitTextPage(
301                     pageName,
302                     oldRevision,
303                     fldPageName.value,
304                     chkIsLocked.checked,
305                     "text/javascript",
306                     $(selPageLang).val(),
307                     otherLangs,
308                     fldSummary.value,
309                     fldJSSource.value);
310             }
311             else if (btnTypeBinary.checked) {
312                 if (fldUploadFile.value != "") {
313                     submitBinaryPage(
314                         pageName,
315                         oldRevision,
316                         fldPageName.value,
317                         chkIsLocked.checked,
318                         $(selPageLang).val(),
319                         otherLangs,
320                         fldSummary.value,
321                         fldUploadFile.value);
322                 }
323             }
324             else if (btnTypeRedirect.checked) {
325                 submitRedirection(
326                     pageName,
327                     oldRevision,
328                     fldPageName.value,
329                     chkIsLocked.checked,
330                     fldRedirect.value);
331             }
332         });
333
334         var btnDelete
335             = $.INPUT({type: "button", value: "Delete this page"});
336
337         $(btnDelete).click(function () {
338             if (window.confirm("Do you really want to delete this page?")) {
339                 deletePage(pageName);
340             }
341         });
342
343         var btnCancel
344             = $.INPUT({type: "button", value: "Cancel editing"});
345
346         $(btnCancel).click(function () {
347             if (isDirty) {
348                 if (window.confirm("Do you really want to discard changes?")) {
349                     Rakka.restoreScreen();
350                 }
351             }
352             else {
353                 Rakka.restoreScreen();
354             }
355         });
356
357         var updateTRContent = function () {
358             if (btnTypeRakka.checked) {
359                 $(trPageLang).show();
360                 $(trOtherLangs).show();
361                 $(trSummary).show();
362                 $(trContent).find("th").text("Wiki source");
363                 $(trContent).find("td").empty().append(fldRakkaSource);
364                 $(btnPreview).show();
365             }
366             else if (btnTypeCSS.checked) {
367                 $(trPageLang).show();
368                 $(trOtherLangs).show();
369                 $(trSummary).show();
370                 $(trContent).find("th").text("CSS source");
371                 $(trContent).find("td").empty().append(fldCSSSource);
372                 $(btnPreview).hide();
373             }
374             else if (btnTypeJS.checked) {
375                 $(trPageLang).show();
376                 $(trOtherLangs).show();
377                 $(trSummary).show();
378                 $(trContent).find("th").text("JavaScript source");
379                 $(trContent).find("td").empty().append(fldJSSource);
380                 $(btnPreview).hide();
381             }
382             else if (btnTypeBinary.checked) {
383                 $(trPageLang).show();
384                 $(trOtherLangs).show();
385                 $(trSummary).show();
386                 $(trContent).find("th").text("File");
387                 $(trContent).find("td").empty().append(fldUploadFile).append(btnSelectFile);
388                 $(btnPreview).show();
389             }
390             else if (btnTypeRedirect.checked) {
391                 $(trPageLang).hide();
392                 $(trOtherLangs).hide();
393                 $(trSummary).hide();
394                 $(trContent).find("th").text("Destination Page");
395                 $(trContent).find("td").empty().append(fldRedirect);
396                 $(btnPreview).hide();
397             }
398         };
399         $(btnTypeRakka   ).change(updateTRContent);
400         $(btnTypeCSS     ).change(updateTRContent);
401         $(btnTypeJS      ).change(updateTRContent);
402         $(btnTypeBinary  ).change(updateTRContent);
403         $(btnTypeRedirect).change(updateTRContent);
404         updateTRContent();
405
406         var pageEditor
407             = $.TABLE({className: "pageEditor"},
408                       $.TBODY({},
409                               $.TR({},
410                                    $.TH({}, "Page name"),
411                                    $.TD({}, fldPageName)
412                                   ),
413                               trIsLocked,
414                               $.TR({},
415                                    $.TH({}, "Page type"),
416                                    $.TD({},
417                                         $.UL({},
418                                              $.LI({},
419                                                   $.LABEL({},
420                                                           btnTypeRakka,
421                                                           "Wiki page"
422                                                          )
423                                                  ),
424                                              $.LI({},
425                                                   $.LABEL({},
426                                                           btnTypeCSS,
427                                                           "Style sheet"
428                                                          )
429                                                  ),
430                                              $.LI({},
431                                                   $.LABEL({},
432                                                           btnTypeJS,
433                                                           "JavaScript"
434                                                          )
435                                                  ),
436                                              $.LI({},
437                                                   $.LABEL({},
438                                                           btnTypeBinary,
439                                                           "Binary file"
440                                                          )
441                                                  ),
442                                              $.LI({},
443                                                   $.LABEL({},
444                                                           btnTypeRedirect,
445                                                           "Redirection"
446                                                          )
447                                                  )
448                                             )
449                                        )
450                                   ),
451                               trPageLang,
452                               trOtherLangs,
453                               trSummary,
454                               trContent,
455                               $.TR({},
456                                    $.TH({}),
457                                    $.TD({}, btnPreview, btnSubmit, btnDelete, btnCancel)
458                                   )
459                              )
460                      );
461
462         var validate = function () {
463             var isValid = (function () {
464                 if (fldPageName.value.match(Rakka.rePageName) == null) {
465                     return false;
466                 }
467
468                 if (btnTypeRedirect.checked) {
469                     if (fldRedirect.value.match(Rakka.rePageName) == null) {
470                         return false;
471                     }
472                 }
473                 else {
474                     for (var tag in otherLangs) {
475                         if (otherLangs[tag].match(Rakka.rePageName) == null) {
476                             return false;
477                         }
478                     }
479
480                     if (btnTypeBinary.checked) {
481                         if (fldUploadFile.value == "") {
482                             return false;
483                         }
484                     }
485                 }
486
487                 return true;
488             })();
489
490             $(btnSubmit).attr({disabled: (isValid ? "" : "disabled")});
491         };
492         $(fldPageName)
493             .add(btnTypeRakka)
494             .add(btnTypeCSS)
495             .add(btnTypeJS)
496             .add(btnTypeBinary)
497             .add(btnTypeRedirect)
498             .add($(trOtherLangs).find("input"))
499             .add(fldUploadFile)
500             .add(fldRedirect)
501             .change(validate)
502             .keyup(validate);
503         validate();
504
505         if (oldRevision == null || oldRevision == 0) {
506             // 削除不可
507             $(btnDelete).hide();
508         }
509
510         $area.append(pageEditor);
511
512         if (!Rakka.isLoggedIn() || Rakka.isGlobalLocked) {
513             $(trIsLocked).hide();
514         }
515     };
516
517     var previewRakkaPage = function (pageName, source) {
518         Rakka.displayWaitingMessage("Loading... please wait.");
519
520         var url = Rakka.baseURI + "render/" + encodeURI(pageName);
521         $.ajax({
522             type       : "POST",
523             url        : url,
524             contentType: "text/x-rakka",
525             data       : source,
526             processData: false,
527             success    : function (resultDoc) {
528                 Rakka.hideWaitingMessage();
529                 showPreview(resultDoc);
530             },
531             error      : function (req) {
532                 Rakka.hideWaitingMessage();
533                 alert("Error: " + req.status + " " + req.statusText);
534             }
535         });
536     };
537
538     var previewBinaryPage = function (pageName, path) {
539         Rakka.displayWaitingMessage("Loading... please wait.");
540
541         /* Firefox でバイナリを送らうとすると 0x00 の位置で切れてしまふ。*/
542         var bin = Rakka.loadLocalBinaryFile(path);
543         var url = Rakka.baseURI + "render/" + encodeURI(pageName);
544         $.ajax({
545             type       : "POST",
546             url        : url,
547             contentType: "application/x-rakka-base64-stream",
548             data       : Rakka.encodeBase64(bin),
549             processData: false,
550             success    : function (resultDoc) {
551                 Rakka.hideWaitingMessage();
552                 showPreview(resultDoc);
553             },
554             error      : function (req) {
555                 Rakka.hideWaitingMessage();
556                 alert("Error: " + req.status + " " + req.statusText);
557             }
558         });
559     };
560
561     var showPreview = function (doc) {
562         $previewArea.empty();
563
564         $previewHeader.show();
565         $previewArea.show();
566
567         var root  = doc.documentElement;
568         var child = root.firstChild;
569         do {
570             if (child.nodeType == 1) {
571                 // 要素だったので複製
572                 $previewArea.append(child.cloneNode(true));
573             }
574         } while (child = child.nextSibling);
575
576         Rakka.scrollToTopLeft();
577     };
578
579     var submitTextPage
580       = function (pageName, oldRevision, givenPageName, isLocked, mimeType, lang, otherLangs, summary, text) {
581          var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
582          var doc  = document.implementation.createDocument(NS, "page", null);
583          var page = doc.documentElement;
584
585         if (oldRevision != null) {
586             // ページ書換時
587             var updateInfo = doc.createElementNS(NS, "updateInfo");
588             updateInfo.setAttribute("oldRevision", oldRevision);
589
590             if (pageName != givenPageName) {
591                 var move = doc.createElementNS(NS, "move");
592                 move.setAttribute("from", pageName);
593                 updateInfo.appendChild(move);
594             }
595
596             page.appendChild(updateInfo);
597         }
598
599         page.setAttribute("isLocked", isLocked ? "yes" : "no");
600         page.setAttribute("type", mimeType);
601
602         if (lang != null && lang != "") {
603             page.setAttribute("lang", lang);
604         }
605
606         if (summary != null && summary != "") {
607             var s = doc.createElementNS(NS, "summary");
608             s.appendChild(
609                 doc.createTextNode(summary));
610             page.appendChild(s);
611         }
612
613         var oLang = doc.createElementNS(NS, "otherLang");
614         for (var tag in otherLangs) {
615             var link = doc.createElementNS(NS, "link");
616             link.setAttribute("lang", tag);
617             link.setAttribute("page", otherLangs[tag]);
618             oLang.appendChild(link);
619         }
620         page.appendChild(oLang);
621
622         var textData = doc.createElementNS(NS, "textData");
623         textData.appendChild(
624             doc.createTextNode(text));
625
626         page.appendChild(textData);
627
628         Rakka.displayWaitingMessage("Submitting... please wait.");
629
630         var url = Rakka.baseURI + encodeURI(givenPageName);
631         $.ajax({
632             type       : "PUT",
633             url        : url,
634             contentType: "text/xml",
635             data       : doc,
636             processData: false,
637             beforeSend : function (req) {
638                 Rakka.setAuthorization(req);
639             },
640             success    : function () {
641                 window.location.replace(url);
642             },
643             error      : function (req) {
644                 Rakka.hideWaitingMessage();
645
646                 var $area = Rakka.switchScreen();
647                 $area.text("Error: " + req.status + " " + req.statusText);
648             }
649         });
650     };
651
652     var submitBinaryPage = function (pageName, oldRevision, givenPageName, isLocked, lang, otherLangs, summary, path) {
653         var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
654         var doc  = document.implementation.createDocument(NS, "page", null);
655         var page = doc.documentElement;
656
657         if (oldRevision != null) {
658             // ページ書換時
659             var updateInfo = doc.createElementNS(NS, "updateInfo");
660             updateInfo.setAttribute("oldRevision", oldRevision);
661
662             if (pageName != givenPageName) {
663                 var move = doc.createElementNS(NS, "move");
664                 move.setAttribute("from", pageName);
665                 updateInfo.appendChild(move);
666             }
667
668             page.appendChild(updateInfo);
669         }
670
671         page.setAttribute("isLocked", isLocked ? "yes" : "no");
672         page.setAttribute("type", "");
673
674         if (lang != null && lang != "") {
675             page.setAttribute("lang", lang);
676         }
677
678         if (summary != null) {
679             var s = doc.createElementNS(NS, "summary");
680             s.appendChild(
681                 doc.createTextNode(summary));
682             page.appendChild(s);
683         }
684
685         var oLang = doc.createElementNS(NS, "otherLang");
686         for (var tag in otherLangs) {
687             var link = doc.createElementNS(NS, "link");
688             link.setAttribute("lang", tag);
689             link.setAttribute("page", otherLangs[tag]);
690             oLang.appendChild(link);
691         }
692         page.appendChild(oLang);
693
694         var bin = Rakka.loadLocalBinaryFile(path);
695         var b64 = Rakka.encodeBase64(bin);
696
697         var binaryData = doc.createElementNS(NS, "binaryData");
698         binaryData.appendChild(
699             doc.createTextNode(b64));
700
701         page.appendChild(binaryData);
702
703         Rakka.displayWaitingMessage("Submitting... please wait.");
704
705         var url = Rakka.baseURI + encodeURI(givenPageName);
706         $.ajax({
707             type       : "PUT",
708             url        : url,
709             contentType: "text/xml",
710             data       : doc,
711             processData: false,
712             beforeSend : function (req) {
713                 Rakka.setAuthorization(req);
714             },
715             success    : function () {
716                 window.location.replace(url);
717             },
718             error      : function (req) {
719                 Rakka.hideWaitingMessage();
720
721                 var $area = Rakka.switchScreen();
722                 $area.text("Error: " + req.status + " " + req.statusText);
723             }
724         });
725     };
726
727     var submitRedirection = function (pageName, oldRevision, givenPageName, isLocked, destination) {
728         var NS   = "http://cielonegro.org/schema/Rakka/Page/1.0";
729         var doc  = document.implementation.createDocument(NS, "page", null);
730         var page = doc.documentElement;
731
732         if (oldRevision != null) {
733             // ページ書換時
734             var updateInfo = doc.createElementNS(NS, "updateInfo");
735             updateInfo.setAttribute("oldRevision", oldRevision);
736
737             if (pageName != givenPageName) {
738                 var move = doc.createElementNS(NS, "move");
739                 move.setAttribute("from", pageName);
740                 updateInfo.appendChild(move);
741             }
742
743             page.appendChild(updateInfo);
744         }
745
746         page.setAttribute("isLocked", isLocked ? "yes" : "no");
747         page.setAttribute("redirect", destination);
748
749         Rakka.displayWaitingMessage("Submitting... please wait.");
750
751         var url = Rakka.baseURI + encodeURI(givenPageName);
752         $.ajax({
753             type       : "PUT",
754             url        : url,
755             contentType: "text/xml",
756             data       : doc,
757             processData: false,
758             beforeSend : function (req) {
759                 Rakka.setAuthorization(req);
760             },
761             success    : function () {
762                 window.location.replace(url);
763             },
764             error      : function (req) {
765                 Rakka.hideWaitingMessage();
766
767                 var $area = Rakka.switchScreen();
768                 $area.text("Error: " + req.status + " " + req.statusText);
769             }
770         });
771     };
772
773     var deletePage = function (pageName) {
774         var url = Rakka.baseURI + encodeURI(pageName);
775         $.ajax({
776             type       : "DELETE",
777             url        : url,
778             beforeSend : function (req) {
779                 Rakka.setAuthorization(req);
780             },
781             success    : function () {
782                 window.location.replace(url);
783             },
784             error      : function (req) {
785                 Rakka.hideWaitingMessage();
786
787                 var $area = Rakka.switchScreen();
788                 $area.text("Error: " + req.status + " " + req.statusText);
789             }
790         });
791     };
792
793 })();