X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=js%2FeditPage.js;h=a9813d2d3fa8bdc21bfaa6359b7a634ac93a0a49;hb=b82b7cb90c3c3666ada1e2a2777c902850f831a2;hp=5297e057726aee809148a390a8f6291c3f3ba286;hpb=ee28059eadd401e5f9256df590bbb7491f952685;p=Rakka.git diff --git a/js/editPage.js b/js/editPage.js index 5297e05..a9813d2 100644 --- a/js/editPage.js +++ b/js/editPage.js @@ -1,150 +1,785 @@ -Rakka.editPage = function (baseURI, pageName) { - var $body = $("div.body"); - - $body.text("Loading... please wait."); - - // XML 版のページを取得する。 - $.ajax({ - url : baseURI + pageName + ".xml", - success: function (pageXml) { - var $page = $(pageXml).find("page"); - var oldRevision = $page.attr("revision"); - var defaultType = $page.attr("isBinary") == "yes" ? "binary" - : $page.attr("type") == "text/x-rakka" ? "rakka" - : $page.attr("type") == "text/css" ? "css" - : "unknown" - ; - var source = $page.find("source").text(); - Rakka.displayPageEditor($body, pageName, oldRevision, defaultType, source); - }, - error : function (req) { - if (req.status == 404) { - Rakka.displayPageEditor($body, pageName, null, "rakka", null); - } - else { - $body.text("Error: " + req.status + " " + req.statusText); - } - } +(function () { + + var $previewHeader = null; + var $previewArea = null; + + Rakka.editPage = function (pageName) { + var $area = Rakka.switchScreen(); + + Rakka.displayWaitingMessage("Loading... please wait."); + + // XML 版のページを取得する。 + $.ajax({ + url : Rakka.baseURI + pageName + ".xml", + success: function (pageXml) { + Rakka.hideWaitingMessage(); + + if (pageXml.documentElement.tagName == "page") { + var $page = $(pageXml).find("page"); + var oldRevision = $page.attr("revision"); + var defaultType + = $page.attr("isBinary") == "yes" ? "binary" + : $page.attr("type") == "text/x-rakka" ? "rakka" + : $page.attr("type") == "text/css" ? "css" + : $page.attr("type") == "text/javascript" ? "js" + : $page.attr("redirect") != null ? "redirect" + : "unknown" + ; + var lang = $page.attr("lang"); + var isLocked = $page.attr("isLocked") == "yes"; + var otherLangs = (function () { + var obj = {}; + $page.find("otherLang > link").each(function () { + obj[this.getAttribute("lang")] = this.getAttribute("page"); + }); + return obj; + })(); + var source + = $page.attr("redirect") != null ? $page.attr("redirect") + : $page.find("textData").text() + ; + var summary = $page.find("summary").text(); + + displayPageEditor(pageName, oldRevision, defaultType, lang, isLocked, otherLangs, source, summary); + } + else { + displayPageEditor(pageName, null, "rakka", null, false, {}, null, ""); + } + }, + error : function (req) { + Rakka.hideWaitingMessage(); + + if (req.status == 404) { + displayPageEditor(pageName, null, "rakka", null, false, {}, null, ""); + } + else { + $area.text("Error: " + req.status + " " + req.statusText); + } + } }); -}; + }; + + Rakka.newPage = function () { + displayPageEditor("", null, "rakka", null, false, {}, null, ""); + }; + + var displayPageEditor = function (pageName, oldRevision, defaultType, lang, isLocked, otherLangs, source, summary) { + var $area = Rakka.switchScreen(); + + $previewHeader = $( $.H1({}, "Preview") ); + $area.append($previewHeader); + $previewHeader.hide(); + + $previewArea = $( $.DIV({className: "preview"}) ); + $area.append($previewArea); + $previewArea.hide(); + + $area.append($.H1({}, pageName == "" ? "Create page" : "Edit page")); + + var isDirty = null; + var makeDirty = function () { + isDirty = true; + }; + + var fldPageName + = $.INPUT({type : "text", value: pageName}); + + $(fldPageName).change(makeDirty); -Rakka.displayPageEditor = function ($place, pageName, oldRevision, defaultType, source) { - $place.empty(); + var chkIsLocked + = $.INPUT({type : "checkbox", + checked : (isLocked ? "checked" : "")}); - $place.append($.H1({}, "Edit page")); + $(chkIsLocked).change(makeDirty); - var fldPageName - = $.INPUT({type : "text", value: pageName}); + var trIsLocked + = $.TR({}, + $.TH({}, "Page lock"), + $.TD({}, + $.LABEL({}, + chkIsLocked, + "Disallow anonymous users to edit or delete this page"))); - var btnTypeRakka - = $.INPUT({type : "radio", - name : "type", - checked: (defaultType == "rakka" ? "checked" : "")}); + var btnTypeRakka + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "rakka" ? "checked" : "")}); - var btnTypeCSS - = $.INPUT({type : "radio", - name : "type", - checked: (defaultType == "css" ? "checked" : "")}); + $(btnTypeRakka).change(makeDirty); - var btnTypeBinary - = $.INPUT({type : "radio", - name : "type", - checked: (defaultType == "binary" ? "checked" : "")}); - + var btnTypeCSS + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "css" ? "checked" : "")}); - var fldRakkaSource - = $.TEXTAREA({}, (defaultType == "rakka" && source != null ? source : "")); + $(btnTypeCSS).change(makeDirty); - var fldCSSSource - = $.TEXTAREA({}, (defaultType == "css" && source != null ? source : "")); + var btnTypeJS + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "js" ? "checked" : "")}); + $(btnTypeJS).change(makeDirty); - var fldUploadFile - = $.INPUT({type: "file"}); + var btnTypeBinary + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "binary" ? "checked" : "")}); - var trContent - = $.TR({}, - $.TH({}), - $.TD({}) - ); + $(btnTypeBinary).change(makeDirty); - var btnPreview - = $.INPUT({type: "button", value: "Preview page"}); + var btnTypeRedirect + = $.INPUT({type : "radio", + name : "type", + checked: (defaultType == "redirect" ? "checked" : "")}); - var btnSubmit - = $.INPUT({type: "button", value: "Submit page"}); + $(btnTypeRedirect).change(makeDirty); - var btnDelete - = $.INPUT({type: "button", value: "Delete this page"}); - - var updateTRContent = function () { - if (btnTypeRakka.checked) { - $(trContent).find("th").text("Wiki source"); - $(trContent).find("td").empty().append(fldRakkaSource); - $(trContent).show(); + var selPageLang + = $.SELECT({}, + $.OPTION({value: ""}, "(unspecified)"), + (function () { + var options = []; + + $.each(Rakka.getSystemConfig().languages, function (tag, name) { + options.push( + $.OPTION({value: tag}, name)); + }); + + return options; + })()); + + $(selPageLang).change(makeDirty); + + if (lang == null || lang == "") { + $(selPageLang).val($("html").attr("xml:lang")); } - else if (btnTypeCSS.checked) { - $(trContent).find("th").text("CSS source"); - $(trContent).find("td").empty().append(fldCSSSource); - $(trContent).show(); + else { + $(selPageLang).val(lang); } - else if (btnTypeBinary.checked) { - $(trContent).find("th").text("File"); - $(trContent).find("td").empty().append(fldUploadFile); - $(trContent).show(); + + var trPageLang + = $.TR({}, + $.TH({}, "Page language"), + $.TD({}, selPageLang)); + + var trOtherLangs = (function () { + var options = []; + + $.each(Rakka.getSystemConfig().languages, function (tag, name) { + options.push( + $.OPTION({value: tag}, name)); + }); + + var selLang = $.SELECT({}, options); + var fldLink = $.INPUT({type: "text", className: "smallField"}); + + $(selLang).change(function () { + var pageName = otherLangs[$(selLang).val()]; + $(fldLink).val( + pageName == null ? "" : pageName + ); + }).trigger("change"); + + var onLinkChanged = function () { + isDirty = true; + + var lang = $(selLang).val(); + var pageName = $(this).val(); + + if (pageName == "") { + delete otherLangs[lang]; + } + else { + otherLangs[lang] = pageName; + } + }; + $(fldLink).change(onLinkChanged).keyup(onLinkChanged); + + return $.TR({}, + $.TH({}, "Language links"), + $.TD({}, selLang, fldLink)); + })(); + + var fldSummary + = $.TEXTAREA({className: "summary"}, summary); + + $(fldSummary).change(makeDirty); + + var trSummary + = $.TR({}, + $.TH({}, "Summary"), + $.TD({}, fldSummary)); + + var fldRakkaSource + = $.TEXTAREA({className: "source"}, + (defaultType == "rakka" && source != null ? source : "")); + + $(fldRakkaSource).change(makeDirty); + + var fldCSSSource + = $.TEXTAREA({className: "source"}, + (defaultType == "css" && source != null ? source : "")); + + $(fldCSSSource).change(makeDirty); + + var fldJSSource + = $.TEXTAREA({className: "source"}, + (defaultType == "js" && source != null ? source : "")); + + $(fldJSSource).change(makeDirty); + + var fldUploadFile + = $.INPUT({type: "file"}); + + $(fldUploadFile).change(makeDirty); + + var fldRedirect + = $.INPUT({type: "text", value: (defaultType == "redirect" ? source : "")}); + + $(fldRedirect).change(makeDirty); + + var trContent + = $.TR({}, + $.TH({}), + $.TD({}) + ); + + var btnPreview + = $.INPUT({type: "button", value: "Preview page"}); + + $(btnPreview).click(function () { + if (btnTypeRakka.checked) { + previewRakkaPage( + fldPageName.value, fldRakkaSource.value); + } + else if (btnTypeBinary.checked) { + if (fldUploadFile.value != "") { + previewBinaryPage( + fldPageName.value, fldUploadFile.value); + } + } + }); + + var btnSubmit + = $.INPUT({type: "button", value: "Submit page"}); + + $(btnSubmit).click(function () { + if (btnTypeRakka.checked) { + submitTextPage( + pageName, + oldRevision, + fldPageName.value, + chkIsLocked.checked, + "text/x-rakka", + $(selPageLang).val(), + otherLangs, + fldSummary.value, + fldRakkaSource.value); + } + else if (btnTypeCSS.checked) { + submitTextPage( + pageName, + oldRevision, + fldPageName.value, + chkIsLocked.checked, + "text/css", + $(selPageLang).val(), + otherLangs, + fldSummary.value, + fldCSSSource.value); + } + else if (btnTypeJS.checked) { + submitTextPage( + pageName, + oldRevision, + fldPageName.value, + chkIsLocked.checked, + "text/javascript", + $(selPageLang).val(), + otherLangs, + fldSummary.value, + fldJSSource.value); + } + else if (btnTypeBinary.checked) { + if (fldUploadFile.value != "") { + submitBinaryPage( + pageName, + oldRevision, + fldPageName.value, + chkIsLocked.checked, + $(selPageLang).val(), + otherLangs, + fldSummary.value, + fldUploadFile.value); + } + } + else if (btnTypeRedirect.checked) { + submitRedirection( + pageName, + oldRevision, + fldPageName.value, + chkIsLocked.checked, + fldRedirect.value); + } + }); + + var btnDelete + = $.INPUT({type: "button", value: "Delete this page"}); + + $(btnDelete).click(function () { + if (window.confirm("Do you really want to delete this page?")) { + deletePage(pageName); + } + }); + + var btnCancel + = $.INPUT({type: "button", value: "Cancel editing"}); + + $(btnCancel).click(function () { + if (isDirty) { + if (window.confirm("Do you really want to discard changes?")) { + Rakka.restoreScreen(); + } + } + else { + Rakka.restoreScreen(); + } + }); + + var updateTRContent = function () { + if (btnTypeRakka.checked) { + $(trPageLang).show(); + $(trOtherLangs).show(); + $(trSummary).show(); + $(trContent).find("th").text("Wiki source"); + $(trContent).find("td").empty().append(fldRakkaSource); + $(btnPreview).show(); + } + else if (btnTypeCSS.checked) { + $(trPageLang).show(); + $(trOtherLangs).show(); + $(trSummary).show(); + $(trContent).find("th").text("CSS source"); + $(trContent).find("td").empty().append(fldCSSSource); + $(btnPreview).hide(); + } + else if (btnTypeJS.checked) { + $(trPageLang).show(); + $(trOtherLangs).show(); + $(trSummary).show(); + $(trContent).find("th").text("JavaScript source"); + $(trContent).find("td").empty().append(fldJSSource); + $(btnPreview).hide(); + } + else if (btnTypeBinary.checked) { + $(trPageLang).show(); + $(trOtherLangs).show(); + $(trSummary).show(); + $(trContent).find("th").text("File"); + $(trContent).find("td").empty().append(fldUploadFile); + $(btnPreview).show(); + } + else if (btnTypeRedirect.checked) { + $(trPageLang).hide(); + $(trOtherLangs).hide(); + $(trSummary).hide(); + $(trContent).find("th").text("Destination Page"); + $(trContent).find("td").empty().append(fldRedirect); + $(btnPreview).hide(); + } + }; + $(btnTypeRakka ).change(updateTRContent); + $(btnTypeCSS ).change(updateTRContent); + $(btnTypeJS ).change(updateTRContent); + $(btnTypeBinary ).change(updateTRContent); + $(btnTypeRedirect).change(updateTRContent); + updateTRContent(); + + var pageEditor + = $.TABLE({className: "pageEditor"}, + $.TBODY({}, + $.TR({}, + $.TH({}, "Page name"), + $.TD({}, fldPageName) + ), + trIsLocked, + $.TR({}, + $.TH({}, "Page type"), + $.TD({}, + $.UL({}, + $.LI({}, + $.LABEL({}, + btnTypeRakka, + "Wiki page" + ) + ), + $.LI({}, + $.LABEL({}, + btnTypeCSS, + "Style sheet" + ) + ), + $.LI({}, + $.LABEL({}, + btnTypeJS, + "JavaScript" + ) + ), + $.LI({}, + $.LABEL({}, + btnTypeBinary, + "Binary file" + ) + ), + $.LI({}, + $.LABEL({}, + btnTypeRedirect, + "Redirection" + ) + ) + ) + ) + ), + trPageLang, + trOtherLangs, + trSummary, + trContent, + $.TR({}, + $.TH({}), + $.TD({}, btnPreview, btnSubmit, btnDelete, btnCancel) + ) + ) + ); + + var validate = function () { + var isValid = (function () { + if (fldPageName.value.match(Rakka.rePageName) == null) { + return false; + } + + if (btnTypeRedirect.checked) { + if (fldRedirect.value.match(Rakka.rePageName) == null) { + return false; + } + } + else { + for (var tag in otherLangs) { + if (otherLangs[tag].match(Rakka.rePageName) == null) { + return false; + } + } + + if (btnTypeBinary.checked) { + if (fldUploadFile.value == "") { + return false; + } + } + } + + return true; + })(); + + $(btnSubmit).attr({disabled: (isValid ? "" : "disabled")}); + }; + $(fldPageName) + .add(btnTypeRakka) + .add(btnTypeCSS) + .add(btnTypeJS) + .add(btnTypeBinary) + .add(btnTypeRedirect) + .add($(trOtherLangs).find("input")) + .add(fldUploadFile) + .add(fldRedirect) + .change(validate) + .keyup(validate); + validate(); + + if (oldRevision == null || oldRevision == 0) { + // 削除不可 + $(btnDelete).hide(); } - else { - $(trContent).hide(); + + $area.append(pageEditor); + + if (!Rakka.isLoggedIn() || Rakka.isGlobalLocked) { + $(trIsLocked).hide(); } }; - $(btnTypeRakka ).change(updateTRContent); - $(btnTypeCSS ).change(updateTRContent); - $(btnTypeBinary).change(updateTRContent); - updateTRContent(); - - var pageEditor - = $.TABLE({className: "pageEditor"}, - $.TBODY({}, - $.TR({}, - $.TH({}, "Page name"), - $.TD({}, fldPageName) - ), - $.TR({}, - $.TH({}, "Page type"), - $.TD({}, - $.UL({}, - $.LI({}, - $.LABEL({}, - btnTypeRakka, - "Wiki page" - ) - ), - $.LI({}, - $.LABEL({}, - btnTypeCSS, - "Style sheet" - ) - ), - $.LI({}, - $.LABEL({}, - btnTypeBinary, - "Binary file" - ) - ) - ) - ) - ), - trContent, - $.TR({}, - $.TH({}), - $.TD({}, btnPreview, btnSubmit, btnDelete) - ) - ) - ); - - if (oldRevision == null || oldRevision == 0) { - // 削除不可 - $(btnDelete).hide(); - } - - $place.append(pageEditor); -}; + + var previewRakkaPage = function (pageName, source) { + Rakka.displayWaitingMessage("Loading... please wait."); + + var url = Rakka.baseURI + "render/" + encodeURI(pageName); + $.ajax({ + type : "POST", + url : url, + contentType: "text/x-rakka", + data : source, + processData: false, + success : function (resultDoc) { + Rakka.hideWaitingMessage(); + showPreview(resultDoc); + }, + error : function (req) { + Rakka.hideWaitingMessage(); + alert("Error: " + req.status + " " + req.statusText); + } + }); + }; + + var previewBinaryPage = function (pageName, path) { + Rakka.displayWaitingMessage("Loading... please wait."); + + /* Firefox でバイナリを送らうとすると 0x00 の位置で切れてしまふ。*/ + var bin = Rakka.loadLocalBinaryFile(path); + var url = Rakka.baseURI + "render/" + encodeURI(pageName); + $.ajax({ + type : "POST", + url : url, + contentType: "application/x-rakka-base64-stream", + data : Rakka.encodeBase64(bin), + processData: false, + success : function (resultDoc) { + Rakka.hideWaitingMessage(); + showPreview(resultDoc); + }, + error : function (req) { + Rakka.hideWaitingMessage(); + alert("Error: " + req.status + " " + req.statusText); + } + }); + }; + + var showPreview = function (doc) { + $previewArea.empty(); + + $previewHeader.show(); + $previewArea.show(); + + var root = doc.documentElement; + var child = root.firstChild; + do { + if (child.nodeType == 1) { + // 要素だったので複製 + $previewArea.append(child.cloneNode(true)); + } + } while (child = child.nextSibling); + + Rakka.scrollToTopLeft(); + }; + + var submitTextPage + = function (pageName, oldRevision, givenPageName, isLocked, mimeType, lang, otherLangs, summary, text) { + var NS = "http://cielonegro.org/schema/Rakka/Page/1.0"; + var doc = document.implementation.createDocument(NS, "page", null); + var page = doc.documentElement; + + if (oldRevision != null) { + // ページ書換時 + var updateInfo = doc.createElementNS(NS, "updateInfo"); + updateInfo.setAttribute("oldRevision", oldRevision); + + if (pageName != givenPageName) { + var move = doc.createElementNS(NS, "move"); + move.setAttribute("from", pageName); + updateInfo.appendChild(move); + } + + page.appendChild(updateInfo); + } + + page.setAttribute("isLocked", isLocked ? "yes" : "no"); + page.setAttribute("type", mimeType); + + if (lang != null && lang != "") { + page.setAttribute("lang", lang); + } + + if (summary != null && summary != "") { + var s = doc.createElementNS(NS, "summary"); + s.appendChild( + doc.createTextNode(summary)); + page.appendChild(s); + } + + var oLang = doc.createElementNS(NS, "otherLang"); + for (var tag in otherLangs) { + var link = doc.createElementNS(NS, "link"); + link.setAttribute("lang", tag); + link.setAttribute("page", otherLangs[tag]); + oLang.appendChild(link); + } + page.appendChild(oLang); + + var textData = doc.createElementNS(NS, "textData"); + textData.appendChild( + doc.createTextNode(text)); + + page.appendChild(textData); + + Rakka.displayWaitingMessage("Submitting... please wait."); + + var url = Rakka.baseURI + encodeURI(givenPageName); + $.ajax({ + type : "PUT", + url : url, + contentType: "text/xml", + data : doc, + processData: false, + beforeSend : function (req) { + Rakka.setAuthorization(req); + }, + success : function () { + window.location.replace(url); + }, + error : function (req) { + Rakka.hideWaitingMessage(); + + var $area = Rakka.switchScreen(); + $area.text("Error: " + req.status + " " + req.statusText); + } + }); + }; + + var submitBinaryPage = function (pageName, oldRevision, givenPageName, isLocked, lang, otherLangs, summary, path) { + var NS = "http://cielonegro.org/schema/Rakka/Page/1.0"; + var doc = document.implementation.createDocument(NS, "page", null); + var page = doc.documentElement; + + if (oldRevision != null) { + // ページ書換時 + var updateInfo = doc.createElementNS(NS, "updateInfo"); + updateInfo.setAttribute("oldRevision", oldRevision); + + if (pageName != givenPageName) { + var move = doc.createElementNS(NS, "move"); + move.setAttribute("from", pageName); + updateInfo.appendChild(move); + } + + page.appendChild(updateInfo); + } + + page.setAttribute("isLocked", isLocked ? "yes" : "no"); + page.setAttribute("type", ""); + + if (lang != null && lang != "") { + page.setAttribute("lang", lang); + } + + if (summary != null) { + var s = doc.createElementNS(NS, "summary"); + s.appendChild( + doc.createTextNode(summary)); + page.appendChild(s); + } + + var oLang = doc.createElementNS(NS, "otherLang"); + for (var tag in otherLangs) { + var link = doc.createElementNS(NS, "link"); + link.setAttribute("lang", tag); + link.setAttribute("page", otherLangs[tag]); + oLang.appendChild(link); + } + page.appendChild(oLang); + + var bin = Rakka.loadLocalBinaryFile(path); + var b64 = Rakka.encodeBase64(bin); + + var binaryData = doc.createElementNS(NS, "binaryData"); + binaryData.appendChild( + doc.createTextNode(b64)); + + page.appendChild(binaryData); + + Rakka.displayWaitingMessage("Submitting... please wait."); + + var url = Rakka.baseURI + encodeURI(givenPageName); + $.ajax({ + type : "PUT", + url : url, + contentType: "text/xml", + data : doc, + processData: false, + beforeSend : function (req) { + Rakka.setAuthorization(req); + }, + success : function () { + window.location.replace(url); + }, + error : function (req) { + Rakka.hideWaitingMessage(); + + var $area = Rakka.switchScreen(); + $area.text("Error: " + req.status + " " + req.statusText); + } + }); + }; + + var submitRedirection = function (pageName, oldRevision, givenPageName, isLocked, destination) { + var NS = "http://cielonegro.org/schema/Rakka/Page/1.0"; + var doc = document.implementation.createDocument(NS, "page", null); + var page = doc.documentElement; + + if (oldRevision != null) { + // ページ書換時 + var updateInfo = doc.createElementNS(NS, "updateInfo"); + updateInfo.setAttribute("oldRevision", oldRevision); + + if (pageName != givenPageName) { + var move = doc.createElementNS(NS, "move"); + move.setAttribute("from", pageName); + updateInfo.appendChild(move); + } + + page.appendChild(updateInfo); + } + + page.setAttribute("isLocked", isLocked ? "yes" : "no"); + page.setAttribute("redirect", destination); + + Rakka.displayWaitingMessage("Submitting... please wait."); + + var url = Rakka.baseURI + encodeURI(givenPageName); + $.ajax({ + type : "PUT", + url : url, + contentType: "text/xml", + data : doc, + processData: false, + beforeSend : function (req) { + Rakka.setAuthorization(req); + }, + success : function () { + window.location.replace(url); + }, + error : function (req) { + Rakka.hideWaitingMessage(); + + var $area = Rakka.switchScreen(); + $area.text("Error: " + req.status + " " + req.statusText); + } + }); + }; + + var deletePage = function (pageName) { + var url = Rakka.baseURI + encodeURI(pageName); + $.ajax({ + type : "DELETE", + url : url, + beforeSend : function (req) { + Rakka.setAuthorization(req); + }, + success : function () { + window.location.replace(url); + }, + error : function (req) { + Rakka.hideWaitingMessage(); + + var $area = Rakka.switchScreen(); + $area.text("Error: " + req.status + " " + req.statusText); + } + }); + }; + +})(); \ No newline at end of file