Detect how to display pdf files

Closes: 
This commit is contained in:
eikek 2021-10-06 23:20:16 +02:00
parent b6187bb88d
commit f216c472ee
15 changed files with 217 additions and 87 deletions

@ -43,8 +43,21 @@
// this is required for transitioning; elm fails to parse the account
account["requireSecondFactor"] = false;
}
// hack to guess if the browser can display PDFs natively. It
// seems that almost all browsers allow to query the
// navigator.mimeTypes array, except firefox.
var ua = navigator.userAgent.toLowerCase();
var pdfSupported = false;
if (ua.indexOf("firefox") > -1) {
pdfSupported = ua.indexOf("mobile") == -1;
} else {
pdfSupported = "application/pdf" in navigator.mimeTypes;
}
var elmFlags = {
"account": account,
"pdfSupported": pdfSupported,
"config": {{{flagsJson}}}
};
</script>

@ -22,6 +22,7 @@ import Api.Model.ItemLight exposing (ItemLight)
import Comp.LinkTarget exposing (LinkTarget(..))
import Data.Direction
import Data.Fields
import Data.Flags exposing (Flags)
import Data.Icons as Icons
import Data.ItemSelection exposing (ItemSelection)
import Data.ItemTemplate as IT
@ -150,8 +151,8 @@ update ddm msg model =
--- View2
view2 : Texts -> ViewConfig -> UiSettings -> Model -> ItemLight -> Html Msg
view2 texts cfg settings model item =
view2 : Texts -> ViewConfig -> UiSettings -> Flags -> Model -> ItemLight -> Html Msg
view2 texts cfg settings flags model item =
let
isCreated =
item.state == "created"
@ -221,7 +222,7 @@ view2 texts cfg settings model item =
, metaDataContent2 texts settings item
, notesContent2 settings item
, fulltextResultsContent2 item
, previewMenu2 texts settings cfg model item (currentAttachment model item)
, previewMenu2 texts settings flags cfg model item (currentAttachment model item)
, selectedDimmer
]
)
@ -475,8 +476,8 @@ previewImage2 cfg settings cardAction model item =
]
previewMenu2 : Texts -> UiSettings -> ViewConfig -> Model -> ItemLight -> Maybe AttachmentLight -> Html Msg
previewMenu2 texts settings cfg model item mainAttach =
previewMenu2 : Texts -> UiSettings -> Flags -> ViewConfig -> Model -> ItemLight -> Maybe AttachmentLight -> Html Msg
previewMenu2 texts settings flags cfg model item mainAttach =
let
pageCount =
Maybe.andThen .pageCount mainAttach
@ -489,11 +490,7 @@ previewMenu2 texts settings cfg model item mainAttach =
Data.UiSettings.fieldHidden settings f
mkAttachUrl attach =
if settings.nativePdfPreview then
cfg.attachUrl attach
else
cfg.attachUrl attach ++ "/view"
Data.UiSettings.pdfUrl settings flags (cfg.attachUrl attach)
attachUrl =
Maybe.map mkAttachUrl mainAttach

@ -169,19 +169,19 @@ type alias ViewConfig =
}
view2 : Texts -> ViewConfig -> UiSettings -> Model -> Html Msg
view2 texts cfg settings model =
view2 : Texts -> ViewConfig -> UiSettings -> Flags -> Model -> Html Msg
view2 texts cfg settings flags model =
div
[ classList
[ ( "ds-item-list", True )
, ( "ds-multi-select-mode", isMultiSelectMode cfg )
]
]
(List.map (viewGroup2 texts model cfg settings) model.results.groups)
(List.map (viewGroup2 texts model cfg settings flags) model.results.groups)
viewGroup2 : Texts -> Model -> ViewConfig -> UiSettings -> ItemLightGroup -> Html Msg
viewGroup2 texts model cfg settings group =
viewGroup2 : Texts -> Model -> ViewConfig -> UiSettings -> Flags -> ItemLightGroup -> Html Msg
viewGroup2 texts model cfg settings flags group =
div [ class "ds-item-group" ]
[ div
[ class "flex py-1 mt-2 mb-2 flex flex-row items-center"
@ -206,12 +206,12 @@ viewGroup2 texts model cfg settings group =
[]
]
, div [ class "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 2xl:grid-cols-4 gap-2" ]
(List.map (viewItem2 texts model cfg settings) group.items)
(List.map (viewItem2 texts model cfg settings flags) group.items)
]
viewItem2 : Texts -> Model -> ViewConfig -> UiSettings -> ItemLight -> Html Msg
viewItem2 texts model cfg settings item =
viewItem2 : Texts -> Model -> ViewConfig -> UiSettings -> Flags -> ItemLight -> Html Msg
viewItem2 texts model cfg settings flags item =
let
currentClass =
if cfg.current == Just item.id then
@ -228,7 +228,7 @@ viewItem2 texts model cfg settings item =
|> Maybe.withDefault Comp.ItemCard.init
cardHtml =
Comp.ItemCard.view2 texts.itemCard vvcfg settings cardModel item
Comp.ItemCard.view2 texts.itemCard vvcfg settings flags cardModel item
in
Html.map (ItemCardMsg item) cardHtml

