2017-05-02 02:27:01 -04:00
|
|
|
|
module View.Draft exposing (draftView)
|
|
|
|
|
|
|
|
|
|
import Autocomplete
|
|
|
|
|
import Html exposing (..)
|
|
|
|
|
import Html.Attributes exposing (..)
|
|
|
|
|
import Html.Events exposing (..)
|
|
|
|
|
import Html.Lazy as Lazy
|
|
|
|
|
import Json.Encode as Encode
|
|
|
|
|
import Json.Decode as Decode
|
|
|
|
|
import Mastodon.Model exposing (..)
|
|
|
|
|
import Types exposing (..)
|
2017-05-07 08:31:51 -04:00
|
|
|
|
import Util
|
2017-05-02 02:27:01 -04:00
|
|
|
|
import View.Common as Common
|
|
|
|
|
import View.Events exposing (..)
|
|
|
|
|
import View.Formatter exposing (formatContent)
|
|
|
|
|
import View.Status exposing (statusView)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type alias CurrentUser =
|
|
|
|
|
Account
|
|
|
|
|
|
|
|
|
|
|
2017-05-05 13:18:20 -04:00
|
|
|
|
visibilities : List ( String, String, String, String )
|
2017-05-02 02:27:01 -04:00
|
|
|
|
visibilities =
|
2017-05-05 13:18:20 -04:00
|
|
|
|
[ ( "direct", "Mentioned", "Visible to mentioned users only", "envelope" )
|
|
|
|
|
, ( "private", "Followers", "Visible to followers only", "lock" )
|
|
|
|
|
, ( "unlisted", "Unlisted", "Do not show in public timelines", "eye-close" )
|
|
|
|
|
, ( "public", "Public", "Visible in public timelines", "globe" )
|
2017-05-03 11:10:03 -04:00
|
|
|
|
]
|
2017-05-02 02:27:01 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
viewAutocompleteMenu : Draft -> Html Msg
|
|
|
|
|
viewAutocompleteMenu draft =
|
|
|
|
|
div [ class "autocomplete-menu" ]
|
|
|
|
|
[ Html.map (DraftEvent << SetAutoState)
|
|
|
|
|
(Autocomplete.view viewConfig
|
|
|
|
|
draft.autoMaxResults
|
|
|
|
|
draft.autoState
|
2017-05-07 08:31:51 -04:00
|
|
|
|
(Util.acceptableAccounts draft.autoQuery draft.autoAccounts)
|
2017-05-02 02:27:01 -04:00
|
|
|
|
)
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
viewConfig : Autocomplete.ViewConfig Mastodon.Model.Account
|
|
|
|
|
viewConfig =
|
|
|
|
|
let
|
|
|
|
|
customizedLi keySelected mouseSelected account =
|
|
|
|
|
{ attributes =
|
|
|
|
|
[ classList
|
|
|
|
|
[ ( "list-group-item autocomplete-item", True )
|
|
|
|
|
, ( "active", keySelected || mouseSelected )
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
, children =
|
|
|
|
|
[ img [ src account.avatar ] []
|
|
|
|
|
, strong []
|
|
|
|
|
[ text <|
|
|
|
|
|
if account.display_name /= "" then
|
|
|
|
|
account.display_name
|
|
|
|
|
else
|
|
|
|
|
account.acct
|
|
|
|
|
]
|
|
|
|
|
, span [] [ text <| " @" ++ account.acct ]
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
in
|
|
|
|
|
Autocomplete.viewConfig
|
|
|
|
|
{ toId = .id >> toString
|
|
|
|
|
, ul = [ class "list-group autocomplete-list" ]
|
|
|
|
|
, li = customizedLi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
currentUserView : Maybe CurrentUser -> Html Msg
|
|
|
|
|
currentUserView currentUser =
|
|
|
|
|
case currentUser of
|
|
|
|
|
Just currentUser ->
|
|
|
|
|
div [ class "current-user" ]
|
2017-05-03 09:08:10 -04:00
|
|
|
|
[ Common.accountAvatarLink False currentUser
|
2017-05-09 12:43:12 -04:00
|
|
|
|
, div [ class "username" ]
|
|
|
|
|
[ Common.accountLink False currentUser
|
|
|
|
|
, span []
|
|
|
|
|
[ text " ("
|
2017-05-13 09:55:46 -04:00
|
|
|
|
, a [ href "", onClickWithPreventAndStop <| SetView AccountSelectorView ]
|
2017-05-09 12:43:12 -04:00
|
|
|
|
[ text "switch account" ]
|
|
|
|
|
, text ")"
|
|
|
|
|
]
|
|
|
|
|
]
|
2017-05-02 02:27:01 -04:00
|
|
|
|
, p [ class "status-text" ] <| formatContent currentUser.note []
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
|
text ""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
draftReplyToView : Draft -> Html Msg
|
|
|
|
|
draftReplyToView draft =
|
|
|
|
|
case draft.inReplyTo of
|
|
|
|
|
Just status ->
|
|
|
|
|
div [ class "in-reply-to" ]
|
|
|
|
|
[ p []
|
|
|
|
|
[ strong []
|
|
|
|
|
[ text "In reply to this toot ("
|
|
|
|
|
, a
|
|
|
|
|
[ href ""
|
|
|
|
|
, onClickWithPreventAndStop <| DraftEvent ClearDraft
|
|
|
|
|
]
|
|
|
|
|
[ Common.icon "remove" ]
|
|
|
|
|
, text ")"
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
, div [ class "well" ] [ Lazy.lazy2 statusView "draft" status ]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
|
text ""
|
|
|
|
|
|
|
|
|
|
|
2017-05-03 11:10:03 -04:00
|
|
|
|
visibilitySelector : Draft -> Html Msg
|
|
|
|
|
visibilitySelector { visibility } =
|
|
|
|
|
let
|
|
|
|
|
btnClass v =
|
|
|
|
|
if v == visibility then
|
2017-05-05 13:18:20 -04:00
|
|
|
|
"btn btn-sm btn-vis btn-primary active"
|
2017-05-03 11:10:03 -04:00
|
|
|
|
else
|
2017-05-05 13:18:20 -04:00
|
|
|
|
"btn btn-sm btn-vis btn-default"
|
2017-05-03 11:10:03 -04:00
|
|
|
|
in
|
|
|
|
|
visibilities
|
|
|
|
|
|> List.map
|
2017-05-05 13:18:20 -04:00
|
|
|
|
(\( v, d, t, i ) ->
|
2017-05-03 11:10:03 -04:00
|
|
|
|
a
|
|
|
|
|
[ href ""
|
|
|
|
|
, class <| btnClass v
|
|
|
|
|
, onClickWithPreventAndStop <| DraftEvent (UpdateVisibility v)
|
|
|
|
|
, title t
|
|
|
|
|
]
|
2017-05-05 13:18:20 -04:00
|
|
|
|
[ Common.icon i, span [] [ text d ] ]
|
2017-05-03 11:10:03 -04:00
|
|
|
|
)
|
2017-05-03 11:24:31 -04:00
|
|
|
|
|> Common.justifiedButtonGroup "draft-visibilities"
|
2017-05-03 11:10:03 -04:00
|
|
|
|
|
|
|
|
|
|
2017-05-02 02:27:01 -04:00
|
|
|
|
draftView : Model -> Html Msg
|
|
|
|
|
draftView ({ draft, currentUser } as model) =
|
|
|
|
|
let
|
|
|
|
|
autoMenu =
|
|
|
|
|
if draft.showAutoMenu then
|
|
|
|
|
viewAutocompleteMenu model.draft
|
|
|
|
|
else
|
|
|
|
|
text ""
|
2017-05-02 06:26:17 -04:00
|
|
|
|
|
|
|
|
|
( hasSpoiler, charCount ) =
|
|
|
|
|
case draft.spoilerText of
|
|
|
|
|
Just spoilerText ->
|
|
|
|
|
( True, (String.length spoilerText) + draft.statusLength )
|
|
|
|
|
|
|
|
|
|
Nothing ->
|
|
|
|
|
( False, draft.statusLength )
|
|
|
|
|
|
|
|
|
|
limitExceeded =
|
|
|
|
|
charCount > 500
|
2017-05-02 02:27:01 -04:00
|
|
|
|
in
|
2017-05-03 14:53:12 -04:00
|
|
|
|
div [ class "panel panel-default draft" ]
|
2017-05-02 02:27:01 -04:00
|
|
|
|
[ div [ class "panel-heading" ]
|
|
|
|
|
[ Common.icon "envelope"
|
|
|
|
|
, text <|
|
|
|
|
|
if draft.inReplyTo /= Nothing then
|
|
|
|
|
"Post a reply"
|
|
|
|
|
else
|
|
|
|
|
"Post a message"
|
|
|
|
|
]
|
2017-05-14 06:53:13 -04:00
|
|
|
|
, div [ class "panel-body timeline" ]
|
2017-05-02 02:27:01 -04:00
|
|
|
|
[ currentUserView currentUser
|
|
|
|
|
, draftReplyToView draft
|
|
|
|
|
, Html.form [ class "form", onSubmit SubmitDraft ]
|
2017-05-18 17:47:01 -04:00
|
|
|
|
[ if hasSpoiler then
|
2017-05-02 02:27:01 -04:00
|
|
|
|
div [ class "form-group" ]
|
2017-05-18 17:47:01 -04:00
|
|
|
|
[ label [ for "spoiler" ] [ text "Content Warning (visible part)" ]
|
2017-05-02 02:27:01 -04:00
|
|
|
|
, textarea
|
|
|
|
|
[ id "spoiler"
|
|
|
|
|
, class "form-control"
|
|
|
|
|
, rows 5
|
|
|
|
|
, placeholder "This text will always be visible."
|
|
|
|
|
, onInput <| DraftEvent << UpdateSpoiler
|
|
|
|
|
, required True
|
|
|
|
|
, value <| Maybe.withDefault "" draft.spoilerText
|
|
|
|
|
]
|
|
|
|
|
[]
|
|
|
|
|
]
|
|
|
|
|
else
|
|
|
|
|
text ""
|
2017-05-18 17:47:01 -04:00
|
|
|
|
, visibilitySelector draft
|
2017-05-18 11:32:19 -04:00
|
|
|
|
, div [ class "form-group status-field" ]
|
2017-05-18 17:47:01 -04:00
|
|
|
|
[ if hasSpoiler then
|
|
|
|
|
label [ for "status" ] [ text "Hidden part" ]
|
|
|
|
|
else
|
|
|
|
|
text ""
|
2017-05-02 02:27:01 -04:00
|
|
|
|
, let
|
|
|
|
|
dec =
|
|
|
|
|
(Decode.map
|
|
|
|
|
(\code ->
|
|
|
|
|
if code == 38 || code == 40 then
|
|
|
|
|
Ok NoOp
|
2017-05-06 10:00:00 -04:00
|
|
|
|
else if code == 27 then
|
|
|
|
|
Ok <| DraftEvent CloseAutocomplete
|
2017-05-02 02:27:01 -04:00
|
|
|
|
else
|
|
|
|
|
Err "not handling that key"
|
|
|
|
|
)
|
|
|
|
|
keyCode
|
|
|
|
|
)
|
|
|
|
|
|> Decode.andThen fromResult
|
|
|
|
|
|
|
|
|
|
options =
|
|
|
|
|
{ preventDefault = draft.showAutoMenu
|
|
|
|
|
, stopPropagation = False
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fromResult : Result String a -> Decode.Decoder a
|
|
|
|
|
fromResult result =
|
|
|
|
|
case result of
|
|
|
|
|
Ok val ->
|
|
|
|
|
Decode.succeed val
|
|
|
|
|
|
|
|
|
|
Err reason ->
|
|
|
|
|
Decode.fail reason
|
|
|
|
|
in
|
|
|
|
|
textarea
|
|
|
|
|
[ id "status"
|
|
|
|
|
, class "form-control"
|
2017-05-11 04:55:15 -04:00
|
|
|
|
, rows 7
|
2017-05-02 02:27:01 -04:00
|
|
|
|
, placeholder <|
|
|
|
|
|
if hasSpoiler then
|
2017-05-12 05:49:42 -04:00
|
|
|
|
"This text will be hidden by default, as you have enabled a Content Warning."
|
2017-05-02 02:27:01 -04:00
|
|
|
|
else
|
|
|
|
|
"Once upon a time..."
|
|
|
|
|
, required True
|
|
|
|
|
, onInputInformation <| DraftEvent << UpdateInputInformation
|
|
|
|
|
, onClickInformation <| DraftEvent << UpdateInputInformation
|
|
|
|
|
, property "defaultValue" (Encode.string draft.status)
|
|
|
|
|
, onWithOptions "keydown" options dec
|
|
|
|
|
]
|
|
|
|
|
[]
|
|
|
|
|
, autoMenu
|
|
|
|
|
]
|
2017-05-18 17:47:01 -04:00
|
|
|
|
, draftAttachments draft.attachments
|
|
|
|
|
, div [ class "draft-actions" ]
|
|
|
|
|
[ div [ class "draft-actions-btns" ]
|
|
|
|
|
[ Common.justifiedButtonGroup ""
|
|
|
|
|
[ button
|
|
|
|
|
[ type_ "button"
|
|
|
|
|
, class "btn btn-default btn-clear"
|
|
|
|
|
, title "Clear this draft"
|
|
|
|
|
, onClick (DraftEvent ClearDraft)
|
|
|
|
|
]
|
|
|
|
|
[ Common.icon "trash" ]
|
|
|
|
|
, button
|
|
|
|
|
[ type_ "button"
|
|
|
|
|
, class <|
|
|
|
|
|
"btn btn-default btn-cw "
|
|
|
|
|
++ (if hasSpoiler then
|
|
|
|
|
"btn-primary active"
|
|
|
|
|
else
|
|
|
|
|
""
|
|
|
|
|
)
|
|
|
|
|
, title "Add a Content Warning"
|
|
|
|
|
, onClick <| DraftEvent (ToggleSpoiler (not hasSpoiler))
|
|
|
|
|
]
|
|
|
|
|
[ text "CW" ]
|
|
|
|
|
, button
|
|
|
|
|
[ type_ "button"
|
|
|
|
|
, class <|
|
|
|
|
|
"btn btn-default btn-nsfw "
|
|
|
|
|
++ (if draft.sensitive then
|
|
|
|
|
"btn-primary active"
|
|
|
|
|
else
|
|
|
|
|
""
|
|
|
|
|
)
|
|
|
|
|
, title "Mark this post as Not Safe For Work (sensitive content)"
|
|
|
|
|
, onClick <| DraftEvent (UpdateSensitive (not draft.sensitive))
|
|
|
|
|
]
|
|
|
|
|
[ text "NSFW" ]
|
|
|
|
|
, fileUploadField draft
|
|
|
|
|
]
|
2017-05-02 06:26:17 -04:00
|
|
|
|
]
|
2017-05-18 17:47:01 -04:00
|
|
|
|
, if limitExceeded then
|
|
|
|
|
div
|
|
|
|
|
[ class "draft-actions-charcount text-center exceed" ]
|
|
|
|
|
[ text <| toString (500 - charCount) ]
|
|
|
|
|
else
|
|
|
|
|
div
|
|
|
|
|
[ class "draft-actions-charcount text-center" ]
|
|
|
|
|
[ text <| toString charCount ]
|
2017-05-02 02:27:01 -04:00
|
|
|
|
, button
|
|
|
|
|
[ type_ "submit"
|
2017-05-18 17:47:01 -04:00
|
|
|
|
, class "draft-actions-submit btn btn-warning btn-toot"
|
2017-05-02 06:26:17 -04:00
|
|
|
|
, disabled limitExceeded
|
2017-05-02 02:27:01 -04:00
|
|
|
|
]
|
2017-05-18 17:47:01 -04:00
|
|
|
|
[ text "Toot" ]
|
2017-05-02 02:27:01 -04:00
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
]
|
2017-05-11 04:55:15 -04:00
|
|
|
|
|
|
|
|
|
|
2017-05-18 17:47:01 -04:00
|
|
|
|
draftAttachments : List Attachment -> Html Msg
|
|
|
|
|
draftAttachments attachments =
|
2017-05-11 04:55:15 -04:00
|
|
|
|
let
|
|
|
|
|
attachmentPreview attachment =
|
|
|
|
|
li
|
|
|
|
|
[ class "draft-attachment-entry"
|
|
|
|
|
, style
|
|
|
|
|
[ ( "background"
|
|
|
|
|
, "url(" ++ attachment.preview_url ++ ") center center / cover no-repeat"
|
|
|
|
|
)
|
|
|
|
|
]
|
|
|
|
|
]
|
|
|
|
|
[ a
|
|
|
|
|
[ href ""
|
|
|
|
|
, onClickWithPreventAndStop <| DraftEvent (RemoveMedia attachment.id)
|
|
|
|
|
]
|
|
|
|
|
[ text "×" ]
|
|
|
|
|
]
|
|
|
|
|
in
|
2017-05-18 17:47:01 -04:00
|
|
|
|
div [ class "draft-attachments-field" ]
|
|
|
|
|
[ if List.length attachments > 0 then
|
2017-05-11 04:55:15 -04:00
|
|
|
|
ul [ class "draft-attachments" ] <|
|
2017-05-18 17:47:01 -04:00
|
|
|
|
List.map attachmentPreview attachments
|
2017-05-11 04:55:15 -04:00
|
|
|
|
else
|
|
|
|
|
text ""
|
|
|
|
|
]
|
2017-05-18 17:47:01 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fileUploadField : Draft -> Html Msg
|
|
|
|
|
fileUploadField draft =
|
|
|
|
|
if draft.mediaUploading then
|
|
|
|
|
button [ class "btn btn-default btn-loading", disabled True ]
|
|
|
|
|
[ Common.icon "time" ]
|
|
|
|
|
else if List.length draft.attachments < 4 then
|
|
|
|
|
label [ class "btn btn-default draft-attachment-input-label" ]
|
|
|
|
|
[ input
|
|
|
|
|
[ type_ "file"
|
|
|
|
|
, id "draft-attachment"
|
|
|
|
|
, on "change" (Decode.succeed <| DraftEvent (UploadMedia "draft-attachment"))
|
|
|
|
|
]
|
|
|
|
|
[]
|
|
|
|
|
, text ""
|
|
|
|
|
]
|
|
|
|
|
else
|
|
|
|
|
text ""
|