<commit_before>module Common.Views exposing (..)

import String
import Json.Decode
import Html exposing (Html, h2, div, nav, textarea, button, span, ul, li, img, a, em, strong, text)
import Html.Attributes exposing (class, rows, value, disabled, href, src, title)
import Html.Events exposing (defaultOptions, onWithOptions, onClick, onInput)
import Common.Models exposing (MessageThread, Message, Banner, ReplyInformation, Breadcrumb, ChapterOverview, Narration, NarrationOverview, NarrationStatus(..), narrationStatusString)


onPreventDefaultClick : msg -> Html.Attribute msg
onPreventDefaultClick message =
  onWithOptions
    "click"
    { defaultOptions | preventDefault = True }
    (Json.Decode.succeed message)


onStopPropagationClick : msg -> Html.Attribute msg
onStopPropagationClick message =
  onWithOptions
    "click"
    { defaultOptions | stopPropagation = True }
    (Json.Decode.succeed message)


messageView : Message -> Html msg
messageView message =
  div [ class "message" ]
    [ strong []
        [ text (case message.sender of
                  Just sender -> sender.name
                  Nothing -> "Narrator")
        ]
    , text ": "
    , span [ class (case message.sender of
                      Just sender -> ""
                      Nothing -> "narrator")
           ]
        [ text message.body ]
    ]


messageThreadInteractionView : Maybe Int -> msg -> (String -> msg) -> msg -> msg -> Maybe ReplyInformation -> Bool -> MessageThread -> Html msg
messageThreadInteractionView maybeCharacterId showReplyMessage updateReplyMessage sendReplyMessage closeReplyMessage maybeReply replyButtonDisabled thread =
  let
    replyButtonDiv =
      div [ class "btn-bar" ]
        [ button [ class "btn btn-small"
                 , onClick showReplyMessage
                 ]
            [ text "Reply" ]
        ]

    replyBoxDiv =
      case maybeReply of
        Just reply ->
          if reply.recipients == thread.participants then
            div []
              [ textarea [ rows 4
                         , value reply.body
                         , onInput updateReplyMessage
                         ]
                  [ text reply.body ]
              , div [ class "btn-bar" ]
                  [ button [ class "btn btn-default btn-small"
                           , onClick sendReplyMessage
                           , disabled replyButtonDisabled
                           ]
                      [ text "Send" ]
                  , button [ class "btn btn-small"
                           , onClick closeReplyMessage
                           ]
                      [ text "Close" ]
                  ]
              ]
          else
            replyButtonDiv

        Nothing ->
          replyButtonDiv
  in
    messageThreadView maybeCharacterId [ replyBoxDiv ] thread


messageThreadView : Maybe Int -> List (Html msg) -> MessageThread -> Html msg
messageThreadView maybeCharacterId extraUi thread =
  let
    participants =
      List.map
        (\c -> c.name)
        (case maybeCharacterId of
          Just characterId ->
            List.filter (\c -> c.id /= characterId) thread.participants
          Nothing ->
            thread.participants)

    participantString =
      String.join ", " participants

    participantStringEnd =
      case maybeCharacterId of
        Nothing ->
          if List.length participants > 1 then
            ", and you"
          else
            " and you"

        Just _ ->
          if List.length participants > 0 then
            ", the narrator, and you"
          else
            "the narrator and you"

    participantsDiv =
      div [ class "thread-participants" ]
        [ text ("Between " ++ participantString ++ participantStringEnd) ]
  in
    li []
      (List.concat
        [ [ participantsDiv ]
        , List.map messageView thread.messages
        , extraUi
        ])


loadingView : Maybe Banner -> Html msg
loadingView maybeBanner =
  div []
    [ bannerView maybeBanner
    , text "Loading…"
    ]


bannerView : Maybe Banner -> Html msg
bannerView maybeBanner =
  case maybeBanner of
    Just banner ->
      div [ class <| "banner banner-" ++ banner.type_ ]
        [ text banner.text ]

    Nothing ->
      text ""


linkTo : (String -> msg) -> String -> List (Html.Attribute msg)
linkTo message url =
  [ href url
  , onPreventDefaultClick (message url)
  ]


breadcrumbView : (String -> msg) -> Breadcrumb -> Html msg
breadcrumbView messageConstructor link =
  a (linkTo messageConstructor link.url)
    [ text link.title ]


breadcrumbNavView : (String -> msg) -> List Breadcrumb -> Html msg -> Html msg
breadcrumbNavView messageConstructor links pageTitle =
  let
    parts =
      List.concat
        [ (List.map (breadcrumbView messageConstructor) links)
        , [ pageTitle ]
        ]
  in
    nav [ class "breadcrumbs" ]
      (List.intersperse
        (text " ⇢ ")
        parts)


unpublishedChapterView : (String -> msg) -> Narration -> ChapterOverview -> Html msg
unpublishedChapterView navigationMessage narration chapterOverview =
  let
    numberChapterParticipants = List.length chapterOverview.participants
    numberNarrationCharacters = List.length narration.characters
  in
    li []
      [ a (linkTo
             navigationMessage
             ("/chapters/" ++ (toString chapterOverview.id) ++ "/edit"))
          [ text chapterOverview.title
          ]
      , text " — "
      , em [] [ text "Draft" ]
      , if numberNarrationCharacters /= numberChapterParticipants then
          text (" — only " ++ (toString numberChapterParticipants) ++
                " participants")
        else
          text ""
      ]
<commit_msg>Make draft chapter information more consistent<commit_after>module Common.Views exposing (..)