@ -100,7 +100,6 @@ type alias Model =
, sentMailsOpen : Bool
, attachMeta : Dict String Comp.AttachmentMeta.Model
, attachMetaOpen : Bool
, pdfNativeView : Maybe Bool
, attachModal : Maybe ConfirmModalValue
, addFilesOpen : Bool
, addFilesModel : Comp.Dropzone.Model
@ -236,7 +235,6 @@ emptyModel =
, sentMailsOpen = False
, attachMeta = Dict.empty
, attachMetaOpen = False
, pdfNativeView = Nothing
, attachModal = Nothing
, addFilesOpen = False
, addFilesModel = Comp.Dropzone.init []
@ -316,7 +314,6 @@ type Msg
| SentMailsResp (Result Http.Error SentMails)
| AttachMetaClick String
| AttachMetaMsg String Comp.AttachmentMeta.Msg
| TogglePdfNativeView Bool
| RequestDeleteAttachment String
| DeleteAttachConfirmed String
| RequestDeleteSelected

@ -85,12 +85,8 @@ view texts flags settings model pos attach =
, style "max-height" "calc(100vh - 140px)"
, style "min-height" "500px"
]
[ iframe
[ if Maybe.withDefault settings.nativePdfPreview model.pdfNativeView then
src fileUrl
else
src (fileUrl ++ "/view")
[ embed
[ src <| Data.UiSettings.pdfUrl settings flags fileUrl
, class "absolute h-full w-full top-0 left-0 mx-0 py-0"
, id "ds-pdf-view-iframe"
]
@ -254,18 +250,6 @@ attachHeader texts settings model _ attach =
, classList [ ( "hidden", not attach.converted ) ]
]
}
, { icon =
if Maybe.withDefault settings.nativePdfPreview model.pdfNativeView then
"fa fa-toggle-on"
else
"fa fa-toggle-off"
, label = texts.renderPdfByBrowser
, attrs =
[ onClick (TogglePdfNativeView settings.nativePdfPreview)
, href "#"
]
}
, { icon =
if isAttachMetaOpen model attach.id then
"fa fa-toggle-on"

@ -913,19 +913,6 @@ update key flags inav settings msg model =
Nothing ->
resultModel model
TogglePdfNativeView default ->
resultModel
{ model
| pdfNativeView =
case model.pdfNativeView of
Just flag ->
Just (not flag)
Nothing ->
Just (not default)
, attachmentDropdownOpen = False
}
DeleteAttachConfirmed attachId ->
let
cmd =

@ -28,6 +28,7 @@ import Data.DropdownStyle as DS
import Data.Fields exposing (Field)
import Data.Flags exposing (Flags)
import Data.ItemTemplate as IT exposing (ItemTemplate)
import Data.Pdf exposing (PdfMode)
import Data.TagOrder
import Data.UiSettings exposing (ItemPattern, Pos(..), UiSettings)
import Dict exposing (Dict)
@ -50,7 +51,8 @@ type alias Model =
, searchPageSizeModel : Comp.IntField.Model
, tagColors : Dict String Color
, tagColorModel : Comp.ColorTagger.Model
, nativePdfPreview : Bool
, pdfMode : PdfMode
, pdfModeModel : Comp.FixedDropdown.Model PdfMode
, itemSearchNoteLength : Maybe Int
, searchNoteLengthModel : Comp.IntField.Model
, searchMenuFolderCount : Maybe Int
@ -122,7 +124,8 @@ init flags settings =
Comp.ColorTagger.init
[]
Data.Color.all
, nativePdfPreview = settings.nativePdfPreview
, pdfMode = settings.pdfMode
, pdfModeModel = Comp.FixedDropdown.init Data.Pdf.allModes
, itemSearchNoteLength = Just settings.itemSearchNoteLength
, searchNoteLengthModel =
Comp.IntField.init
@ -169,7 +172,6 @@ type Msg
= SearchPageSizeMsg Comp.IntField.Msg
| TagColorMsg Comp.ColorTagger.Msg
| GetTagsResp (Result Http.Error TagList)
| TogglePdfPreview
| NoteLengthMsg Comp.IntField.Msg
| SearchMenuFolderMsg Comp.IntField.Msg
| SearchMenuTagMsg Comp.IntField.Msg
@ -185,6 +187,7 @@ type Msg
| ToggleSideMenuVisible
| TogglePowerSearch
| UiLangMsg (Comp.FixedDropdown.Msg UiLanguage)
| PdfModeMsg (Comp.FixedDropdown.Msg PdfMode)
@ -290,15 +293,6 @@ update sett msg model =
in
( model_, nextSettings )
TogglePdfPreview ->
let
flag =
not model.nativePdfPreview
in
( { model | nativePdfPreview = flag }
, Just { sett | nativePdfPreview = flag }
)
GetTagsResp (Ok tl) ->
let
categories =
@ -463,6 +457,22 @@ update sett msg model =
Just { sett | uiLang = newLang }
)
PdfModeMsg lm ->
let
( m, sel ) =
Comp.FixedDropdown.update lm model.pdfModeModel
newMode =
Maybe.withDefault model.pdfMode sel
in
( { model | pdfModeModel = m, pdfMode = newMode }
, if newMode == model.pdfMode then
Nothing
else
Just { sett | pdfMode = newMode }
)
--- View2
@ -516,6 +526,13 @@ settingFormTabs texts flags _ model =
, style = DS.mainStyle
, selectPlaceholder = texts.basics.selectPlaceholder
}
pdfModeCfg =
{ display = texts.pdfMode
, icon = \_ -> Nothing
, style = DS.mainStyle
, selectPlaceholder = texts.basics.selectPlaceholder
}
in
[ { name = "general"
, title = texts.general
@ -689,13 +706,14 @@ settingFormTabs texts flags _ model =
, info = Nothing
, body =
[ div [ class "mb-4" ]
[ MB.viewItem <|
MB.Checkbox
{ tagger = \_ -> TogglePdfPreview
, label = texts.browserNativePdfView
, value = model.nativePdfPreview
, id = "uisetting-pdfpreview-toggle"
}
[ label [ class S.inputLabel ] [ text texts.browserNativePdfView ]
, Html.map PdfModeMsg
(Comp.FixedDropdown.viewStyled2
pdfModeCfg
False
(Just model.pdfMode)
model.pdfModeModel
)
]
, div [ class "mb-4" ]
[ MB.viewItem <|

@ -41,6 +41,7 @@ type alias Config =
type alias Flags =
{ account : Maybe AuthResult
, pdfSupported : Bool
, config : Config
}

@ -0,0 +1,67 @@
module Data.Pdf exposing (PdfMode(..), allModes, asString, detectUrl, fromString, serverUrl)
{-| Makes use of the fact, that docspell uses a `/view` suffix on the
path to provide a browser independent PDF view.
-}
import Data.Flags exposing (Flags)
import Html exposing (..)
import Html.Attributes exposing (..)
type PdfMode
= Detect
| Native
| Server
allModes : List PdfMode
allModes =
[ Detect, Native, Server ]
asString : PdfMode -> String
asString mode =
case mode of
Detect ->
"detect"
Native ->
"native"
Server ->
"server"
fromString : String -> Maybe PdfMode
fromString str =
case String.toLower str of
"detect" ->
Just Detect
"native" ->
Just Native
"server" ->
Just Server
_ ->
Nothing
serverUrl : String -> String
serverUrl url =
if String.endsWith "/" url then
url ++ "view"
else
url ++ "/view"
detectUrl : Flags -> String -> String
detectUrl flags url =
if flags.pdfSupported then
url
else
serverUrl url

@ -20,6 +20,7 @@ module Data.UiSettings exposing
, fieldVisible
, merge
, mergeDefaults
, pdfUrl
, posFromString
, posToString
, storedUiSettingsDecoder
@ -34,7 +35,9 @@ import Api.Model.Tag exposing (Tag)
import Data.BasicSize exposing (BasicSize)
import Data.Color exposing (Color)
import Data.Fields exposing (Field)
import Data.Flags exposing (Flags)
import Data.ItemTemplate exposing (ItemTemplate)
import Data.Pdf exposing (PdfMode)
import Data.UiTheme exposing (UiTheme)
import Dict exposing (Dict)
import Html exposing (Attribute)
@ -57,7 +60,7 @@ force default settings.
type alias StoredUiSettings =
{ itemSearchPageSize : Maybe Int
, tagCategoryColors : List ( String, String )
, nativePdfPreview : Bool
, pdfMode : Maybe String
, itemSearchNoteLength : Maybe Int
, itemDetailNotesPosition : Maybe String
, searchMenuFolderCount : Maybe Int
@ -91,7 +94,7 @@ storedUiSettingsDecoder =
Decode.succeed StoredUiSettings
|> P.optional "itemSearchPageSize" maybeInt Nothing
|> P.optional "tagCategoryColors" (Decode.keyValuePairs Decode.string) []
|> P.optional "nativePdfPreview" Decode.bool False
|> P.optional "pdfMode" maybeString Nothing
|> P.optional "itemSearchNoteLength" maybeInt Nothing
|> P.optional "itemDetailNotesPosition" maybeString Nothing
|> P.optional "searchMenuFolderCount" maybeInt Nothing
@ -121,7 +124,7 @@ storedUiSettingsEncode value =
Encode.object
[ ( "itemSearchPageSize", maybeEnc Encode.int value.itemSearchPageSize )
, ( "tagCategoryColors", Encode.dict identity Encode.string (Dict.fromList value.tagCategoryColors) )
, ( "nativePdfPreview", Encode.bool value.nativePdfPreview )
, ( "pdfMode", maybeEnc Encode.string value.pdfMode )
, ( "itemSearchNoteLength", maybeEnc Encode.int value.itemSearchNoteLength )
, ( "itemDetailNotesPosition", maybeEnc Encode.string value.itemDetailNotesPosition )
, ( "searchMenuFolderCount", maybeEnc Encode.int value.searchMenuFolderCount )
@ -146,14 +149,15 @@ storedUiSettingsEncode value =
{-| Settings for the web ui. These fields are all mandatory, since
there is always a default value.
When loaded from local storage, all optional fields can fallback to a
default value, converting the StoredUiSettings into a UiSettings.
When loaded from local storage or the server, all optional fields can
fallback to a default value, converting the StoredUiSettings into a
UiSettings.
-}
type alias UiSettings =
{ itemSearchPageSize : Int
, tagCategoryColors : Dict String Color
, nativePdfPreview : Bool
, pdfMode : PdfMode
, itemSearchNoteLength : Int
, itemDetailNotesPosition : Pos
, searchMenuFolderCount : Int
@ -219,7 +223,7 @@ defaults : UiSettings
defaults =
{ itemSearchPageSize = 60
, tagCategoryColors = Dict.empty
, nativePdfPreview = False
, pdfMode = Data.Pdf.Detect
, itemSearchNoteLength = 0
, itemDetailNotesPosition = Bottom
, searchMenuFolderCount = 3
@ -259,7 +263,10 @@ merge given fallback =
|> Dict.map (\_ -> Maybe.withDefault Data.Color.Grey)
)
fallback.tagCategoryColors
, nativePdfPreview = given.nativePdfPreview
, pdfMode =
given.pdfMode
|> Maybe.andThen Data.Pdf.fromString
|> Maybe.withDefault fallback.pdfMode
, itemSearchNoteLength =
choose given.itemSearchNoteLength fallback.itemSearchNoteLength
, itemDetailNotesPosition =
@ -313,7 +320,7 @@ toStoredUiSettings settings =
, tagCategoryColors =
Dict.map (\_ -> Data.Color.toString) settings.tagCategoryColors
|> Dict.toList
, nativePdfPreview = settings.nativePdfPreview
, pdfMode = Just (Data.Pdf.asString settings.pdfMode)
, itemSearchNoteLength = Just settings.itemSearchNoteLength
, itemDetailNotesPosition = Just (posToString settings.itemDetailNotesPosition)
, searchMenuFolderCount = Just settings.searchMenuFolderCount
@ -407,6 +414,19 @@ cardPreviewSize2 settings =
"max-h-80"
pdfUrl : UiSettings -> Flags -> String -> String
pdfUrl settings flags originalUrl =
case settings.pdfMode of
Data.Pdf.Detect ->
Data.Pdf.detectUrl flags originalUrl
Data.Pdf.Native ->
originalUrl
Data.Pdf.Server ->
Data.Pdf.serverUrl originalUrl
--- Helpers

@ -13,9 +13,11 @@ module Messages.Comp.UiSettingsForm exposing
import Data.Color exposing (Color)
import Data.Fields exposing (Field)
import Data.Pdf exposing (PdfMode)
import Messages.Basics
import Messages.Data.Color
import Messages.Data.Fields
import Messages.Data.PdfMode
type alias Texts =
@ -53,6 +55,7 @@ type alias Texts =
, fieldsInfo : String
, fieldLabel : Field -> String
, templateHelpMessage : String
, pdfMode : PdfMode -> String
}
@ -127,6 +130,7 @@ for example `{{corrOrg|corrPerson|-}}` would render the organization
and if that is not present the person. If both are absent a dash `-`
is rendered.
"""
, pdfMode = Messages.Data.PdfMode.gb
}
@ -203,4 +207,5 @@ verknüpft werden, bis zur ersten die einen Wert enthält. Zum Beispiel:
oder, wenn diese leer ist, die Person. Sind beide leer wird ein `-`
dargestellt.
"""
, pdfMode = Messages.Data.PdfMode.de
}

@ -0,0 +1,39 @@
{-
Copyright 2020 Eike K. & Contributors
SPDX-License-Identifier: AGPL-3.0-or-later
-}
module Messages.Data.PdfMode exposing
( de
, gb
)
import Data.Pdf exposing (PdfMode(..))
gb : PdfMode -> String
gb st =
case st of
Detect ->
"Detect automatically"
Native ->
"Use the browser's native PDF view"
Server ->
"Use cross-browser fallback"
de : PdfMode -> String
de st =
case st of
Detect ->
"Automatisch ermitteln"
Native ->
"Browsernative Darstellung"
Server ->
"Browserübergreifende Ersatzdarstellung"

@ -460,7 +460,7 @@ searchStats texts _ settings model =
itemCardList : Texts -> Flags -> UiSettings -> Model -> List (Html Msg)
itemCardList texts _ settings model =
itemCardList texts flags settings model =
let
previewUrl attach =
Api.attachmentPreviewURL attach.id
@ -489,6 +489,7 @@ itemCardList texts _ settings model =
(Comp.ItemCardList.view2 texts.itemCardList
itemViewCfg
settings
flags
model.itemListModel
)
, loadMore texts settings model

@ -9,6 +9,7 @@ module Page.Share.Results exposing (view)
import Api
import Comp.ItemCardList
import Data.Flags exposing (Flags)
import Data.ItemSelection
import Data.UiSettings exposing (UiSettings)
import Html exposing (..)
@ -18,8 +19,8 @@ import Page exposing (Page(..))
import Page.Share.Data exposing (Model, Msg(..))
view : Texts -> UiSettings -> String -> Model -> Html Msg
view texts settings shareId model =
view : Texts -> UiSettings -> Flags -> String -> Model -> Html Msg
view texts settings flags shareId model =
let
viewCfg =
{ current = Nothing
@ -32,5 +33,5 @@ view texts settings shareId model =
in
div []
[ Html.map ItemListMsg
(Comp.ItemCardList.view2 texts.itemCardList viewCfg settings model.itemListModel)
(Comp.ItemCardList.view2 texts.itemCardList viewCfg settings flags model.itemListModel)
]

@ -63,7 +63,7 @@ viewContent texts flags versionInfo uiSettings shareId model =
mainContent : Texts -> Flags -> UiSettings -> String -> Model -> Html Msg
mainContent texts _ settings shareId model =
mainContent texts flags settings shareId model =
div
[ id "content"
, class "h-full flex flex-col"
@ -76,7 +76,7 @@ mainContent texts _ settings shareId model =
[ text <| Maybe.withDefault "" model.verifyResult.name
]
, Menubar.view texts model
, Results.view texts settings shareId model
, Results.view texts settings flags shareId model
]