From d128bc12ae9f763c37941122bf2e163517810bba Mon Sep 17 00:00:00 2001 From: pho Date: Sun, 6 Jan 2008 17:55:52 +0900 Subject: [PATCH] implemented binary file preview/upload darcs-hash:20080106085552-62b54-560383c5e58f1408c5f8365f9ab160cf4d14116d.gz --- Rakka.cabal | 2 ++ Rakka/Page.hs | 11 ++++-- Rakka/Resource/Render.hs | 24 +++++++------ js/Makefile | 2 ++ js/base64.js | 41 ++++++++++++++++++++++ js/editPage.js | 76 ++++++++++++++++++++++++++++++++++++++++ js/localFile.js | 44 +++++++++++++++++++++++ 7 files changed, 187 insertions(+), 13 deletions(-) create mode 100644 js/base64.js create mode 100644 js/localFile.js diff --git a/Rakka.cabal b/Rakka.cabal index afca200..f6da68d 100644 --- a/Rakka.cabal +++ b/Rakka.cabal @@ -29,9 +29,11 @@ Extra-Source-Files: configure.ac js/Makefile js/base.js + js/base64.js js/editPage.js js/jquery-1.2.1.js js/jquery-dom.js + js/localFile.js js/screen.js Flag build-test-suite diff --git a/Rakka/Page.hs b/Rakka/Page.hs index d6a9369..f701d92 100644 --- a/Rakka/Page.hs +++ b/Rakka/Page.hs @@ -339,8 +339,7 @@ parseEntity = proc (name, tree) -> do updateInfo <- maybeA parseUpdateInfo -< tree - mimeType <- (getXPathTreesInDoc "/page/@type/text()" >>> getText - >>> arr read) -< tree + mimeTypeStr <- withDefault (getXPathTreesInDoc "/page/@type/text()" >>> getText) "" -< tree lang <- maybeA (getXPathTreesInDoc "/page/@lang/text()" >>> getText) -< tree fileName <- maybeA (getXPathTreesInDoc "/page/@filename/text()" >>> getText) -< tree @@ -372,6 +371,14 @@ parseEntity (Just text, Nothing ) -> (False, L.pack $ UTF8.encode text ) (Nothing , Just binary) -> (True , L.pack $ B64.decode binary) _ -> error "one of textData or binaryData is required" + mimeType + = if isBinary then + if null mimeTypeStr then + guessMIMEType content + else + read mimeTypeStr + else + read mimeTypeStr returnA -< Entity { entityName = name diff --git a/Rakka/Resource/Render.hs b/Rakka/Resource/Render.hs index 670edd8..778ca21 100644 --- a/Rakka/Resource/Render.hs +++ b/Rakka/Resource/Render.hs @@ -3,23 +3,19 @@ module Rakka.Resource.Render ) where +import qualified Codec.Binary.Base64 as B64 import Control.Arrow import Control.Arrow.ArrowIO import Control.Arrow.ArrowList import Control.Monad.Trans -import qualified Codec.Binary.UTF8.String as UTF8 -import qualified Data.ByteString.Lazy as Lazy -import qualified Data.Map as M +import qualified Data.ByteString.Lazy as Lazy (ByteString, pack) +import qualified Data.ByteString.Lazy.Char8 as L8 hiding (ByteString) import Network.HTTP.Lucu import Network.HTTP.Lucu.Utils import Rakka.Environment import Rakka.Page import Rakka.Utils -import Rakka.Wiki import Rakka.Wiki.Engine -import Rakka.Wiki.Parser -import Rakka.Wiki.Interpreter -import Text.ParserCombinators.Parsec import Text.XML.HXT.Arrow.Namespace import Text.XML.HXT.Arrow.WriteDocument import Text.XML.HXT.Arrow.XmlArrow @@ -66,12 +62,18 @@ resRender env -} handleRender :: Environment -> PageName -> Resource () handleRender env name - = do bin <- inputLBS defaultLimit + = do entity <- inputLBS defaultLimit cTypeM <- getContentType - let cType = case cTypeM of - Just t -> t - Nothing -> guessMIMEType bin + let (bin, cType) = case cTypeM of + Just (MIMEType "application" "x-rakka-base64-stream" _) + -> let b = Lazy.pack $ B64.decode $ L8.unpack entity + in + (b, guessMIMEType b) + Just t + -> (entity, t) + Nothing + -> (entity, guessMIMEType entity) setContentType $ read "text/xml" [xmlStr] <- liftIO $ runX ( setErrorMsgHandler False fail diff --git a/js/Makefile b/js/Makefile index effc48b..a399e6f 100644 --- a/js/Makefile +++ b/js/Makefile @@ -5,7 +5,9 @@ SOURCES = \ $(JQUERY_SOURCE) \ jquery-dom.js \ base.js \ + base64.js \ editPage.js \ + localFile.js \ redirection.js \ screen.js \ $(NULL) diff --git a/js/base64.js b/js/base64.js new file mode 100644 index 0000000..f4775ae --- /dev/null +++ b/js/base64.js @@ -0,0 +1,41 @@ +(function () { + + var b64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + Rakka.encodeBase64 = function (src) { + var len = src.length; + var i = 0; + var ret = ""; + + while (i < len) { + var c1 = src.charCodeAt(i++); + + if (i == len) { + ret += b64Chars.charAt(c1 >> 2); + ret += b64Chars.charAt((c1 & 0x03) << 4); + ret += "=="; + } + else { + var c2 = src.charCodeAt(i++); + + if (i == len) { + ret += b64Chars.charAt(c1 >> 2); + ret += b64Chars.charAt(((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)); + ret += b64Chars.charAt((c2 & 0x0F) << 2); + ret += "="; + } + else { + var c3 = src.charCodeAt(i++); + + ret += b64Chars.charAt(c1 >> 2); + ret += b64Chars.charAt(((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)); + ret += b64Chars.charAt(((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)); + ret += b64Chars.charAt(c3 & 0x3F); + } + } + } + + return ret; + }; + +})(); \ No newline at end of file diff --git a/js/editPage.js b/js/editPage.js index 2dd9951..a8869fb 100644 --- a/js/editPage.js +++ b/js/editPage.js @@ -253,6 +253,30 @@ Rakka.previewRakkaPage = function (pageName, source) { Rakka.showPreview(resultDoc); }, error : function (req) { + Rakka.hideWaitingMessage(); + alert("Error: " + req.status + " " + req.statusText); + } + }); +}; + +Rakka.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(); + Rakka.showPreview(resultDoc); + }, + error : function (req) { + Rakka.hideWaitingMessage(); alert("Error: " + req.status + " " + req.statusText); } }); @@ -323,6 +347,58 @@ Rakka.submitTextPage = function (pageName, oldRevision, givenPageName, mimeType, }); }; +Rakka.submitBinaryPage = function (pageName, oldRevision, givenPageName, path) { + var doc = document.implementation.createDocument( + "http://cielonegro.org/schema/Rakka/Page/1.0", "page", null); + + var page = doc.documentElement; + + if (oldRevision != null) { + // ページ書換時 + var updateInfo = doc.createElement("updateInfo"); + updateInfo.setAttribute("oldRevision", oldRevision); + + if (pageName != givenPageName) { + var move = doc.createElement("move"); + move.setAttribute("from", pageName); + updateInfo.appendChild(move); + } + + page.appendChild(updateInfo); + } + + page.setAttribute("type", ""); + + var bin = Rakka.loadLocalBinaryFile(path); + var b64 = Rakka.encodeBase64(bin); + + var binaryData = doc.createElement("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, + success : function () { + window.location.replace(url); + }, + error : function (req) { + Rakka.hideWaitingMessage(); + + var $area = Rakka.switchScreen(); + $area.text("Error: " + req.status + " " + req.statusText); + } + }); +}; + Rakka.submitRedirection = function (pageName, oldRevision, givenPageName, destination) { var doc = document.implementation.createDocument( "http://cielonegro.org/schema/Rakka/Page/1.0", "page", null); diff --git a/js/localFile.js b/js/localFile.js new file mode 100644 index 0000000..1a6fbfe --- /dev/null +++ b/js/localFile.js @@ -0,0 +1,44 @@ +(function () { + + Rakka.canAccessLocalFile = function () { + return $.browser.mozilla; + }; + + var loadBin_mozilla = function (path) { + try { + netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); + } + catch (e) { + alert("Permission to read local file was denied. " + + "Open about:config and check that " + + "signed.applets.codebase_principal_support is set to true."); + } + + var localFile + = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); + localFile.initWithPath(path); + + var stream + = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); + stream.init(localFile, 0x01, 00004, null); + + var bstream + = Components.classes["@mozilla.org/network/buffered-input-stream;1"].getService(); + bstream.QueryInterface(Components.interfaces.nsIBufferedInputStream); + bstream.init(stream, 1000); + bstream.QueryInterface(Components.interfaces.nsIInputStream); + + var binary + = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream); + binary.setInputStream(stream); + + return binary.readBytes(binary.available()); + }; + + Rakka.loadLocalBinaryFile = function (path) { + if ($.browser.mozilla) { + return loadBin_mozilla(path); + } + }; + +})(); \ No newline at end of file -- 2.40.0