Skip to content

Instantly share code, notes, and snippets.

@AdrianoFerrari
Last active December 5, 2016 22:04
Show Gist options
  • Save AdrianoFerrari/2c5c5d46828bf969def1c53c7b30aae3 to your computer and use it in GitHub Desktop.
Save AdrianoFerrari/2c5c5d46828bf969def1c53c7b30aae3 to your computer and use it in GitHub Desktop.
--- TYPES
type alias ViewState =
{ active : String
, activePast : List String
, activeFuture : List String
, descendants : List String
, editing : Maybe String
, field : String
}
-- Trimmed down ViewState for view functions
-- so that (in theory), lazy can avoid rebuilding
-- DOM if these arguments are the same
type alias VisibleViewState =
{ active : String
, editing : Maybe (String, String)
, descendants : List String
}
type alias Tree =
{ id : String
, content : String
, children : Children -- ~ List Tree (recursive)
}
type Children = Children (List Tree)
type alias Group = List Tree
type alias Column = List (List Tree)
-- VIEW
view : ViewState -> Tree -> Html Msg
view vstate tree =
let
columnsWithDepth =
getColumnsWithDepth [([[ tree ]], 0)]
getViewArgs cwd =
let
editing_ =
case vstate.editing of
Nothing ->
Nothing
Just editId ->
if (first cwd |> List.concat |> List.map .id |> List.member editId ) then
Just (editId, vstate.field) -- only send down 'field' if this column actually contains card being edited
else
Nothing
in
VisibleViewState
vstate.active
editing_
vstate.descendants
columns =
[([[]], -1)] ++
columnsWithDepth ++
[([[]], List.length columnsWithDepth)]
|> List.map (\t -> lazy3 viewColumn (getViewArgs t) (second t) (first t))
-- I believe this call would mean that if I'm editing a card in e.g. column 1,
-- none of the arguments to lazy3 are changing in e.g. column 3.
-- Yet when I open Chrome inspector, divs in all columns are flashing on every edit keystroke.
in
div [ id "app"
, classList [ ("editing", vstate.editing /= Nothing) ]
]
( columns
)
viewColumn : VisibleViewState -> Int -> Column -> Html Msg
viewColumn vstate depth col =
let
buffer =
[div [ class "buffer" ][]]
in
div
[ class "column" ]
( buffer ++
(List.map (lazy3 viewGroup vstate depth) col) ++
buffer
)
viewGroup : VisibleViewState -> Int -> Group -> Html Msg
viewGroup vstate depth xs =
let
firstChild =
xs
|> List.head
|> Maybe.withDefault defaultTree
|> .id
isActiveDescendant =
vstate.descendants
|> List.member firstChild
viewFunction t =
let
isActive =
t.id == vstate.active
field_ =
case vstate.editing of
Just (editId, field) ->
if editId == t.id then
Just field
else
Nothing
Nothing ->
Nothing
in
viewKeyedCard (isActive, field_, depth) t
in
Keyed.node "div"
[ classList [ ("group", True)
, ("active-descendant", isActiveDescendant)
]
]
(List.map viewFunction xs)
viewKeyedCard : (Bool, Maybe String, Int) -> Tree -> (String, Html Msg)
viewKeyedCard tup tree =
(tree.id, lazy2 viewCard tup tree)
viewCard : (Bool, Maybe String, Int) -> Tree -> Html Msg
viewCard (isActive, field_, depth) tree =
let
isEditing =
field_ /= Nothing
isRoot = tree.id == "0"
options =
{ githubFlavored = Just { tables = True, breaks = True }
, defaultHighlighting = Nothing
, sanitize = False
, smartypants = False
}
hasChildren =
case tree.children of
Children c ->
( c
|> List.length
) /= 0
tarea content =
textarea
[ id ( "card-edit-" ++ tree.id )
, classList [ ("edit", True)
, ("mousetrap", True)
]
, value content
, onInput UpdateField
]
[]
buttons =
case (isEditing, field_, isRoot) of
( False, Just field, False ) ->
[ div [ class "flex-row card-top-overlay" ]
[ span
[ class "card-btn ins-above"
, title "Insert Above (Ctrl+K)"
, onClick (InsertAbove tree.id)
]
[ text "+" ]
]
, div [ class "flex-column card-right-overlay"]
[ span
[ class "card-btn delete"
, title "Delete Card (Ctrl+Backspace)"
, onClick (DeleteCard tree.id)
]
[]
, span
[ class "card-btn ins-right"
, title "Add Child (Ctrl+L)"
, onClick (InsertChild tree.id)
]
[ text "+" ]
, span
[ class "card-btn edit"
, title "Edit Card (Enter)"
, onClick (OpenCard tree.id tree.content)
]
[]
]
, div [ class "flex-row card-bottom-overlay" ]
[ span
[ class "card-btn ins-below"
, title "Insert Below (Ctrl+J)"
, onClick (InsertBelow tree.id)
]
[ text "+" ]
]
]
( False, Just field, True ) ->
[ div [ class "flex-column card-right-overlay"]
[ span
[ class "card-btn ins-right"
, title "Add Child (Ctrl+L)"
, onClick (InsertChild tree.id)
]
[ text "+" ]
, span
[ class "card-btn edit"
, title "Edit Card (Enter)"
, onClick (OpenCard tree.id tree.content)
]
[]
]
]
( True, _, _ ) ->
[ div [ class "flex-column card-right-overlay"]
[ span
[ class "card-btn save"
, title "Save Changes (Ctrl+Enter)"
, onClick SaveCard
]
[]
]
]
_ ->
[]
cardAttributes =
[ id ("card-" ++ tree.id)
, classList [ ("card", True)
, ("root", isRoot)
, ("active", isActive)
, ("editing", isEditing)
, ("has-children", hasChildren)
]
]
splitContent =
String.split newLine tree.content
autoheading =
List.repeat (Basics.min 6 (depth+1)) "#"
content =
case splitContent of
[] -> ""
head :: tail ->
if String.startsWith "#" head then
String.join newLine splitContent
else
String.concat
( autoheading ++ [" ", head, newLine, String.join newLine tail] )
in
case field_ of
Just field ->
div cardAttributes
(
[ tarea field ]
++
buttons
)
Nothing ->
div cardAttributes
(
[ Markdown.toHtmlWith options
[ class "view"
, onClick (Activate tree.id)
, onDoubleClick (OpenCard tree.id tree.content)
] content
, tarea content
] ++
buttons
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment