Skip to content

Instantly share code, notes, and snippets.

@chrisbuttery
Forked from danyx23/CustomStartApp.elm
Created March 4, 2016 01:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisbuttery/950fff7a867ab1954cc3 to your computer and use it in GitHub Desktop.
Save chrisbuttery/950fff7a867ab1954cc3 to your computer and use it in GitHub Desktop.
Use ports with customized StartApp and "PortActions"
module CustomStartApp (start, App, Config) where
import Html exposing (Html)
import Effects exposing (Effects, Never)
import Task
type alias Config model action portAction =
{ init : ( model, Effects action, portAction )
, update : action -> model -> ( model, Effects action, Maybe portAction )
, view : Signal.Address action -> model -> Html
, inputs : List (Signal.Signal action)
}
type alias App model portAction =
{ html : Signal Html
, model : Signal model
, tasks : Signal (Task.Task Never ())
, portActions : Signal portAction
}
start : Config model action portAction -> App model portAction
start config =
let
fst3 ( a, _, _ ) =
a
snd3 ( _, b, _ ) =
b
thrd3 ( _, _, c ) =
c
singleton action =
[ action ]
-- messages : Signal.Mailbox (List action)
messages =
Signal.mailbox []
-- address : Signal.Address action
address =
Signal.forwardTo messages.address singleton
-- updateStep : action -> (model, Effects action, Maybe portAction) -> (model, Effects action, Maybe portAction)
updateStep action ( oldModel, accumulatedEffects, _ ) =
let
( newModel, additionalEffects, maybePortAction ) =
config.update action oldModel
in
( newModel, Effects.batch [ accumulatedEffects, additionalEffects ], maybePortAction )
-- update : List action -> (model, Effects action, Maybe portAction) -> (model, Effects action, Maybe portAction)
update actions ( model, _, _ ) =
List.foldl updateStep ( model, Effects.none, Nothing ) actions
-- inputs : Signal (List action)
inputs =
Signal.mergeMany (messages.signal :: List.map (Signal.map singleton) config.inputs)
-- effectsAndModel : Signal (model, Effects action, Maybe portAction)
modelEffectsPortActions =
Signal.foldp update (config.init |> maybefy) inputs
model =
Signal.map fst3 modelEffectsPortActions
tasks =
Signal.map (Effects.toTask messages.address << snd3) modelEffectsPortActions
portActions =
Signal.filterMap identity (config.init |> thrd3) <| Signal.map thrd3 modelEffectsPortActions
in
{ html = Signal.map (config.view address) model
, model = model
, tasks = tasks
, portActions = portActions
}
maybefy : ( model, Effects action, portAction ) -> ( model, Effects action, Maybe portAction )
maybefy ( model, action, portAction ) =
( model, action, Just portAction )
{
"version": "1.0.0",
"summary": "helpful summary of your project, less than 80 characters",
"repository": "https://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"."
],
"exposed-modules": [],
"dependencies": {
"elm-lang/core": "3.0.0 <= v < 4.0.0",
"evancz/elm-effects": "2.0.1 <= v < 3.0.0",
"evancz/elm-html": "4.0.2 <= v < 5.0.0",
"evancz/start-app": "2.0.2 <= v < 3.0.0"
},
"elm-version": "0.16.0 <= v < 0.17.0"
}
module EncryptMessage (..) where
import Html exposing (Html, Attribute, text, toElement, div, input)
import Html.Attributes exposing (..)
import Html.Events exposing (on, targetValue)
import Signal exposing (Address, Signal, Mailbox, mailbox, send)
import CustomStartApp
import Effects exposing (Effects, Never)
import Task
app : CustomStartApp.App Model PortAction
app =
CustomStartApp.start { init = init, view = view, update = update, inputs = [ encryptedString ] }
main : Signal Html
main =
app.html
port tasks : Signal (Task.Task Never ())
port tasks =
app.tasks
type Action
= TextChanged String
| EncryptedValueReceived String
| Noop
type alias Model =
{ clearText : String
, encryptedText : String
}
init : ( Model, Effects Action, PortAction )
init =
( Model "" ""
, Effects.none
, RequestEncryption ""
)
-- outgoing ports & mailbox
type PortAction
= RequestEncryption String
port requestEncryption : Signal String
port requestEncryption =
Signal.map (\(RequestEncryption message) -> message) app.portActions
-- incoming ports
port encryptionCompleted : Signal String
encryptedString : Signal Action
encryptedString =
Signal.map EncryptedValueReceived encryptionCompleted
update : Action -> Model -> ( Model, Effects Action, Maybe PortAction )
update action model =
case action of
TextChanged text ->
( { model | clearText = text }
, Effects.none
, Just (RequestEncryption text)
)
EncryptedValueReceived encrypted ->
( { model | encryptedText = encrypted }
, Effects.none
, Nothing
)
Noop ->
( model, Effects.none, Nothing )
view : Address Action -> Model -> Html
view address model =
div
[]
[ input
[ placeholder "Text to encrypt"
, value model.clearText
, on "input" targetValue (\textfieldContent -> Signal.message address <| TextChanged textfieldContent)
, myStyle
]
[]
, div [ myStyle ] [ text (model.encryptedText) ]
]
myStyle : Attribute
myStyle =
style
[ ( "width", "100%" )
, ( "height", "40px" )
, ( "padding", "10px 0" )
, ( "font-size", "2em" )
, ( "text-align", "center" )
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Encryption sample</title>
<link href="base.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script src="encryptMessageAlternative.js"></script>
<script>
var div = document.getElementById('root');
var myapp = Elm.embed(Elm.EncryptMessage, div, {encryptionCompleted : ""});
myapp.ports.requestEncryption.subscribe(encryptString);
function encryptString(message) {
encryptedMessage = "Encypted: " + message; // actually encypting the message is ommited
myapp.ports.encryptionCompleted.send(encryptedMessage);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment