-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | stateful, RESTful web framework -- -- MFlow run stateful server processes. This version is the first -- stateful web framework that is as RESTful as a web framework can be. -- -- The routes are expressed as normal, monadic haskell code in the FlowM -- monad. Local links point to alternative routes within this monadic -- computation just like a textual menu in a console application. Any GET -- page is directly reachable by means of a RESTful URL. -- -- All the flow of requests and responses are coded by the programmer in -- a single procedure. Allthoug single request-response flows are -- possible. Therefore, the code is more understandable. It is not -- continuation based. It uses a log for thread state persistence and -- backtracking for handling the back button. Back button state -- syncronization is supported out-of-the-box -- -- The MFlow architecture is scalable, since the state is serializable -- and small -- -- The processes are stopped and restarted by the application server on -- demand, including the execution state (if the Wokflow monad is used). -- Therefore session management is automatic. State consistence and -- transactions are given by the TCache package. -- -- The processes interact trough widgets, that are an extension of -- formlets with additional applicative combinators, formatting, link -- management, callbacks, modifiers, caching, byteString conversion and -- AJAX. All is coded in pure haskell. -- -- The interfaces and communications are abstract, but there are bindings -- for blaze-html, HSP, Text.XHtml and byteString , Hack and WAI but it -- can be extended to non Web based architectures. -- -- Bindings for hack, and hsp >= 0.8, are not compiled by Hackage, and -- do not appear, but are included in the package files. To use them, add -- then to the exported modules and execute cabal install -- -- It is designed for applications that can be run with no deployment -- with runghc in order to speed up the development process. see -- http://haskell-web.blogspot.com.es/2013/05/a-web-application-in-tweet.html -- -- This release includes: -- -- -- -- The version 0.2 added better WAI integration, higher level dynamic -- Widgets, content management, multilanguage, blaze-html support, -- stateful ajax for server-side control, user-defined data in sessions -- and widget requirements for automatic installation of scripts, CSS and -- server flows. -- -- The version 0.1 added transparent back button management, cached -- widgets, callbacks, modifiers, heterogeneous formatting, AJAX, and WAI -- integration. -- -- See MFlow.Forms for details . . To do: -- -- @package MFlow @version 0.3.0.1 module MFlow.Cookies type Cookie = (String, String, String, Maybe String) contentHtml :: (String, String) urlDecode :: String -> [(String, String)] cookieuser :: String cookieHeaders :: IsString t => [Cookie] -> [(t, String)] getCookies :: (Eq a, IsString a) => [(a, [Char])] -> [([Char], [Char])] -- | Non monadic low level primitives that implement the MFlow application -- server. See MFlow.Form for the higher level interface that you -- may use. -- -- it implements an scheduler of Processable messages that are -- served according with the source identification and the verb invoked. -- The scheduler executed the appropriate workflow (using the workflow -- package). The workflow will send additional messages to the source and -- wait for the responses. The diaglog is identified by a Token, -- which is associated to the flow. . The computation state is optionally -- logged. On timeout, the process is killed. When invoked again, the -- execution state is recovered as if no interruption took place. -- -- There is no asumption about message codification, so instantiations of -- this scheduler for different infrastructures is possible, including -- non-Web based ones as long as they support or emulate cookies. -- -- MFlow.Hack is an instantiation for the Hack interface in a Web -- context. -- -- MFlow.Wai is a instantiation for the WAI interface. -- -- MFlow.Forms implements a monadic type safe interface with -- composabe widgets and and applicative combinator as well as an higher -- comunication interface. -- -- MFlow.Forms.XHtml is an instantiation for the Text.XHtml format -- -- MFlow.Forms.Blaze.Html is an instantaiation for blaze-html -- -- MFlow.Forms.HSP is an instantiation for the Haskell Server -- Pages format -- -- There are some *.All packages that contain a mix of these -- instantiations. For exmaple, MFlow.Wai.Blaze.Html.All includes -- most of all necessary for using MFlow with Wai -- http://hackage.haskell.org/package/wai and Blaze-html -- http://hackage.haskell.org/package/blaze-html -- -- In order to manage resources, there are primitives that kill the -- process and its state after a timeout. -- -- All these details are hidden in the monad of MFlow.Forms that -- provides an higher level interface. -- -- Fragment based streaming: sendFragment are provided only at -- this level. -- -- stateless and transient server processeses are also -- possible. the first are request-response . transient processes -- do not persist after timeout, so they restart anew after a timeout or -- a crash. module MFlow type Flow = Token -> Workflow IO () type Params = [(String, String)] data HttpData HttpData :: Params -> [Cookie] -> ByteString -> HttpData Error :: WFErrors -> ByteString -> HttpData class Processable a where pwfname s = head $ pwfPath s !> "head mf" pwfname :: Processable a => a -> String pwfPath :: Processable a => a -> [String] puser :: Processable a => a -> String pind :: Processable a => a -> String getParams :: Processable a => a -> Params -- | a Token identifies a flow that handle messages. The scheduler compose -- a Token with every Processable message that arrives and send -- the mesage to the appropriate flow. data Token Token :: String -> String -> String -> [String] -> Params -> MVar Req -> MVar Resp -> Token twfname :: Token -> String tuser :: Token -> String tind :: Token -> String tpath :: Token -> [String] tenv :: Token -> Params tsendq :: Token -> MVar Req trecq :: Token -> MVar Resp -- | List of (wfname, workflow) pairs, to be scheduled depending on the -- message's pwfname type ProcList = WorkflowList IO Token () flushRec :: Token -> IO () receive :: Typeable a => Token -> IO a receiveReq :: Token -> IO Req receiveReqTimeout :: Int -> Integer -> Token -> IO Req -- | send a complete response send :: Token -> HttpData -> IO() send :: Token -> HttpData -> IO () sendFlush :: Token -> HttpData -> IO () -- | send a response fragment. Useful for streaming. the last packet must -- sent trough send sendFragment :: Token -> HttpData -> IO () -- | Deprecated: use send to end a fragmented response instead sendEndFragment :: Token -> HttpData -> IO () sendToMF :: (Typeable a, Processable a) => Token -> a -> IO () -- | add a list of flows to be scheduled. Each entry in the list is a pair -- (path, flow) addMessageFlows :: [([Char], Token -> Workflow IO ())] -> IO () -- | return the list of the scheduler getMessageFlows :: IO (WorkflowList IO Token ()) -- | Executes a monadic computation that send and receive messages, but -- does not store its state in permanent storage. The process once -- stopped, will restart anew transient :: (Token -> IO ()) -> Flow -- | executes a simple monadic computation that receive the params and -- return a response -- -- It is used with addMessageFlows -- -- There is a higuer level version wstateless in -- MFLow.Forms stateless :: (Params -> IO HttpData) -> Flow -- | The anonymous user anonymous :: [Char] -- | It is the path of the root flow noScript :: [Char] -- | The handler of the error log hlog :: Handle -- | set the 404 not found response. -- -- The parameter is as follows: (String The user identifier. The username -- when logged -> String The error string -> HttpData) The -- response. See defNotFoundResponse code for an example setNotFoundResponse :: (String -> String -> HttpData) -> IO () getNotFoundResponse :: IO (String -> [Char] -> HttpData) -- | Writes a XML tag in a ByteString. It is the most basic form of -- formatting. For more sophisticated formatting , use -- MFlow.Forms.XHtml or MFlow.Forms.HSP. btag :: String -> Attribs -> ByteString -> ByteString -- |
--   bhtml ats v= btag "html" ats v
--   
bhtml :: Attribs -> ByteString -> ByteString -- |
--   bbody ats v= btag "body" ats v
--   
bbody :: Attribs -> ByteString -> ByteString type Attribs = [(String, String)] addAttrs :: ByteString -> Attribs -> ByteString -- | Set the path of the files in the web server. The links to the files -- are relative to it. The files are cached (memoized) according with the -- Data.TCache policies in the program space. This avoid the -- blocking of the efficient GHC threads by frequent IO calls.So it -- enhances the performance in the context of heavy concurrence. It uses -- Memoization. The caching-uncaching follows the -- setPersist criteria setFilesPath :: String -> IO () addTokenToList :: Token -> IO () deleteTokenInList :: Token -> IO () -- | The scheduler creates a Token with every Processable message -- that arrives and send the mesage to the appropriate flow, then waht -- for the response and return it. -- -- It is the core of the application server. MFLow.Wai and -- MFlow.Hack use it msgScheduler :: (Typeable a, Processable a) => a -> IO (HttpData, ThreadId) serveFile :: [Char] -> IO HttpData newFlow :: IO String instance Typeable HttpData instance Typeable Req instance Typeable Token instance Typeable NFlow instance Show HttpData instance Read NFlow instance Show NFlow instance Indexable NFlow instance Serializable NFlow instance Serializable Token instance Read Token instance Show Token instance Indexable Token instance Processable Req instance Processable Token instance Monoid HttpData -- | MFlow run stateful server processes. This version is the first -- stateful web framework that is as RESTful as a web framework can be. -- -- The routes are expressed as normal, monadic haskell code in the FlowM -- monad. Local links point to alternative routes within this monadic -- computation just like a textual menu in a console application. Any GET -- page is directly reachable by means of a RESTful URL. -- -- At any moment the flow can respond to the back button or to any -- RESTful path that the user may paste in the navigation bar. If the -- procedure is waiting for another different page, the FlowM monad -- backtrack until the path partially match . From this position the -- execution goes forward until the rest of the path match. This way the -- statelessness is optional. However, it is possible to store a session -- state, which may backtrack or not when the navigation goes back and -- forth. It is upto the programmer. -- -- All the flow of requests and responses are coded by the programmer in -- a single procedure. Allthoug single request-response flows are -- possible. Therefore, the code is more understandable. It is not -- continuation based. It uses a log for thread state persistence and -- backtracking for handling the back button. Back button state -- syncronization is supported out-of-the-box -- -- The MFlow architecture is scalable, since the state is serializable -- and small -- -- The processes are stopped and restarted by the application server on -- demand, including the execution state (if the Wokflow monad is used). -- Therefore session management is automatic. State consistence and -- transactions are given by the TCache package. -- -- The processes interact trough widgets, that are an extension of -- formlets with additional applicative combinators, formatting, link -- management, callbacks, modifiers, caching, byteString conversion and -- AJAX. All is coded in pure haskell. -- -- The interfaces and communications are abstract, but there are bindings -- for blaze-html, HSP, Text.XHtml and byteString , Hack and WAI but it -- can be extended to non Web based architectures. -- -- Bindings for hack, and hsp >= 0.8, are not compiled by Hackage, and -- do not appear, but are included in the package files. To use them, add -- then to the exported modules and execute cabal install -- -- It is designed for applications that can be run with no deployment -- with runghc in order to speed up the development process. see -- http://haskell-web.blogspot.com.es/2013/05/a-web-application-in-tweet.html -- -- This release (0.3) includes: -- -- -- -- The version 0.2 added better WAI integration, higher level dynamic -- Widgets, content management, multilanguage, blaze-html support, -- stateful ajax for server-side control, user-defined data in sessions -- and widget requirements for automatic installation of scripts, CSS and -- server flows. -- -- The version 0.1 added transparent back button management, cached -- widgets, callbacks, modifiers, heterogeneous formatting, AJAX, and WAI -- integration. -- -- This module implement stateful processes (flows) that are optionally -- persistent. This means that they automatically store and recover his -- execution state. They are executed by the MFlow app server. defined in -- the MFlow module. -- -- These processses interact with the user trough user interfaces made of -- widgets (see below) that return back statically typed responses to the -- calling process. Because flows are stateful, not request-response, the -- code is more understandable, because all the flow of request and -- responses is coded by the programmer in a single procedure in the -- FlowM monad. Allthoug single request-response flows and callbacks are -- possible. -- -- This module is abstract with respect to the formatting (here referred -- with the type variable view) . For an instantiation for -- Text.XHtml import MFlow.Forms.XHtml, -- MFlow.Hack.XHtml.All or MFlow.Wai.XHtml.All . To use -- Haskell Server Pages import MFlow.Forms.HSP. However the -- functionalities are documented here. -- -- ask is the only method for user interaction. It run in the -- MFlow view m monad, with m the monad chosen by the -- user, usually IO. It send user interfaces (in the View view m -- monad) and return statically typed responses. The user interface -- definitions are based on a extension of formLets -- (http://www.haskell.org/haskellwiki/Formlets) with the addition -- of caching, links, formatting, attributes, extra combinators, callbaks -- and modifiers. The interaction with the user is stateful. In the same -- computation there may be many request-response interactions, in the -- same way than in the case of a console applications. -- -- -- -- Therefore, session and state management is simple and transparent: it -- is in the haskell structures in the scope of the computation. -- transient (normal) procedures have no persistent session state -- and stateless procedures accept a single request and return a -- single response. -- -- step is a lifting monad transformer that permit persistent -- server procedures that remember the execution state even after system -- shutdowns by using the package workflow -- (http://hackage.haskell.org/package/Workflow) internally. This -- state management is transparent. There is no programer interface for -- session management. -- -- The programmer set the process timeout and the session timeout with -- setTimeouts. If the procedure has been stopped due to the -- process timeout or due to a system shutdowm, the procedure restart in -- the last state when a request for this procedure arrives (if the -- procedure uses the step monad transformer) -- -- -- -- The correctness of the web responses is assured by the use of -- formLets. But unlike formLets in its current form, it permits the -- definition of widgets. A widget is a combination of formLets and -- links within its own formatting template, all in the same -- definition in the same source file, in plain declarative Haskell -- style. -- -- The formatting is abstract. It has to implement the FormInput -- class. There are instances for Text.XHtml (MFlow.Forms.XHtml), -- Haskell Server Pages (MFlow.Forms.HSP) and ByteString. So -- widgets can use any formatting that is instance of FormInput. -- It is possible to use more than one format in the same widget. -- -- Links defined with wlink are treated the same way than forms. -- They are type safe and return values to the same flow of execution. It -- is posssible to combine links and forms in the same widget by using -- applicative combinators but also additional applicative combinators -- like <+> !*> , |*|. Widgets are also monoids, so they can be -- combined as such. -- -- -- -- -- -- -- -- -- -- Example: -- --
--   ask $ wform userloginform `validate` valdateProc `waction` loginProc `wmodify` hideIfLogged
--   
-- -- module MFlow.Forms -- | the FlowM monad executes the page navigation. It perform backtracking -- when necessary to syncronize when the user press the back button or -- when the user enter an arbitrary URL. The instruction pointer is moved -- to the right position within the procedure to handle the request. -- -- However this is transparent to the programmer, who codify in the style -- of a console application. data FlowM v m a -- | View v m a is a widget (formlet) with formatting v -- running the monad m (usually IO) and which return a -- value of type a -- -- It has Applicative, Alternative and Monad -- instances. -- -- Things to know about these instances: -- -- If the View expression does not validate, ask will present the page -- again. -- -- Alternative instance: Both alternatives are executed. The rest -- is as usual -- -- Monad Instance: -- -- The rendering of each statement is added to the previous. If you want -- to avoid this, use wcallback -- -- The execution is stopped when the statement has a formlet-widget that -- does not validate. -- -- The monadic code is executed from the beginning each time the page is -- presented or refreshed -- -- use pageFlow if your page has more than one monadic -- computation with dynamic behaviour -- -- use pageFlow to identify each subflow branch of a conditional -- -- For example: -- --
--   pageFlow "myid" $ do
--        r <- formlet1
--        liftIO $ ioaction1 r
--        s <- formlet2
--        liftIO $ ioaction2 s
--        case s of
--         True  -> pageFlow "idtrue" $ do ....
--         False -> paeFlow "idfalse" $ do ...
--        ...
--   
-- -- Here if formlet2 do not validate, ioaction2 is not -- executed. But if formLet1 validates and the page is refreshed -- two times (because formlet2 has failed, see above),then -- ioaction1 is executed two times. newtype View v m a View :: WState v m (FormElm v a) -> View v m a runView :: View v m a -> WState v m (FormElm v a) data FormElm view a FormElm :: [view] -> (Maybe a) -> FormElm view a class (Monoid view, Typeable view) => FormInput view where flink1 verb = flink verb (fromStr verb) foption1 val msel = foption val (fromStr val) msel toByteString :: FormInput view => view -> ByteString toHttpData :: FormInput view => view -> HttpData fromStr :: FormInput view => String -> view fromStrNoEncode :: FormInput view => String -> view ftag :: FormInput view => String -> view -> view inred :: FormInput view => view -> view flink :: FormInput view => String -> view -> view flink1 :: FormInput view => String -> view finput :: FormInput view => Name -> Type -> Value -> Checked -> OnClick -> view ftextarea :: FormInput view => String -> String -> view fselect :: FormInput view => String -> view -> view foption :: FormInput view => String -> view -> Bool -> view foption1 :: FormInput view => String -> Bool -> view formAction :: FormInput view => String -> view -> view attrs :: FormInput view => view -> Attribs -> view -- | Register an user/password userRegister :: MonadIO m => String -> String -> m (DBRef User) -- | Authentication against userRegistered users. to be used with -- validate userValidate :: (FormInput view, MonadIO m) => (UserStr, PasswdStr) -> m (Maybe view) -- | Wether the user is logged or is anonymous isLogged :: MonadState (MFlowState v) m => m Bool setAdminUser :: MonadIO m => UserStr -> PasswdStr -> m () getAdminName :: MonadIO m => m UserStr getCurrentUser :: MonadState (MFlowState view) m => m String -- | If not logged, perform login. otherwise return the user -- --
--   getUserSimple= getUser Nothing userFormLine
--   
getUserSimple :: (FormInput view, Typeable view) => FlowM view IO String -- | Very basic user authentication. The user is stored in a cookie. it -- looks for the cookie. If no cookie, it ask to the user for a -- userRegistered user-password combination. The user-password -- combination is only asked if the user has not logged already -- otherwise, the stored username is returned. -- --
--   getUser mu form= ask $ userWidget mu form
--   
getUser :: (FormInput view, Typeable view) => Maybe String -> View view IO (Maybe (UserStr, PasswdStr), Maybe String) -> FlowM view IO String -- | Is an example of login/register validation form needed by -- userWidget. In this case the form field appears in a single -- line. it shows, in sequence, entries for the username, password, a -- button for loging, a entry to repeat password necesary for registering -- and a button for registering. The user can build its own user -- login/validation forms by modifying this example -- --
--   userFormLine=
--       (User <$> getString (Just "enter user") <*> getPassword <+> submitButton "login")
--       <+> fromStr "  password again" +> getPassword <* submitButton "register"
--   
userFormLine :: (FormInput view, Functor m, Monad m) => View view m (Maybe (UserStr, PasswdStr), Maybe PasswdStr) -- | Example of user/password form (no validation) to be used with -- userWidget userLogin :: (FormInput view, Functor m, Monad m) => View view m (Maybe (UserStr, PasswdStr), Maybe String) -- | logout. The user is reset to the anonymous user logout :: (MonadIO m, MonadState (MFlowState view) m) => m () -- | It creates a widget for user login/registering. If a user name is -- specified in the first parameter, it is forced to login/password as -- this specific user. If this user was already logged, the widget return -- the user without asking. If the user press the register button, the -- new user-password is registered and the user logged. userWidget :: (MonadIO m, Functor m, FormInput view) => Maybe String -> View view m (Maybe (UserStr, PasswdStr), Maybe String) -> View view m String -- | Return the user language. Now it is fixed to en getLang :: MonadState (MFlowState view) m => m String -- | change the user -- -- It is supposed that the user has been validated login :: (MonadIO m, MonadState (MFlowState view) m) => String -> m () userName :: User -> String ask :: FormInput view => View view IO a -> FlowM view IO a -- | A synonym of ask. -- -- Maybe more appropiate for pages with long interactions with the user -- while the result has little importance. page :: FormInput view => View view IO a -> FlowM view IO a -- | for compatibility with the same procedure in askt. This is the -- non testing version -- --
--   askt v w= ask w
--   
-- -- hide one or the other askt :: FormInput v => (Int -> a) -> View v IO a -> FlowM v IO a -- | Clears the environment clearEnv :: MonadState (MFlowState view) m => m () -- | Creates a stateless flow (see stateless) whose behaviour is -- defined as a widget. It is a higuer level form of the latter wstateless :: (Typeable view, FormInput view) => View view IO a -> Flow -- | transfer control to another flow. transfer :: MonadIO m => String -> FlowM v m () pageFlow :: (Monad m, Functor m, FormInput view) => String -> View view m a -> View view m a -- | Display a text box and return a non empty String getString :: (FormInput view, Monad m) => Maybe String -> View view m String -- | Display a text box and return a Int (if the value entered is not an -- Int, fails the validation) getInt :: (FormInput view, MonadIO m) => Maybe Int -> View view m Int -- | Display a text box and return an Integer (if the value entered is not -- an Integer, fails the validation) getInteger :: (FormInput view, MonadIO m) => Maybe Integer -> View view m Integer getTextBox :: (FormInput view, Monad m, Typeable a, Show a, Read a) => Maybe a -> View view m a -- | Display a multiline text box and return its content getMultilineText :: (FormInput view, Monad m) => String -> View view m String -- | Display a dropdown box with the two values (second (true) and third -- parameter(false)) . With the value of the first parameter selected. getBool :: (FormInput view, Monad m, Functor m) => Bool -> String -> String -> View view m Bool -- | Display a dropdown box with the options in the first parameter is -- optionally selected . It returns the selected option. getSelect :: (FormInput view, Monad m, Typeable a, Read a) => View view m (MFOption a) -> View view m a -- | Set the option for getSelect. Options are concatenated with -- <|> setOption :: (Monad m, Show a, Eq a, Typeable a, FormInput view) => a -> view -> View view m (MFOption a) -- | Set the selected option for getSelect. Options are concatenated with -- <|> setSelectedOption :: (Monad m, Show a, Eq a, Typeable a, FormInput view) => a -> view -> View view m (MFOption a) -- | Display a password box getPassword :: (FormInput view, Monad m) => View view m String -- | encloses a set of Radio boxes. Return the option selected getRadio :: (Monad m, Functor m, FormInput view) => [String -> View view m (Radio a)] -> View view m a -- | Implement a radio button the parameter is the name of the radio group setRadio :: (FormInput view, MonadIO m, Read a, Typeable a, Eq a, Show a) => a -> String -> View view m (Radio a) -- | Implement a radio button that perform a submit when pressed. the -- parameter is the name of the radio group setRadioActive :: (FormInput view, MonadIO m, Read a, Typeable a, Eq a, Show a) => a -> String -> View view m (Radio a) wlabel :: (Monad m, FormInput view) => view -> View view m a -> View view m a getCheckBoxes :: (FormInput view, Monad m) => View view m CheckBoxes -> View view m [String] -- | Read the checkboxes dinamically created by JavaScript within the view -- parameter see for example selectAutocomplete in -- MFlow.Forms.Widgets genCheckBoxes :: (Monad m, FormInput view) => view -> View view m CheckBoxes -- | Display a text box and return the value entered if it is readable( -- Otherwise, fail the validation) setCheckBox :: (FormInput view, MonadIO m) => Bool -> String -> View view m CheckBoxes submitButton :: (FormInput view, Monad m) => String -> View view m String resetButton :: (FormInput view, Monad m) => String -> View view m () whidden :: (Monad m, FormInput v, Read a, Show a, Typeable a) => a -> View v m a -- | Creates a link wiget. A link can be composed with other widget -- elements, wlink :: (Typeable a, Show a, MonadIO m, FormInput view) => a -> view -> View view m a -- | When some user interface int return some response to the server, but -- it is not produced by a form or a link, but for example by an script, -- returning notify the type checker. -- -- At runtime the parameter is read from the environment and validated. -- -- . The parameter is the visualization code, that accept a serialization -- function that generate the server invocation string, used by the -- visualization to return the value by means of a link or a -- window.location statement in javasCript returning :: (Typeable a, Read a, Show a, Monad m, FormInput view) => ((a -> String) -> view) -> View view m a -- | Wrap a widget with form element within a form-action element. Usually -- this is not necessary since this wrapping is done automatically by the -- Wiew monad, unless there are more than one form in the page. wform :: (Monad m, FormInput view) => View view m b -> View view m b -- | Concat a list of widgets of the same type, return a the first -- validated result firstOf :: (Monoid view, Monad m, Functor m) => [View view m a] -> View view m a -- | from a list of widgets, it return the validated ones. manyOf :: (FormInput view, MonadIO m, Functor m) => [View view m a] -> View view m [a] -- | Render raw view formatting. It is useful for displaying information wraw :: Monad m => view -> View view m () -- | Render a Show-able value and return it wrender :: (Monad m, Functor m, Show a, FormInput view) => a -> View view m a notValid :: Monad m => view -> View view m a -- | Validates a form or widget result against a validating procedure -- --
--   getOdd= getInt Nothing validate (x -> return $ if mod x 2==0 then  Nothing else Just only odd numbers, please)
--   
validate :: (FormInput view, Monad m) => View view m a -> (a -> WState view m (Maybe view)) -> View view m a -- | Empty widget that return Nothing. May be used as "empty boxes" inside -- larger widgets noWidget :: (FormInput view, Monad m) => View view m a -- | Actions are callbacks that are executed when a widget is validated. A -- action may be a complete flow in the flowM monad. It takes complete -- control of the navigation while it is executed. At the end it return -- the result to the caller and display the original calling page. It is -- useful when the widget is inside widget containers that may treat it -- as a black box. -- -- It returns a result that can be significative or, else, be ignored -- with <** and **>. An action may or may not -- initiate his own dialog with the user via ask waction :: (FormInput view, Monad m) => View view m a -> (a -> FlowM view m b) -> View view m b -- | It is a callback in the view monad. The callback rendering substitutes -- the widget rendering when the latter is validated, without afecting -- the rendering of other widgets. This allow the simultaneous execution -- of different behaviours in different widgets simultaneously in the -- same page. The inspiration is the callback primitive in the Seaside -- Web Framework that allows similar functionality (See -- http://www.seaside.st) -- -- This is the visible difference with waction callbacks, which -- execute a a flow in the FlowM monad that takes complete control of the -- navigation, while wactions are executed whithin the same ask -- statement. wcallback :: Monad m => View view m a -> (a -> View view m b) -> View view m b wmodify :: (Monad m, FormInput v) => View v m a -> ([v] -> Maybe a -> WState v m ([v], Maybe b)) -> View v m b -- | Cached widgets operate with widgets in the Identity monad, but they -- may perform IO using the execute instance of the monad m, which is -- usually the IO monad. execute basically "sanctifies" the use of -- unsafePerformIO for a transient purpose such is caching. This is -- defined in Data.TCache.Memoization. The programmer can create -- his own instance for his monad. -- -- With cachedWidget it is possible to cache the rendering of a -- widget as a ByteString (maintaining type safety) , permanently or for -- a certain time. this is very useful for complex widgets that present -- information. Specially it they must access to databases. -- --
--   import MFlow.Wai.XHtm.All
--   import Some.Time.Library
--   addMessageFlows [(noscript, time)]
--   main= run 80 waiMessageFlow
--   time=do  ask $ cachedWidget "time" 5
--              $ wlink () bold << "the time is " ++ show (execute giveTheTime) ++ " click here"
--            time
--   
-- -- this pseudocode would update the time every 5 seconds. The execution -- of the IO computation giveTheTime must be executed inside the cached -- widget to avoid unnecesary IO executions. -- -- NOTE: cached widgets are shared by all users cachedWidget :: (MonadIO m, Typeable view, FormInput view, Typeable a, Executable m) => String -> Int -> View view Identity a -> View view m a -- | A shorter name for cachedWidget wcached :: (MonadIO m, Typeable view, FormInput view, Typeable a, Executable m) => String -> Int -> View view Identity a -> View view m a -- | Unlike cachedWidget, which cache the rendering but not the user -- response, wfreeze cache also the user response. This is -- useful for pseudo-widgets which just show information while the -- controls are in other non freezed widgets. A freezed widget ever -- return the first user response It is faster than cachedWidget. -- It is not restricted to the Identity monad. -- -- NOTE: cached widgets are shared by all users wfreeze :: (MonadIO m, Typeable view, FormInput view, Typeable a, Executable m) => String -> Int -> View view m a -> View view m a -- | Join two widgets in the same page the resulting widget, when -- asked with it, return a 2 tuple of their validation results if -- both return Noting, the widget return Nothing (invalid). -- -- it has a low infix priority: infixr 2 -- --
--   r <- ask  widget1 <+>  widget2
--   case r of (Just x, Nothing) -> ..
--   
(<+>) :: Monad m => View view m a -> View view m b -> View view m (Maybe a, Maybe b) -- | Intersperse a widget in a list of widgets. the results is a 2-tuple of -- both types. -- -- it has a infix priority infixr 5 (|*>) :: (MonadIO m, Functor m, Monoid view) => View view m r -> [View view m r'] -> View view m (Maybe r, Maybe r') -- | Put a widget before and after other. Useful for navigation links in a -- page that appears at toAdd and at the bottom of a page. (|+|) :: (Functor m, Monoid view, MonadIO m) => View view m r -> View view m r' -> View view m (Maybe r, Maybe r') -- | The first elem result (even if it is not validated) is discarded, and -- the secod is returned . This contrast with the applicative operator -- *> which fails the whole validation if the validation of the -- first elem fails. -- -- The first element is displayed however, as happens in the case of -- *> . -- -- Here w's are widgets and r's are returned values -- -- (w1 <* w2) will return Just r1 only if w1 and w2 -- are validated -- -- (w1 <** w2) will return Just r1 even if w2 is not -- validated -- -- it has a low infix priority: infixr 1 (**>) :: (Functor m, Monad m) => View view m a -> View view m b -> View view m b -- | The second elem result (even if it is not validated) is discarded, and -- the first is returned . This contrast with the applicative operator -- *> which fails the whole validation if the validation of the -- second elem fails. The second element is displayed however, as in the -- case of <*. see the <** examples -- -- it has a low infix priority: infixr 1 (<**) :: (Functor m, Monad m) => View view m a -> View view m b -> View view m a -- | An associative binary operation (<|>) :: Alternative f => forall a. f a -> f a -> f a -- | Sequence actions, discarding the value of the second argument. (<*) :: Applicative f => forall a b. f a -> f b -> f a -- | An infix synonym for fmap. (<$>) :: Functor f => (a -> b) -> f a -> f b -- | Sequential application. (<*>) :: Applicative f => forall a b. f (a -> b) -> f a -> f b (>:>) :: Monad m => View v m a -> View v m [a] -> View v m [a] -- |
--   (.<+>.) x y = normalize x <+> normalize y
--   
(.<+>.) :: (Monad m, FormInput v, FormInput v1) => View v m a -> View v1 m b -> View ByteString m (Maybe a, Maybe b) -- |
--   (.|*>.) x y = normalize x |*> map normalize y
--   
(.|*>.) :: (Functor m, MonadIO m, FormInput v, FormInput v1) => View v m r -> [View v1 m r'] -> View ByteString m (Maybe r, Maybe r') -- |
--   (.|+|.) x y = normalize x |+| normalize y
--   
(.|+|.) :: (Functor m, MonadIO m, FormInput v, FormInput v1) => View v m r -> View v1 m r' -> View ByteString m (Maybe r, Maybe r') -- |
--   (.**>.) x y = normalize x **> normalize y
--   
(.**>.) :: (Monad m, Functor m, FormInput v, FormInput v1) => View v m a -> View v1 m b -> View ByteString m b -- |
--   (.<**.) x y = normalize x <** normalize y
--   
(.<**.) :: (Monad m, Functor m, FormInput v, FormInput v1) => View v m a -> View v1 m b -> View ByteString m a -- |
--   (.<|>.) x y= normalize x <|> normalize y
--   
(.<|>.) :: (Monad m, Functor m, FormInput v, FormInput v1) => View v m a -> View v1 m a -> View ByteString m a -- | Enclose Widgets within some formating. view is intended to be -- instantiated to a particular format -- -- NOTE: It has a infix priority : infixr 5 less than the one of -- ++> and <++ of the operators, so use -- parentheses when appropriate, unless the we want to enclose all the -- widgets in the right side. Most of the type errors in the DSL are due -- to the low priority of this operator. -- -- This is a widget, which is a table with some links. it returns an Int -- --
--   import MFlow.Forms.Blaze.Html
--   
--   tableLinks :: View Html Int
--   table ! At.style "border:1;width:20%;margin-left:auto;margin-right:auto"
--              <<< caption << text "choose an item"
--              ++> thead << tr << ( th << b << text  "item" <> th << b << text "times chosen")
--              ++> (tbody
--                   <<< tr ! rowspan "2" << td << linkHome
--                   ++> (tr <<< td <<< wlink  IPhone (b << text "iphone") <++  td << ( b << text (fromString $ show ( cart V.! 0)))
--                   <|>  tr <<< td <<< wlink  IPod (b << text "ipad")     <++  td << ( b << text (fromString $ show ( cart V.! 1)))
--                   <|>  tr <<< td <<< wlink  IPad (b << text "ipod")     <++  td << ( b << text (fromString $ show ( cart V.! 2))))
--                   )
--   
(<<<) :: (Monad m, Monoid view) => (view -> view) -> View view m a -> View view m a -- | Prepend formatting code to a widget -- --
--   bold "enter name" ++ getString Nothing
--   
-- -- It has a infix prority: infixr 6 higuer that -- <<< and most other operators (++>) :: (Monad m, Monoid view) => view -> View view m a -> View view m a -- | Append formatting code to a widget -- --
--   getString hi <++ H1 << hi there
--   
-- -- It has a infix prority: infixr 6 higuer that -- <<< and most other operators (<++) :: Monad m => View v m a -> v -> View v m a -- | Add attributes to the topmost tag of a widget -- -- it has a fixity infix 8 ( View view m a -> Attribs -> View view m a -- |
--   (.<<.) w x = w $ toByteString x
--   
(.<<.) :: FormInput view => (ByteString -> ByteString) -> view -> ByteString -- |
--   (.<++.) x v= normalize x <++ toByteString v
--   
(.<++.) :: (Monad m, FormInput v, FormInput v') => View v m a -> v' -> View ByteString m a -- |
--   (.++>.) v x= toByteString v ++> normalize x
--   
(.++>.) :: (Monad m, FormInput v, FormInput v') => v -> View v' m a -> View ByteString m a -- | Writes a XML tag in a ByteString. It is the most basic form of -- formatting. For more sophisticated formatting , use -- MFlow.Forms.XHtml or MFlow.Forms.HSP. btag :: String -> Attribs -> ByteString -> ByteString -- |
--   bhtml ats v= btag "html" ats v
--   
bhtml :: Attribs -> ByteString -> ByteString -- |
--   bbody ats v= btag "body" ats v
--   
bbody :: Attribs -> ByteString -> ByteString -- | Flatten a binary tree of tuples of Maybe results produced by the -- <+> operator into a single tuple with the same elements in the -- same order. This is useful for easing matching. For example: -- --
--   res <- ask $ wlink1 <+> wlink2 wform <+> wlink3 <+> wlink4
--   
-- -- res has type: -- --
--   Maybe (Maybe (Maybe (Maybe (Maybe a,Maybe b),Maybe c),Maybe d),Maybe e)
--   
-- -- but flatten res has type: -- --
--   (Maybe a, Maybe b, Maybe c, Maybe d, Maybe e)
--   
flatten :: Flatten (Maybe tree) list => tree -> list normalize :: (Monad m, FormInput v) => View v m a -> View ByteString m a -- | Execute the Flow, in the FlowM view m monad. It is used as -- parameter of hackMessageFlow waiMessageFlow or -- addMessageFlows -- -- The flow is executed in a loop. When the flow is finished, it is -- started again -- --
--   main= do
--      addMessageFlows [("noscript",transient $ runFlow mainf)]
--      forkIO . run 80 $ waiMessageFlow
--      adminLoop
--   
runFlow :: (FormInput view, MonadIO m) => FlowM view m () -> Token -> m () -- | to execute transient flows as if they were persistent -- --
--   transient $ runFlow f === runFlow $ transientNav f
--   
transientNav :: (Serialize a, Typeable view, FormInput view, Typeable a) => FlowM view IO a -> FlowM view (Workflow IO) a runFlowOnce :: (FormInput view, Monad m) => FlowM view m () -> Token -> m () -- | Run a persistent flow inside the current flow. It is identified by the -- procedure and the string identifier. unlike the normal flows, that are -- infinite loops, runFlowIn executes a finite flow once executed, in -- subsequent executions the flow will return the stored result without -- asking again. This is useful for askingstoringretrieving user -- defined configurations. runFlowIn :: (MonadIO m, FormInput view) => String -> FlowM view (Workflow IO) b -> FlowM view m b -- | to unlift a FlowM computation. useful for executing the configuration -- generated by runFLowIn outside of a web application runFlowConf :: (FormInput view, MonadIO m) => FlowM view m a -> m a step :: (Serialize a, Typeable view, FormInput view, MonadIO m, Typeable a) => FlowM view m a -> FlowM view (Workflow m) a -- | True if the flow is going back (as a result of the back button pressed -- in the web browser). Usually this check is nos necessary unless -- conditional code make it necessary -- --
--   menu= do
--          mop <- getGoStraighTo
--          case mop of
--           Just goop -> goop
--           Nothing -> do
--                  r <- ask option1 <|> option2
--                  case r of
--                   op1 -> setGoStraighTo (Just goop1) >> goop1
--                   op2 -> setGoStraighTo (Just goop2) >> goop2
--   
-- -- This pseudocode below would execute the ask of the menu once. But the -- user will never have the possibility to see the menu again. To let him -- choose other option, the code has to be change to -- --
--   menu= do
--          mop <- getGoStraighTo
--          back <- goingBack
--          case (mop,back) of
--           (Just goop,False) -> goop
--           _ -> do
--                  r <- ask option1 <|> option2
--                  case r of
--                   op1 -> setGoStraighTo (Just goop1) >> goop1
--                   op2 -> setGoStraighTo (Just goop2) >> goop2
--   
-- -- However this is very specialized. Normally the back button detection -- is not necessary. In a persistent flow (with step) even this default -- entry option would be completely automatic, since the process would -- restar at the last page visited. No setting is necessary. goingBack :: (MonadIO m, MonadState (MFlowState view) m) => m Bool -- | Use this instead of return to return from a computation with ask -- statements -- -- This way when the user press the back button, the computation will -- execute back, to the returned code, according with the user -- navigation. breturn :: Monad m => a -> FlowM v m a -- | Will prevent the backtrack beyond the point where -- preventGoingBack is located. If the user press the back button -- beyond that point, the flow parameter is executed, usually it is an -- ask statement with a message. If the flow is not going back, it does -- nothing. It is a cut in backtracking -- -- It is useful when an undoable transaction has been commited. For -- example, after a payment. -- -- This example show a message when the user go back and press again to -- pay -- --
--   ask $ wlink () << b << "press here to pay 100000 $ "
--   payIt
--   preventGoingBack . ask $   b << "You  paid 10000 $ one time"
--                          ++> wlink () << b << " Please press here to complete the proccess"
--   ask $ wlink () << b << "OK, press here to go to the menu or press the back button to verify that you can not pay again"
--   where
--   payIt= liftIO $ print "paying"
--   
preventGoingBack :: (Functor m, MonadIO m, FormInput v) => FlowM v m () -> FlowM v m () -- | Set the header-footer that will enclose the widgets. It must be -- provided in the same formatting than them, altrough with normalization -- to byteStrings any formatting can be used -- -- This header uses XML trough Haskell Server Pages -- (http://hackage.haskell.org/package/hsp) -- --
--   setHeader $ c ->
--              <html>
--                   <head>
--                        <title>  my title </title>
--                        <meta name= "Keywords" content= "sci-fi" />)
--                   </head>
--                    <body style= "margin-left:5%;margin-right:5%">
--                         <% c %>
--                    </body>
--              </html>
--   
-- -- This header uses Text.XHtml -- --
--   setHeader $ c ->
--             thehtml
--                 << (header
--                     << (thetitle << title +++
--                         meta ! [name "Keywords",content "sci-fi"])) +++
--                    body ! [style "margin-left:5%;margin-right:5%"] c
--   
-- -- This header uses both. It uses byteString tags -- --
--   setHeader $ c ->
--            bhtml [] $
--                 btag head [] $
--                       (toByteString (thetitle << title) append
--                       toByteString name= \"Keywords\" content= \"sci-fi\" /) append
--                    bbody [("style", "margin-left:5%;margin-right:5%")] c
--   
setHeader :: MonadState (MFlowState view) m => (view -> view) -> m () -- | Set user-defined data in the context of the session. -- -- The data is indexed by type in a map. So the user can insert-retrieve -- different kinds of data in the session context. -- -- This example define addHistory and getHistory to -- maintain a Html log in the session of a Flow: -- --
--   newtype History = History ( Html) deriving Typeable
--   setHistory html= setSessionData $ History html
--   getHistory= getSessionData `onNothing` return (History mempty) >>= \(History h) -> return h
--   addHistory html= do
--        html' <- getHistory
--        setHistory $ html' `mappend` html
--   
setSessionData :: (Typeable a, MonadState (MFlowState view) m) => a -> m () -- | Get the session data of the desired type if there is any. getSessionData :: (Typeable a, MonadState (MFlowState view) m) => m (Maybe a) -- | Return the current header getHeader :: Monad m => FlowM view m (view -> view) -- | Set 1) the timeout of the flow execution since the last user -- interaction. Once passed, the flow executes from the begining. 2). In -- persistent flows it set the session state timeout for the flow, that -- is persistent. If the flow is not persistent, it has no effect. -- -- transient flows restart anew. persistent flows (that use -- step) restart at the las saved execution point, unless the -- session time has expired for the user. setTimeouts :: Monad m => Int -> Integer -> FlowM view m () -- | Set an HTTP cookie setCookie :: MonadState (MFlowState view) m => String -> String -> String -> Maybe Integer -> m () -- | Install the server code and return the client code for an AJAX -- interaction. -- -- This example increases the value of a text box each time the box is -- clicked -- --
--   ask $ do
--         let elemval= "document.getElementById('text1').value"
--         ajaxc <- ajax $ \n -> return $ elemval <> "='" <> B.pack(show(read  n +1)) <> "'"
--         b <<  text "click the box"
--           ++> getInt (Just 0) <! [("id","text1"),("onclick", ajaxc elemval)]
--   
ajax :: MonadIO m => (String -> View v m ByteString) -> View v m (String -> String) -- | Send the javascript expression, generated by the procedure parameter -- as a ByteString, execute it in the browser and the result is returned -- back -- -- The ajaxSend invocation must be inside a ajax procedure or -- else a No ajax session set error will be produced ajaxSend :: (Read a, MonadIO m) => View v m ByteString -> View v m a -- | Like ajaxSend but the result is ignored ajaxSend_ :: MonadIO m => View v m ByteString -> View v m () class Requirements a installRequirements :: (Requirements a, Monad m, FormInput view) => [a] -> m view data WebRequirement -- | Script URL and the list of scripts to be executed when loaded JScriptFile :: String -> [String] -> WebRequirement -- | a CSS file URL CSSFile :: String -> WebRequirement -- | a String with a CSS description CSS :: String -> WebRequirement -- | a string with a valid JavaScript JScript :: String -> WebRequirement -- | a server procedure ServerProc :: (String, Flow) -> WebRequirement -- | Requirements are javascripts, Stylesheets or server processes (or any -- instance of the Requirement class) that are included in the Web -- page or in the server when a widget specifies this. requires -- is the procedure to be called with the list of requirements. Varios -- widgets in the page can require the same element, MFlow will install -- it once. requires :: (Typeable a, MonadState (MFlowState view) m, Requirements a) => [a] -> m () -- | Generate a new string. Useful for creating tag identifiers and other -- attributes genNewId :: MonadState (MFlowState view) m => m String -- | Execute the widget in a monad and return the result in another. changeMonad :: (Monad m, Executable m1) => View v m1 a -> View v m a data FailBack a fromFailBack :: FailBack t -> t toFailBack :: a -> FailBack a data MFlowState view instance [incoherent] Typeable1 MFOption instance [incoherent] Typeable AjaxSessionId instance [incoherent] FormInput ByteString instance [incoherent] Flatten (Tuple6 a b c d e f) (Maybe a, Maybe b, Maybe c, Maybe d, Maybe e, Maybe f) instance [incoherent] Flatten (Tuple5 a b c d e) (Maybe a, Maybe b, Maybe c, Maybe d, Maybe e) instance [incoherent] Flatten (Tuple4 a b c d) (Maybe a, Maybe b, Maybe c, Maybe d) instance [incoherent] Flatten (Tuple3 a b c) (Maybe a, Maybe b, Maybe c) instance [incoherent] Flatten (Tuple2 a b) (Maybe a, Maybe b) instance [incoherent] (Monad m, Functor m) => Monoid (View view m (MFOption a)) instance [incoherent] Monoid CheckBoxes -- | Instantiation of the FormInput class for blaze-html -- http://hackage.haskell.org/package/blaze-html -- -- This package is included in MFlow.Wai.Blaze.Hml.All. -- -- Use it to create applicaitons with this kind of formatting. module MFlow.Forms.Blaze.Html -- | used to insert html elements within a tag with the appropriate infix -- priority for the other operators used in MFlow. Also it can be used -- for adding markup to widgets with this signature such are wlink -- ad setOption (<<) :: ToMarkup a => (Markup -> t) -> a -> t instance FormInput Html -- | Instances of FormInput for the XHtml module of the xhtml -- package module MFlow.Forms.XHtml instance Typeable Html instance FormInput Html instance Monad m => ADDATTRS (View Html m a) module MFlow.Forms.Admin -- | A small console interpreter with some commands: -- -- -- -- on exception, for example Control-c, it sync and exits. It must be -- used as the last statement of the main procedure. adminLoop :: IO () -- | execute the process and wait for its finalization. then it -- synchronizes the cache wait :: IO a -> IO Bool -- | Install the admin flow in the list of flows handled by -- HackMessageFlow this gives access to an administrator page. -- It is necessary to create an admin user with setAdminUser. -- -- The administration page is reached with the path "adminserv" addAdminWF :: IO () -- | Some dynamic widgets, widgets that dynamically edit content in other -- widgets, widgets for templating, content management and multilanguage. -- And some primitives to create other active widgets. module MFlow.Forms.Widgets -- | present the JQuery datepicker calendar to choose a date. The second -- parameter is the configuration. Use "()" by default. See -- http:jqueryui.comdatepicker datePicker :: (Monad m, FormInput v) => String -> Maybe String -> View v m (Int, Int, Int) -- | show the jQuery spinner widget. the first parameter is the -- configuration . Use "()" by default. See -- http:jqueryui.com/spinner getSpinner :: (MonadIO m, Read a, Show a, Typeable a, FormInput view) => String -> Maybe a -> View view m a -- | Present the JQuery autocompletion list, from a procedure defined by -- the programmer, to a text box. wautocomplete :: (Show a, MonadIO m, FormInput v) => Maybe String -> (String -> IO a) -> View v m String wdialog :: (Monad m, FormInput v) => String -> String -> View v m a -> View v m a -- | Present a user form if not logged in. Otherwise, the user name and a -- logout link is presented. The paremeters and the behaviour are the -- same as userWidget. Only the display is different userFormOrName :: (Functor m, MonadIO m, FormInput view) => Maybe String -> View view m (Maybe (UserStr, PasswdStr), Maybe String) -> View view m String -- | Display a logout link if the user is logged. Nothing otherwise maybeLogout :: (MonadIO m, Functor m, FormInput v) => View v m () -- | Inside a tag, it add and delete widgets of the same type. When the -- form is submitted or a wlink is pressed, this widget return the list -- of validated widgets. the event for adding a new widget is attached , -- as a click event to the element of the page with the identifier -- wEditListAdd that the user will choose. -- -- This example add or delete editable text boxes, with two initial boxes -- with hi, how are you as values. Tt uses blaze-html: wEditList :: (Typeable a, Read a, FormInput view, Functor m, MonadIO m, Executable m) => (view -> view) -> (Maybe String -> View view Identity a) -> [String] -> String -> View view m [a] -- | A specialization of selectAutocompleteEdit which make appear -- each option choosen with a checkbox that deletes the element when -- uncheched. The result, when submitted, is the list of selected -- elements. wautocompleteList :: (Functor m, MonadIO m, Executable m, FormInput v) => String -> (String -> IO [String]) -> [String] -> View v m [String] -- | Produces a text box. It gives a autocompletion list to the textbox. -- When return is pressed in the textbox, the box content is used to -- create a widget of a kind defined by the user, which will be situated -- above of the textbox. When submitted, the result of this widget is the -- content of the created widgets (the validated ones). -- -- wautocompleteList is an specialization of this widget, where -- the widget parameter is fixed, with a checkbox that delete the -- eleement when unselected . This fixed widget is as such (using generic -- FormElem class tags): -- --
--   ftag "div"    <<< ftag "input" mempty
--                                 `attrs` [("type","checkbox")
--                                         ,("checked","")
--                                         ,("onclick","this.parentNode.parentNode.removeChild(this.parentNode)")]
--                 ++> ftag "span" (fromStr $ fromJust x )
--                 ++> whidden( fromJust x)
--   
wautocompleteEdit :: (Typeable a, MonadIO m, Functor m, Executable m, FormInput v) => String -> (String -> IO [String]) -> (Maybe String -> View v Identity a) -> [String] -> View v m [a] -- | Deletes the list of edited widgets for a certain identifier and with -- the type of the witness widget parameter delEdited :: (Typeable v, Typeable a, MonadIO m, MonadState (MFlowState view) m) => ByteString -> [View v m1 a] -> m () -- | Return the list of edited widgets (added by the active widgets) for a -- given identifier getEdited :: (Typeable v, Typeable a, MonadState (MFlowState view) m) => ByteString -> m [View v m1 a] -- | Return the javascript to be executed on the browser to prepend a -- widget to the location identified by the selector (the bytestring -- parameter), The selector must have the form of a jquery expression . -- It stores the added widgets in the edited list, that is accessed with -- getEdited -- -- The resulting string can be executed in the browser. ajax will -- return the code to execute the complete ajax roundtrip. This code -- returned by ajax must be in an eventhabdler. -- -- This example will insert a widget in the div when the element with -- identifier clickelem is clicked. when the form is sbmitted, the -- widget values are returned and the list of edited widgets are deleted. -- --
--   id1<- genNewId
--   let sel= "$('#" <>  B.pack id1 <> "')"
--   callAjax <- ajax . const $ prependWidget sel wn
--   let installevents= "$(document).ready(function(){\
--             \$('#clickelem').click(function(){"++callAjax "''"++"});})"
--   
--   requires [JScriptFile jqueryScript [installevents] ]
--   ws <- getEdited sel
--   r <-  (div <<< manyOf ws) <! [("id",id1)]
--   delEdited sel ws'
--   return  r
--   
prependWidget :: (Typeable a, MonadIO m, Executable m, FormInput v) => ByteString -> View v Identity a -> View v m ByteString -- | Like prependWidget but append the widget instead of prepend. appendWidget :: (Typeable a, MonadIO m, Executable m, FormInput v) => ByteString -> View v Identity a -> View v m ByteString -- | L ike prependWidget but set the entire content of the selector -- instead of prepending an element setWidget :: (Typeable a, MonadIO m, Executable m, FormInput v) => ByteString -> View v Identity a -> View v m ByteString -- | Read the field value and present it without edition. tField :: (MonadIO m, Functor m, Executable m, FormInput v) => Key -> View v m () -- | A widget that display the content of an html, But if logged as -- administrator, it permits to edit it in place. So the editor could see -- the final appearance of what he write in the page. -- -- When the administrator double click in the paragraph, the content is -- saved and identified by the key. Then, from now on, all the users will -- see the saved content instead of the code content. -- -- The content is saved in a file by default (texts in this -- versions), but there is a configurable version (tFieldGen). The -- content of the element and the formatting is cached in memory, so the -- display is, theoretically, very fast. -- -- THis is an example of how to use the content management primitives (in -- demos.blaze.hs): -- --
--   textEdit= do
--     setHeader $ \t -> html << body << t
--   
--     let first=  p << i <<
--                    (El.span << text "this is a page with"
--                    <> b << text " two " <> El.span << text "paragraphs")
--   
--         second= p << i << text "This is the original text of the second paragraph"
--   
--         pageEditable =  (tFieldEd "first"  first)
--                     **> (tFieldEd "second" second)
--   
--     ask $   first
--         ++> second
--         ++> wlink () (p << text "click here to edit it")
--   
--     ask $ p << text "Please login with admin/admin to edit it"
--             ++> userWidget (Just "admin") userLogin
--   
--     ask $   p << text "now you can click the field and edit them"
--         ++> p << b << text "to save the edited field, double click on it"
--         ++> pageEditable
--         **> wlink () (p << text "click here to see it as a normal user")
--   
--     logout
--   
--     ask $   p << text "the user sees the edited content. He can not edit"
--         ++> pageEditable
--         **> wlink () (p << text "click to continue")
--   
--     ask $   p << text "When text are fixed,the edit facility and the original texts can be removed. The content is indexed by the field key"
--         ++> tField "first"
--         **> tField "second"
--         **> p << text "End of edit field demo" ++> wlink () (p << text "click here to go to menu")
--   
tFieldEd :: (Functor m, MonadIO m, Executable m, FormInput v) => Key -> v -> View v m () -- | Like tFieldEd with user-configurable storage. tFieldGen :: (MonadIO m, Functor m, Executable m, FormInput v) => Key -> (Key -> IO v) -> (Key -> v -> IO ()) -> View v m () -- | A multilanguage version of tFieldEd. For a field with key it -- add a suffix with the two characters of the language used. mFieldEd :: (Functor m, Executable m, MonadIO m, FormInput v) => [Char] -> v -> View v m () -- | A multilanguage version of tField mField :: (Functor m, Executable m, MonadIO m, FormInput v) => [Char] -> View v m () -- | Capture the form submissions and the links of the enclosed widget and -- send them via AJAX. The response is the new presentation of the -- widget, that is updated. No navigation occur. So a widget with -- autoRefresh can be used in heavyweight pages. If AJAX or javascript is -- not available, the widget is refresh normally, via a new page. The -- enclosed widget if has form elements, must include the form action -- tag, not a part of it. For this purpose, autoRefresh encloses the -- widget in a form tag if there are form elements on it and the -- programmer has not enclosed them in a wform element. autoRefresh :: (MonadIO m, FormInput v) => View v m a -> View v m a instance [overlap ok] Indexable TFields instance [overlap ok] (Typeable view, Typeable a) => Typeable (Medit view m a) module MFlow.Wai waiMessageFlow :: Request -> ResourceT IO Response instance Processable Request module MFlow.Wai.Blaze.Html.All -- | run a persistent flow. The port is read from the first exectution -- parameter if no parameter, it is read from the PORT environment -- variable. if this does not exist, the port 80 is used. runNavigation :: String -> FlowM Html (Workflow IO) () -> IO Bool module MFlow.Wai.XHtml.All module MFlow.Forms.Test class Generate a generate :: Generate a => IO a -- | run a list of flows with a number of simultaneous threads runTest :: [(Int, Flow)] -> IO () runTest1 :: (Token -> Workflow IO b) -> IO (Either WFErrors b) -- | inject substitutes an expression by other. It may be used to override -- ask interaction with the user. It should bee used infix for greater -- readability: -- --
--   ask something    `inject` const someother
--   
-- -- The parameter passed is the test number if the flow has not been -- executed by runTest, inject return the original inject :: MonadIO m => m b -> (Int -> b) -> m b -- | a simulated ask that generate simulated user input of the type -- expected. -- -- It forces the web page rendering, since it is monadic and can contain -- side effects and load effects to be tested. -- -- it is a substitute of ask from MFlow.Forms for testing -- purposes. ask :: (Generate a, MonadIO m, Functor m, FormInput v, Typeable v) => View v m a -> FlowM v m a -- | instead of generating a result like ask, the result is given as -- the first parameter so it does not need a Generate instance. -- -- It forces the web page rendering, since it is monadic so it can -- contain side effects and load effects to be tested. askt :: (MonadIO m, FormInput v) => (Int -> a) -> View v m a -> FlowM v m a userWidget :: (MonadIO m, Functor m, FormInput view) => Maybe String -> View view m (Maybe (String, String), Maybe String) -> View view m String getUser :: (FormInput view, Typeable view, MonadIO m, Functor m) => Maybe String -> View view m (Maybe (String, String), Maybe String) -> FlowM view m String getUserSimple :: (FormInput view, Typeable view, MonadIO m, Functor m) => FlowM view m String -- | a pure version of verifyM verify :: a -> (Bool, String) -> a instance [overlap ok] (Bounded a, Enum a) => Generate a instance [overlap ok] (Generate a, Generate b) => Generate (Maybe a, Maybe b) instance [overlap ok] (Generate a, Generate b) => Generate (a, b) instance [overlap ok] Generate Integer instance [overlap ok] Generate Int instance [overlap ok] Generate String instance [overlap ok] Generate a => Generate (Maybe a)