【问题标题】:How to make nicEditor snaplet? (Several questions)如何制作nicEditor snaplet? (几个问题)
【发布时间】:2013-03-18 12:58:30
【问题描述】:

下面的示例定义了一个将 nicEditor 绑定到 textarea 的 snaplet。以下问题不仅与下面的示例有关,而且可能与其他一些类似的案例有关。..

  1. 新手能否按照以下说明进行操作(如何澄清)?
  2. 如何使示例使用更少的步骤或更简单? (是否可能与以下内容大致相同?)
  3. 这使用了解释拼接。如果可能,snaplet 是否也应提供已编译的拼接?
  4. 一个 snaplet 可能会为典型情况提供一个默认处理程序或几个处理程序。处理程序可以在下面的“SnapNic.hs”中定义。那么给用户一些回调机制呢?

--

{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE OverloadedStrings #-}

 ------------------------------------------------------------------------------
-- | This module defines nicEditor snaplet, just a short example to show,
-- how snaplets can be defined together with splices.
-- License: BSD3. 
-- Here are hopefully easy instructions, how to use or try:
-- 
-- 1. Make a directory, we'll use "netry" below, go there.
--  Initialize a project, e.g. "snap init default".
-- 2. Copy this file to netry/src-directory as SnapNic.hs.
-- 3. Add "import SnapNic" to Site.hs and to Application.hs
-- 4. Add ", _niced :: Snaplet Nicsnap" to data App in Application.hs 
-- 
-- 5. Add "n <- nestSnaplet "niced" niced nicsnapInit" to 
--    app :: SnapletInit App App in Site.hs. 
-- 6. Add "addNicEditSplices n" to the same function as in step 5.
-- 7. Change the return-line of the same function as in step 5: 
--      "return $ App h s a n" 
--    that is, add "n" into the end. We need this because of step 4.
-- 
-- 8. Make route, e.g. ", ("/netext",   with auth handleNEtext)" to
--    routes-function in Site.hs
-- 
-- 9. And then add handler into Site.hs:
--    handleNEtext :: Handler App v ()
--    handleNEtext = method GET handleForm <|> method POST handleFormSubmit
--      where
--       handleForm = render "textedit"
--       handleFormSubmit = do 
--        p <- getParam "ots"
--        writeText "Submitting text from textarea...\n"
--        writeText (T.pack (show p))
-- 
-- 10. Last, add the following 2 templates to "netry/snaplets/heist/templates".
--    (This could be made simpler, but this works as an example of apply-tag.)
--    textedit.tpl:
--      <apply template="base">
--         <apply template="_textedit" />
--      </apply>
--    _textedit.tpl:
--       <h2>Your nic editor</h2>
--         <form method="post" action="netext">
--           <neTA/>
--           <button name="ne" value="ne" type="Submit">Send text</button>
--         </form>
--         <neScript/>
-- 
-- 11. Compile everything "cabal install -fdevelopment". After that, 
--     if everything compiled, "netry -p 8000", start your browser and go
--     to "localhost:8000/netext".
-- 
-- TODO! This could use the config-files at least for some parameters, and more
-- tags,please. Tags could use some attributes (for example, size parameters
-- could be given as attributes of tags)...
-- 
module SnapNic 
  ( Nicsnap (..)
  , nicsnapInit
  , addNicEditSplices
  ) where

------------------------------------------------------------------------------
import           Control.Lens   (makeLenses, view, (^.))
import qualified Data.Text as T (Text, append, pack)
import           Data.Maybe     (fromJust, fromMaybe)
import           Snap.Core      (MonadSnap)
import           Snap.Snaplet   (Snaplet
                                , makeSnaplet
                                , snapletValue
                                , SnapletInit
                                , Initializer
                                )
import           Snap.Snaplet.Heist     (HasHeist, addSplices)
import qualified Text.XmlHtml as X      (Node (Element, TextNode))
import qualified Heist.Interpreted as I (Splice)

------------------------------------------------------------------------------
-- | Nicsnap has fields that can be used to set some basic properties.
-- The editor can have a title and its size can be set. Javascript can be
-- local or remote.
data Nicsnap = Nicsnap
  { _nicsnap  :: T.Text       -- title
  , _areaSize :: (Int,Int)    -- rows, cols
  , _areaRef  :: T.Text       -- how to apply nicEditors? 
  -- (This may not be sufficient in order to refer in some other way, TODO!)
  , _localR   :: Maybe T.Text -- local route to nicEdit.js
  , _webR     :: T.Text       -- route to nicEdit's javascript source. 
  }

makeLenses ''Nicsnap          -- makes webR and other lenses


------------------------------------------------------------------------------
-- | Configurations are given here. This could use config-files...
-- What other things to configure?
-- If you want to make a local copy of the nicEdit, then add a static route
-- to the "routes"-function. 
nicsnapInit :: SnapletInit b Nicsnap
nicsnapInit = makeSnaplet "nicsnap" "NicEditor snaplet " Nothing $ do
   let m  = "Nic editor title"
       aS = (20,80)::(Int,Int) -- rows, cols
       aR = "nicEditors.allTextAreas" -- TODO! We need to be able to tell,
       -- which textareas have editors in a page.
       lR = Nothing 
       -- lR = Just "/nicEdit.js" 
       -- If localR is nothing, then webR is used with the following addr.
       wR = "http://js.nicedit.com/nicEdit-latest.js"
   return $ Nicsnap m aS aR lR wR

------------------------------------------------------------------------------

-- | Internal, this makes the script-tag.
-- Input could be e.g. txt = "/nicEdit.js"
srcElem :: T.Text -> X.Node
srcElem txt = X.Element "script" 
   [("src",txt),("type","text/javascript")] []

-- | Internal, this makes the script-tag. At the moment this changes all
-- textareas to niceditors, if the example input below is used. TODO!...
-- Input could be e.g.  txt = "nicEditors.allTextAreas"
srcOnLoad :: T.Text -> X.Node
srcOnLoad txt = X.Element "script" [("type","text/javascript")] 
   [X.TextNode (T.append (T.append "bkLib.onDomLoaded(" txt) ");")] 


-- | Internal, used to define "divs", where we give a label and size to 
-- textarea. Also ids and names.
-- TODO! ids and names could be parameters.
divLabelTX :: T.Text -> T.Text -> T.Text -> X.Node
divLabelTX title r c =  X.Element "div" [("class", "required")]
   [ X.Element "label" [("for","ots")] 
        [X.TextNode title]
   , X.Element "textarea" 
        [("id","ots"), ("name","ots"), ("cols",c), ("rows",r)] 
        [X.TextNode " "]
   ]

-- | Internal, this can be used in splice-definition.
-- TODO! ids and names could be parameters, too.
nicTextAreaAdd :: MonadSnap m => T.Text -> (Int,Int) -> I.Splice m
nicTextAreaAdd title (r,c) = return [divLabelTX 
  title
  (T.pack . show $ r) 
  (T.pack . show $ c)]

-- | Add script-tags to web page with splice that tell, what javascript
-- library to use... 
nicEditAdd :: MonadSnap m => T.Text -> T.Text -> I.Splice m
nicEditAdd src edElems = return (srcElem src : [srcOnLoad edElems])

------------------------------------------------------------------------------

-- | Get the route to the javascript library that is applied (either local
-- library or construct a link to a web address).
nicRoute :: Nicsnap -> T.Text
nicRoute ns = let mlR = ns ^. localR in fromMaybe (ns ^. webR) mlR

------------------------------------------------------------------------------

-- | neTextAreaTag and neScripTag are used in addSplices to define the tags
-- to be used in templates.
-- What other tags could be useful? Maybe a way to add a nicEditor directly
-- with one or more button bind to it ("send", "clear", etc). TODO!
neTextAreaTag = "neTA"     :: T.Text
neScriptTag   = "neScript" :: T.Text

-- | Make the tags to be used in templates. At the moment, only the above
-- tags are defined. 
addNicEditSplices :: HasHeist b => Snaplet Nicsnap -> Initializer b v ()
addNicEditSplices n = let m = view snapletValue n in addSplices
  [(neTextAreaTag, nicTextAreaAdd (m ^. nicsnap) (m ^. areaSize))
  ,(neScriptTag,   nicEditAdd (nicRoute m) (m ^. areaRef) )
  ]
------------------------------------------------------------------------------

【问题讨论】:

    标签: haskell haskell-snap-framework


    【解决方案1】:

    我不是新手,所以我无法回答你的第一个问题,但我对其他一些问题有一些想法和答案。首先,如果您真的希望这是一个严肃的 snaplet(用于教学目的或实际使用),您可能应该将其变成一个 cabal 项目。这将从您的说明中消除第 2 步。接下来,snaplets 可以定义自己的路由。您可以通过调用 addRoutes 函数在初始化程序中执行此操作。这将消除第 8 步。Snaplets 还可以提供自己的文件系统资源,这些资源将被复制到使用它的任何项目中。您可以使用此功能来消除第 10 步,并提供默认配置文件。有关如何执行此操作的更多信息,请查看 snaplet 教程末尾的 filesystem data and automatic installation 部分。

    目前,snaplet-postgresql-simple 可能是关于如何使用 snaplet 必须提供的大多数功能的 hackage 的最佳示例。如果你想让它成为一个真正强大的通用 snaplet 供其他人使用,那么你绝对应该包括解释和编译的拼接。我最近在 snap 包中添加了一些 new functions,这使得编写在编译或解释拼接模式下自动工作的通用 snaplets 变得更加容易。该代码还没有被破解,但我可能很快就会发布它。

    我也一直致力于another snaplet,它可以更全面地使用 snaplet API 的大部分功能。与 snaplet-postgresql-simple 不同,这个 snaplet 定义了模板和拼接。它仍在开发中,但已经展示了大部分功能。剩下的工作主要是润色和健壮性。

    【讨论】:

    • 再次感谢!我不得不多次阅读文件系统数据部分,并且在 cabal 中遇到了一些困难。现在它似乎可以安装了,我可以像其他库一样使用。
    • 继续,接下来的问题是,在我完成一些清洁后如何处理这个包。 (这应该放到 github 上吗?)另一个问题是现在路由需要 /-char 在地址末尾。如何使它也接受一个不结束 /-char 的地址?
    • 如果你认为其他人可以从中受益,那么通常的做法是把它放在github和hackage上。如果没有更多信息,我无法回答第二个问题。
    • 我认为你在玩 snaplet 很棒,但我也可能会附带说明,这可能不是 snaplet 的最佳应用程序。在我看来,您可以通过使用&lt;bind&gt; 标签在模板中更灵活地完成大部分工作。我倾向于为需要更多 haskell 代码且不能仅在模板中完成的事情编写 snaplet。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-30
    • 2015-01-03
    • 2010-10-21
    • 1970-01-01
    相关资源
    最近更新 更多