Skip to content

Instantly share code, notes, and snippets.

@TwistingTwists
Last active April 1, 2019 03:29
Show Gist options
  • Save TwistingTwists/7d483744f4e9b3cf0057bf3186b885ce to your computer and use it in GitHub Desktop.
Save TwistingTwists/7d483744f4e9b3cf0057bf3186b885ce to your computer and use it in GitHub Desktop.
reading json at runtime in Elm
module Central exposing (central_idea)
central_idea =
"""
{
"map": {
"@version": "freeplane 1.7.0",
"node": {
"@TEXT": "Central Idea",
"node": [
{
"@TEXT": "IDEA 1",
"@POSITION": "right",
"@ID": "ID_273436263",
"@CREATED": "1554050528404",
"@MODIFIED": "1554050528404",
"@HGAP_QUANTITY": "91.26829627750192 pt",
"@VSHIFT_QUANTITY": "-30.731708746733723 pt",
"edge": {
"@COLOR": "#007c7c"
}
},
{
"@TEXT": "IDEA 2",
"@POSITION": "right",
"@ID": "ID_495676614",
"@CREATED": "1554050528404",
"@MODIFIED": "1554050528404",
"@HGAP_QUANTITY": "101.80488213352491 pt",
"@VSHIFT_QUANTITY": "-42.14634342409195 pt",
"edge": {
"@COLOR": "#009900"
},
"node": [
{
"@TEXT": "IDEA 2.1",
"@ID": "ID_744391648",
"@CREATED": "1554050528404",
"@MODIFIED": "1554050528404",
"@HGAP_QUANTITY": "15.756097642670499 pt",
"@VSHIFT_QUANTITY": "-14.926829962699236 pt"
},
{
"@TEXT": "IDEA 2.2",
"@ID": "ID_903669612",
"@CREATED": "1554050528404",
"@MODIFIED": "1554050528404"
}
]
},
{
"@TEXT": "IDEA 5",
"@POSITION": "left",
"@ID": "ID_1822402846",
"@CREATED": "1554050528405",
"@MODIFIED": "1554050528405",
"@HGAP_QUANTITY": "84.24390570681993 pt",
"@VSHIFT_QUANTITY": "-36.00000167474521 pt",
"edge": {
"@COLOR": "#ff9900"
},
"node": [
{
"@TEXT": "IDEA 5.1",
"@ID": "ID_1274507163",
"@CREATED": "1554050528405",
"@MODIFIED": "1554050528405",
"@HGAP_QUANTITY": "14.0 pt",
"@VSHIFT_QUANTITY": "-21.07317171204598 pt"
},
{
"@TEXT": "IDEA 5.2",
"@ID": "ID_1203076641",
"@CREATED": "1554050528405",
"@MODIFIED": "1554050528405"
}
]
}
]
}
}
}
"""
module MMjsonDecoder exposing (MNode(..), Model, NodeAttributes, boolFromString, decodeNode, main, timestamp)
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (style)
import Html.Events exposing (onClick)
import Json.Decode as Decode exposing (..)
import Json.Decode.Pipeline exposing (custom, hardcoded, optional, required)
import Lazy.Tree as Tree exposing (Tree(..))
import Lazy.Tree.Zipper as Zipper exposing (Zipper)
import Time
import Central exposing (central_idea)
type alias Model =
Zipper ( Bool, MNode )
type MNode
= MNode String NodeAttributes (List MNode)
type alias NodeAttributes =
{ style : Maybe String
, folded : Maybe Bool
-- toInt = Maybe.withDefault 0 (String.toInt(String.dropLeft 3 d)) : converts `id` to int.
, id : Maybe String
, created : Maybe Time.Posix
, modified : Maybe Time.Posix
-- , position : Maybe Position
}
-- map : (a -> b) -> MNode a -> MNode b
-- map f (MNode a NodeAttributes (List MNode)) = MNode (f a) <| childrenMap f forest
getChildren (MNode _ _ children) =
children
------------------------
-- Defaults
------------------------
rootNode =
MNode "ROOT NODE" defaultNodeAttributes []
defaultNodeAttributes =
NodeAttributes Nothing (Just False) (Just "0") Nothing Nothing
----------
-- MAIN
----------
main : Html msg
main =
-- viewPrettyJson
--viewSimpleJson
--viewZipperTree
viewLevel zipper_tree
zipper_tree =
input_node
|> Tree.build getChildren
|> Zipper.fromTree
input_node =
Decode.decodeString (Decode.at [ "map", "node" ] decodeNode) input_string
|> Result.withDefault rootNode
viewSimpleJson =
div []
[ text <| Debug.toString input_node
]
viewZipperTree =
div []
[ text <| Debug.toString zipper_tree
]
viewLevel : Zipper MNode -> Html msg
viewLevel zipper =
Html.li []
[ viewMNode <| Zipper.current zipper
, Html.ul [] <| List.map viewLevel <| Zipper.openAll zipper
]
viewMNode : MNode -> Html msg
viewMNode mnode =
div []
[ text <| getString mnode
]
getString (MNode str _ _) =
str
----------------------------------------
-- Decoding .mm -> .json to Node type
----------------------------------------
decodeNode : Decoder MNode
decodeNode =
Decode.succeed MNode
|> required "@TEXT" string
|> custom decodeNodeAttributes
|> custom decodeNodeChildren
decodeNodeChildren : Decoder (List MNode)
decodeNodeChildren =
oneOf
[ Debug.log "node []" (field "node" (list (lazy (\_ -> decodeNode))))
, Debug.log "node {}" (field "node" (map List.singleton (lazy (\_ -> decodeNode))))
, Debug.log "else" succeed []
]
decodeNodeAttributes : Decoder NodeAttributes
decodeNodeAttributes =
Decode.succeed NodeAttributes
|> optional "@LOCALIZED_STYLE_REF" (map Just string) Nothing
|> optional "@FOLDED" (map Just boolFromString) Nothing
|> optional "@ID" (map Just string) Nothing
|> optional "@CREATED" (map Just timestamp) Nothing
|> optional "@MODIFIED" (map Just timestamp) Nothing
boolFromString : Decoder Bool
boolFromString =
Decode.andThen
(\s ->
if s == "true" then
succeed True
else if s == "false" then
succeed False
else
fail "invalid bool"
)
Decode.string
-- convert string to Maybe Timestamp
timestamp : Decoder Time.Posix
timestamp =
Decode.andThen
(\s ->
String.toInt s
|> Maybe.map (Time.millisToPosix >> Decode.succeed)
|> Maybe.withDefault (Decode.fail "not a valid timestamp")
)
Decode.string
----------------
-- Converting to UTF-8 using `zwilias/elm-utf-tools 2.0.1`
----------------
-- input_string = large_input
input_string =
central_idea
-- input_string = small_input
--input_string = input
-- this is the kind of input I am trying to read from json file in ReadingJson.elm
input =
"""
{
"map": {
"node": {
"@TEXT": "alpha",
"edge": {
"@COLOR": "#ffffff"
},
"richcontent": {
"@TYPE": "DETAILS",
"html": {
"head": null,
"body": {
"p": [
"1. Write the central idea",
"2. Save the map",
"3. Select central node,",
"click on icon to add picture",
"4. Delete menu links Add image..",
"with CTRL+K and delete field with link",
"5. Delete node details with right click on mouse",
"on central node - Remove node details"
]
}
}
},
"node": [
{
"@TEXT": "asldfjasfdl1",
"node": [
{
"@TEXT": "1.1"
},
{
"@TEXT": "1.2"
}
]
},
{
"@TEXT": "2",
"node": {
"@TEXT": "2.1"
}
}
]
}
}
}
"""
module Main exposing (Model, Msg(..), filesDecoder, init, main, subscriptions, update, view)
import Browser
import File exposing (File)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Http
import Json.Decode as Decode
import MMjsonDecoder exposing (..)
-- MAIN
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
List File
init : () -> ( Model, Cmd Msg )
init _ =
( [], Cmd.none )
-- UPDATE
type Msg
= GotFiles (List File)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotFiles files ->
( files, Cmd.none )
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
Sub.none
-- VIEW
view : Model -> Html Msg
view model =
div []
[ input
[ type_ "file", multiple True, on "change" (Decode.map GotFiles filesDecoder) ]
[]
, div [] [ text (Debug.toString model) ]
-- , text <| Debug.toString (Decode.decodeString (Decode.at [ "map", "node" ] decodeNode) inputData)
]
file_received : Decode.Decoder (List File)
file_received =
Decode.field "dataTransfer" (Decode.field "files" (Decode.list File.decoder))
-- TODO : NEED TO stringify json file I select from 'ChooseFile' button on Runtime to create inputData
inputData = ????
inputDataText =
Decode.decodeString (Decode.at [ "map", "node" ] decodeNode) inputData
filesDecoder : Decode.Decoder (List File)
filesDecoder =
Decode.at [ "target", "files" ] (Decode.list File.decoder)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment