markdown icon indicating copy to clipboard operation
markdown copied to clipboard

Links in markdown do not trigger onUrlRequest in Browser.application

Open owanturist opened this issue 6 years ago • 4 comments

Hi @evancz! Thanks for great work with 0.19 - community was waiting for this for a long time, you know.

However, I've got an unexpected behaviour of interaction between Browser.application and Markdown. The problem is Markdown's links don't work like external links in case when they are linked with internal routes ("/" for example). Furthermore clicks to the links don't trigger neither onUrlRequest nor onUrlChange - browser just load a page from scratch.

I guess it happens because the module insert links as is and without handling of click event.

I've made an Ellie example but it won't work inside of the sandbox so you should run it locally thru elm reactor.

owanturist avatar Aug 29 '18 12:08 owanturist

Can you get the example down to something smaller? When you do that, please share it directly in the thread, not in an Ellie link. It is easier when it's included directly.

evancz avatar Aug 29 '18 18:08 evancz

@evancz no problem:

module Main exposing (main)

import Browser
import Browser.Navigation as Navigation
import Html exposing (Html, a, br, div, h2, text)
import Html.Attributes exposing (href)
import Html.Events exposing (onClick)
import Markdown
import Url exposing (Url)
import Url.Parser exposing (s, top)


type Route
    = ToHome
    | ToMarkdown
    | ToNotFound


matchRoute : Url -> Route
matchRoute url =
    Url.Parser.parse
        (Url.Parser.oneOf
            [ Url.Parser.map ToHome top
            , Url.Parser.map ToMarkdown (s "markdown")
            ]
        )
        url
        |> Maybe.withDefault ToNotFound


type alias Model =
    { route : Route
    , key : Navigation.Key
    }


init : Url -> Navigation.Key -> ( Model, Cmd Msg )
init url key =
    ( Model (matchRoute url) key
    , Cmd.none
    )


type Msg
    = UrlChanged Url
    | UrlRequested Browser.UrlRequest


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        UrlChanged url ->
            ( { model | route = matchRoute url }
            , Cmd.none
            )

        UrlRequested (Browser.Internal url) ->
            ( model
            , Navigation.pushUrl model.key (Url.toString url)
            )

        UrlRequested (Browser.External uri) ->
            ( model
            , Navigation.load uri
            )


view : Model -> Browser.Document Msg
view model =
    case model.route of
        ToHome ->
            Browser.Document "Home"
                [ a [ href "/markdown" ] [ text "Link from Home to Markdown" ]
                ]

        ToMarkdown ->
            Browser.Document "Markdown"
                [ h2 [] [ text "Markdown" ]
                , Markdown.toHtml [] """[Link from Markdown to Home](/)."""
                , h2 [] [ text "Elm Html" ]
                , a [ href "/" ] [ text "Link from Markdown to Home" ]
                ]

        ToNotFound ->
            Browser.Document "404"
                [ a [ href "/" ] [ text "Link from 404 to Home" ]
                , br [] []
                , a [ href "/markdown" ] [ text "Link from 404 to Markdown" ]
                ]


main : Program () Model Msg
main =
    Browser.application
        { init = always init
        , view = view
        , update = update
        , subscriptions = always Sub.none
        , onUrlRequest = UrlRequested
        , onUrlChange = UrlChanged
        }

owanturist avatar Aug 30 '18 02:08 owanturist

For completeness sake: It's not working right on package.elm-lang.org right now. Go to this page https://package.elm-lang.org/packages/elm/browser/latest/Browser-Navigation and click on the first link to Browser.application and watch the page do a full reload.

ChristophP avatar Sep 18 '18 21:09 ChristophP

This is also an issue for me. My use case is to add support for markdown links to modules functions/values/types in elm-doc-preview, see https://github.com/dmy/elm-doc-preview/issues/1.

Here is a slightly smaller SSCCE:

module Main exposing (main)

import Browser exposing (UrlRequest(..))
import Browser.Navigation exposing (Key)
import Html exposing (Html, a, div, h4, text)
import Html.Attributes exposing (href)
import Markdown
import Url exposing (Url)


type alias Urls =
    List String


type Msg
    = UrlRequested UrlRequest
    | UrlChanged Url


body : Urls -> List (Html msg)
body urls =
    [ a [ href "/standard" ] [ text "standard anchor link" ]
    , Markdown.toHtml [] "[markdown link](markdown)"
    , div [] <| List.map (\u -> div [] [ text u ]) urls
    ]


update : Msg -> Urls -> ( Urls, Cmd Msg )
update msg model =
    case msg of
        UrlRequested request ->
            case request of
                Internal url ->
                    ( Url.toString url :: model, Cmd.none )

                External string ->
                    ( string :: model, Cmd.none )

        UrlChanged _ ->
            ( model, Cmd.none )


main : Program () Urls Msg
main =
    Browser.application
        { init = \_ url key -> ( [], Cmd.none )
        , view = \model -> { title = "", body = body model }
        , update = update
        , subscriptions = always Sub.none
        , onUrlRequest = UrlRequested
        , onUrlChange = UrlChanged
        }

Clicking the first standard a link add the url to the list of requested ones, clicking the markdown one reloads the page.

rlefevre avatar Sep 19 '18 09:09 rlefevre