import String
import Json.Decode
import Html exposing (Html, h2, div, nav, textarea, button, span, ul, li, img, a, em, strong, text)
import Html.Attributes exposing (class, rows, value, disabled, href, src, title)
import Html.Events exposing (defaultOptions, onWithOptions, onClick, onInput)
import Common.Models exposing (MessageThread, Message, Banner, ReplyInformation, Breadcrumb, ChapterOverview, Narration, NarrationOverview, NarrationStatus(..), narrationStatusString)


onPreventDefaultClick : msg -> Html.Attribute msg
onPreventDefaultClick message =
  onWithOptions
    "click"
    { defaultOptions | preventDefault = True }
    (Json.Decode.succeed message)


onStopPropagationClick : msg -> Html.Attribute msg
onStopPropagationClick message =
  onWithOptions
    "click"
    { defaultOptions | stopPropagation = True }
    (Json.Decode.succeed message)


messageView : Message -> Html msg
messageView message =
  div [ class "message" ]
    [ strong []
        [ text (case message.sender of
                  Just sender -> sender.name
                  Nothing -> "Narrator")
        ]
    , text ": "
    , span [ class (case message.sender of
                      Just sender -> ""
                      Nothing -> "narrator")
           ]
        [ text message.body ]
    ]


messageThreadInteractionView : Maybe Int -> msg -> (String -> msg) -> msg -> msg -> Maybe ReplyInformation -> Bool -> MessageThread -> Html msg
messageThreadInteractionView maybeCharacterId showReplyMessage updateReplyMessage sendReplyMessage closeReplyMessage maybeReply replyButtonDisabled thread =
  let
    replyButtonDiv =
      div [ class "btn-bar" ]
        [ button [ class "btn btn-small"
                 , onClick showReplyMessage
                 ]
            [ text "Reply" ]
        ]

    replyBoxDiv =
      case maybeReply of
        Just reply ->
          if reply.recipients == thread.participants then
            div []
              [ textarea [ rows 4
                         , value reply.body
                         , onInput updateReplyMessage
                         ]
                  [ text reply.body ]
              , div [ class "btn-bar" ]
                  [ button [ class "btn btn-default btn-small"
                           , onClick sendReplyMessage
                           , disabled replyButtonDisabled
                           ]
                      [ text "Send" ]
                  , button [ class "btn btn-small"
                           , onClick closeReplyMessage
                           ]
                      [ text "Close" ]
                  ]
              ]
          else
            replyButtonDiv

        Nothing ->
          replyButtonDiv
  in
    messageThreadView maybeCharacterId [ replyBoxDiv ] thread


messageThreadView : Maybe Int -> List (Html msg) -> MessageThread -> Html msg
messageThreadView maybeCharacterId extraUi thread =
  let
    participants =
      List.map
        (\c -> c.name)
        (case maybeCharacterId of
          Just characterId ->
            List.filter (\c -> c.id /= characterId) thread.participants
          Nothing ->
            thread.participants)

    participantString =
      String.join ", " participants

    participantStringEnd =
      case maybeCharacterId of
        Nothing ->
          if List.length participants > 1 then
            ", and you"
          else
            " and you"

        Just _ ->
          if List.length participants > 0 then
            ", the narrator, and you"
          else
            "the narrator and you"

    participantsDiv =
      div [ class "thread-participants" ]
        [ text ("Between " ++ participantString ++ participantStringEnd) ]
  in
    li []
      (List.concat
        [ [ participantsDiv ]
        , List.map messageView thread.messages
        , extraUi
        ])


loadingView : Maybe Banner -> Html msg
loadingView maybeBanner =
  div []
    [ bannerView maybeBanner
    , text "Loading…"
    ]


bannerView : Maybe Banner -> Html msg
bannerView maybeBanner =
  case maybeBanner of
    Just banner ->
      div [ class <| "banner banner-" ++ banner.type_ ]
        [ text banner.text ]

    Nothing ->
      text ""


linkTo : (String -> msg) -> String -> List (Html.Attribute msg)
linkTo message url =
  [ href url
  , onPreventDefaultClick (message url)
  ]


breadcrumbView : (String -> msg) -> Breadcrumb -> Html msg
breadcrumbView messageConstructor link =
  a (linkTo messageConstructor link.url)
    [ text link.title ]


breadcrumbNavView : (String -> msg) -> List Breadcrumb -> Html msg -> Html msg
breadcrumbNavView messageConstructor links pageTitle =
  let
    parts =
      List.concat
        [ (List.map (breadcrumbView messageConstructor) links)
        , [ pageTitle ]
        ]
  in
    nav [ class "breadcrumbs" ]
      (List.intersperse
        (text " ⇢ ")
        parts)


unpublishedChapterView : (String -> msg) -> Narration -> ChapterOverview -> Html msg
unpublishedChapterView navigationMessage narration chapterOverview =
  let
    numberChapterParticipants = List.length chapterOverview.participants
    numberNarrationCharacters = List.length narration.characters
    participantNames = String.join ", " <|
        List.map
          (\r -> r.name)
          chapterOverview.participants
  in
    li []
      [ a (linkTo
             navigationMessage
             ("/chapters/" ++ (toString chapterOverview.id) ++ "/edit"))
          [ text chapterOverview.title
          ]
      , text " — "
      , em [] [ text "Draft" ]
      , if numberNarrationCharacters /= numberChapterParticipants then
          span [ title <| "Only for " ++ participantNames ]
            [ text " — "
            , img [ src "/img/character.png" ] []
            , text <| toString numberChapterParticipants
            ]
        else
          text ""
      ]

{'fraction_non_alphanumeric': 0.0865533230293663, 'fraction_numerical': 0.0006869311351537008, 'mean_word_length': 1.8836345630106461, 'pattern_counts': {'":': 2, '<': 8, '<?xml version=': 0, '>': 98, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7088791', 'n_tokens_mistral': 3106, 'n_tokens_neox': 2946, 'n_words': 848}