elm-explorations / markdown

Markdown parser available for historical reasons. Will be replaced when we have an Elm implementation!
BSD 3-Clause "New" or "Revised" License
30 stars 3 forks source link

Links in markdown do not trigger onUrlRequest in Browser.application #1

Open owanturist opened 6 years ago

owanturist commented 6 years ago

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.

evancz commented 6 years ago

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.

owanturist commented 6 years ago

@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
        }
ChristophP commented 6 years ago

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.

rlefevre commented 6 years ago

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.