-- Copyright 2010 Google Inc. -- -- Licensed under the Apache License, Version 2.0 (the "License"); -- you may not use this file except in compliance with the License. -- You may obtain a copy of the License at -- -- http://www.apache.org/licenses/LICENSE-2.0 -- -- Unless required by applicable law or agreed to in writing, software -- distributed under the License is distributed on an "AS IS" BASIS, -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -- See the License for the specific language governing permissions and -- limitations under the License. module Source where import DevUtils import Tutorial import Control.Monad (when) import Control.Monad.IO.Class import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as C import Data.Maybe import qualified Data.Text as T import qualified Data.Text.Encoding as T import Snap.Types import Text.Html hiding (()) import qualified Text.Html as Html handler :: Snap () handler = do fileparam <- getParam (C.pack "file") showPreview <- (maybe False (not . C.null)) `fmap` getParam (C.pack "preview") case maybe Nothing (legalPath . C.unpack) fileparam of Nothing -> errorBadRequest Just file -> do meth <- rqMethod `fmap` getRequest when (meth == POST) $ handleSave file html <- liftIO $ mkSrcPage file showPreview htmlResponse html handleSave :: FilePath -> Snap() handleSave file = do contents <- getParam (C.pack "contents") case contents of Nothing -> errorBadRequest Just c -> liftIO $ B.writeFile file $ clean c where clean = T.encodeUtf8 . T.filter (/= '\r') . T.decodeUtf8 mkSrcPage :: FilePath -> Bool -> IO Html mkSrcPage path showPreview = do si <- getSrcInfo path contents <- if srcExists si then readFile (srcPath si) else return $ emptyModule (srcPath si) return $ srcPage si contents showPreview srcPage :: SrcInfo -> String -> Bool -> Html srcPage si contents showPreview = devpage ("Source of " ++ srcPath si) content (modules si) scriptSrcs where content = thediv ! [identifier "source-page"] << [ h1 << srcPath si , p << small << srcFullPath si , rocker , preview showPreview si , editor contents ] rocker = thediv ! [identifier "rocker", theclass "button-set"] << [ thediv ! [identifier "rocker-edit-image"] << noHtml , thediv ! [identifier "rocker-run-image", displayHidden] << noHtml , anchor ! [identifier "rocker-edit", href "#"] << "Edit" , anchor ! [identifier "rocker-run", href "#"] << "Run" ] editor :: String -> Html editor contents = thediv ! [identifier "editor", displayHidden] << [ errors , form ! [Html.method "POST"] << [editorBox, btns, hidden] ] where btns = thediv ! [theclass "button-set"] << [ input ! [thetype "button", value "Cancel", theclass "btn-cancel"] , input ! [thetype "submit", value "Save", theclass "btn-save"] ] editorBox = thediv ! [identifier "editor-box"] << textarea ! [theclass "src", name "contents", identifier "txt-src", strAttr "readonly" "readonly" ] << contents hidden = input ! [thetype "hidden", name "preview", value "1"] preview :: Bool -> SrcInfo -> Html preview showPreview = maybe noHtml build . previewPath where build path = thediv ! [ identifier "preview" , theclass "panel with-preview" , displayHidden ] << [ h1 << "Rendering Preview" , tag "iframe" ! [ theclass "panel-content" ] << noHtml , p ! [ identifier "preview-url", displayHidden ] << path , showMarker ] showMarker = if showPreview then thediv ! [ identifier "preview-show", displayHidden ] << noHtml else noHtml errors :: Html errors = thediv ! [ identifier "errors" , theclass "panel with-errors" , displayHidden] << [ h1 << "Compilation Errors" , pre ! [ theclass "panel-content", displayHidden ] << noHtml ] modules :: SrcInfo -> [Html] modules si = catMaybes [ Just $ modFStat si , Just $ modActions si , modTutorial si , Just modSearch] modFStat :: SrcInfo -> Html modFStat si = (h2 << "File Info") +++ if srcExists si then [if srcWritable si then noHtml else p << bold << "read only", p << show (srcModTime si)] else [p << bold << "new file"] modActions :: SrcInfo -> Html modActions si = (h2 << "Actions") +++ ulist << map (li ! [theclass "op"]) (catMaybes [ previewLink si --, Just $ italics << "Revert" , downloadLink si , fileLink si , Just (anchor ! [ identifier "recompile", theclass "op-recompile", href "#" ] << "Force Recompile") ]) modTutorial :: SrcInfo -> Maybe Html modTutorial si = previewPath si >>= tutorialModule modSearch :: Html modSearch = (h2 << "Research") +++ [ form ! [action "http://holumbus.fh-wedel.de/hayoo/hayoo.html" , target "barley-reseach"] << [ input ! [thetype "text", name "query", theclass "research-query"] , input ! [thetype "submit", value "Hayoo"] ] , form ! [action "http://haskell.org/hoogle", target "barley-reseach"] << [ input ! [thetype "text", name "q", theclass "research-query"] , input ! [thetype "submit", value "Hoogle"] ] ] emptyModule :: FilePath -> String emptyModule filename = "module " ++ modName ++ " where\n\ \\n\ \import Text.Html\n\ \\n\ \page = body << [\n\ \ h1 << \"Hi!\",\n\ \ paragraph << \"testing\"\n\ \ ]\n" where modName = filename -- TODO should replace slashes with dots scriptSrcs :: [String] scriptSrcs = [ "/static/jquery.js" , "/static/codemirror_min.js" , "Source.js" ] displayHidden :: HtmlAttr displayHidden = thestyle "display: none;"