mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-03-28 09:45:07 +00:00
167 lines
3.7 KiB
Elm
167 lines
3.7 KiB
Elm
-- inspired from here: https://ellie-app.com/3T5mNms7SwKa1
|
|
|
|
|
|
module Comp.Dropzone exposing
|
|
( Model
|
|
, Msg(..)
|
|
, Settings
|
|
, defaultSettings
|
|
, init
|
|
, setActive
|
|
, update
|
|
, view
|
|
)
|
|
|
|
import File exposing (File)
|
|
import File.Select
|
|
import Html exposing (..)
|
|
import Html.Attributes exposing (..)
|
|
import Html.Events exposing (..)
|
|
import Json.Decode as D
|
|
|
|
|
|
type alias State =
|
|
{ hover : Bool
|
|
, active : Bool
|
|
}
|
|
|
|
|
|
type alias Settings =
|
|
{ classList : State -> List ( String, Bool )
|
|
, contentTypes : List String
|
|
}
|
|
|
|
|
|
defaultSettings : Settings
|
|
defaultSettings =
|
|
{ classList = \_ -> [ ( "ui placeholder segment", True ) ]
|
|
, contentTypes = [ "application/pdf" ]
|
|
}
|
|
|
|
|
|
type alias Model =
|
|
{ state : State
|
|
, settings : Settings
|
|
}
|
|
|
|
|
|
init : Settings -> Model
|
|
init settings =
|
|
{ state = State False True
|
|
, settings = settings
|
|
}
|
|
|
|
|
|
type Msg
|
|
= DragEnter
|
|
| DragLeave
|
|
| GotFiles File (List File)
|
|
| PickFiles
|
|
| SetActive Bool
|
|
|
|
|
|
setActive : Bool -> Msg
|
|
setActive flag =
|
|
SetActive flag
|
|
|
|
|
|
update : Msg -> Model -> ( Model, Cmd Msg, List File )
|
|
update msg model =
|
|
case msg of
|
|
SetActive flag ->
|
|
let
|
|
ns =
|
|
{ hover = model.state.hover, active = flag }
|
|
in
|
|
( { model | state = ns }, Cmd.none, [] )
|
|
|
|
PickFiles ->
|
|
( model, File.Select.files model.settings.contentTypes GotFiles, [] )
|
|
|
|
DragEnter ->
|
|
let
|
|
ns =
|
|
{ hover = True, active = model.state.active }
|
|
in
|
|
( { model | state = ns }, Cmd.none, [] )
|
|
|
|
DragLeave ->
|
|
let
|
|
ns =
|
|
{ hover = False, active = model.state.active }
|
|
in
|
|
( { model | state = ns }, Cmd.none, [] )
|
|
|
|
GotFiles file files ->
|
|
let
|
|
ns =
|
|
{ hover = False, active = model.state.active }
|
|
|
|
newFiles =
|
|
if model.state.active then
|
|
filterMime model.settings (file :: files)
|
|
|
|
else
|
|
[]
|
|
in
|
|
( { model | state = ns }, Cmd.none, newFiles )
|
|
|
|
|
|
view : Model -> Html Msg
|
|
view model =
|
|
div
|
|
[ classList (model.settings.classList model.state)
|
|
, hijackOn "dragenter" (D.succeed DragEnter)
|
|
, hijackOn "dragover" (D.succeed DragEnter)
|
|
, hijackOn "dragleave" (D.succeed DragLeave)
|
|
, hijackOn "drop" dropDecoder
|
|
]
|
|
[ div [ class "ui icon header" ]
|
|
[ i [ class "mouse pointer icon" ] []
|
|
, div [ class "content" ]
|
|
[ text "Drop files here"
|
|
, div [ class "sub header" ]
|
|
[ text "PDF files only"
|
|
]
|
|
]
|
|
]
|
|
, div [ class "ui horizontal divider" ]
|
|
[ text "Or"
|
|
]
|
|
, a
|
|
[ classList
|
|
[ ( "ui basic primary button", True )
|
|
, ( "disabled", not model.state.active )
|
|
]
|
|
, onClick PickFiles
|
|
, href ""
|
|
]
|
|
[ i [ class "folder open icon" ] []
|
|
, text "Select ..."
|
|
]
|
|
]
|
|
|
|
|
|
filterMime : Settings -> List File -> List File
|
|
filterMime settings files =
|
|
let
|
|
pred f =
|
|
List.member (File.mime f) settings.contentTypes
|
|
in
|
|
List.filter pred files
|
|
|
|
|
|
dropDecoder : D.Decoder Msg
|
|
dropDecoder =
|
|
D.at [ "dataTransfer", "files" ] (D.oneOrMore GotFiles File.decoder)
|
|
|
|
|
|
hijackOn : String -> D.Decoder msg -> Attribute msg
|
|
hijackOn event decoder =
|
|
preventDefaultOn event (D.map hijack decoder)
|
|
|
|
|
|
hijack : msg -> ( msg, Bool )
|
|
hijack msg =
|
|
( msg, True )
|