From 1204104b8fa41569e49fde80c127186cd4cbf471 Mon Sep 17 00:00:00 2001 From: Christophe de Vienne Date: Fri, 1 Apr 2022 12:02:49 +0200 Subject: [PATCH] Move 'Editor' to the page stack --- src/Main.elm | 61 +++++++------------ src/Page/Article/Editor.elm | 113 ++++++++++++++++++++---------------- src/Route.elm | 15 ++++- 3 files changed, 100 insertions(+), 89 deletions(-) diff --git a/src/Main.elm b/src/Main.elm index 2581c037d0..8899c6f886 100644 --- a/src/Main.elm +++ b/src/Main.elm @@ -40,7 +40,6 @@ import Viewer exposing (Viewer) type Model = Redirect Session | NotFound Session - | Editor (Maybe Slug) Editor.Model | Stack Session StackModel @@ -53,26 +52,30 @@ type alias StackModel = type alias StackCurrentModel = - Article.Model + Editor.Model type alias StackPreviousModel = Spa.PageStack.Model Never - Register.Model + Article.Model (Spa.PageStack.Model Never - Login.Model + Register.Model (Spa.PageStack.Model Never - Profile.Model + Login.Model (Spa.PageStack.Model Never - Settings.Model + Profile.Model (Spa.PageStack.Model Never - Home.Model - (Spa.PageStack.Model Never () ()) + Settings.Model + (Spa.PageStack.Model + Never + Home.Model + (Spa.PageStack.Model Never () ()) + ) ) ) ) @@ -84,23 +87,27 @@ type alias StackMsg = type alias StackCurrentMsg = - Article.Msg + Editor.Msg type alias StackPreviousMsg = Spa.PageStack.Msg Route - Register.Msg + Article.Msg (Spa.PageStack.Msg Route - Login.Msg + Register.Msg (Spa.PageStack.Msg Route - Profile.Msg + Login.Msg (Spa.PageStack.Msg Route - Settings.Msg - (Spa.PageStack.Msg Route Home.Msg (Spa.PageStack.Msg Route () ())) + Profile.Msg + (Spa.PageStack.Msg + Route + Settings.Msg + (Spa.PageStack.Msg Route Home.Msg (Spa.PageStack.Msg Route () ())) + ) ) ) ) @@ -119,6 +126,7 @@ stack = |> Spa.PageStack.add ( View.map, View.map ) Route.matchLogin (Login.page >> Ok) |> Spa.PageStack.add ( View.map, View.map ) Route.matchRegister (Register.page >> Ok) |> Spa.PageStack.add ( View.map, View.map ) Route.matchArticle (Article.page >> Ok) + |> Spa.PageStack.add ( View.map, View.map ) Route.matchEditor (Editor.page >> Ok) @@ -157,12 +165,6 @@ view model = NotFound _ -> Page.view viewer Page.Other NotFound.view - Editor Nothing editor -> - viewPage Page.NewArticle GotEditorMsg (Editor.view editor) - - Editor (Just _) editor -> - viewPage Page.Other GotEditorMsg (Editor.view editor) - Stack session stackmodel -> let page = @@ -178,7 +180,6 @@ view model = type Msg = ChangedUrl Url | ClickedLink Browser.UrlRequest - | GotEditorMsg Editor.Msg | GotSession Session | StackMsg StackMsg | SessionMsg Session.Msg @@ -194,9 +195,6 @@ toSession page = NotFound session -> session - Editor _ editor -> - Editor.toSession editor - Stack session _ -> session @@ -217,14 +215,6 @@ changeRouteTo maybeRoute model = Just Route.Logout -> ( model, Api.logout ) - Just Route.NewArticle -> - Editor.initNew session - |> updateWith (Editor Nothing) GotEditorMsg model - - Just (Route.EditArticle slug) -> - Editor.initEdit session slug - |> updateWith (Editor (Just slug)) GotEditorMsg model - Just route -> let ( newStack, effect ) = @@ -269,10 +259,6 @@ update msg model = ( ChangedUrl url, _ ) -> changeRouteTo (Route.fromUrl url) model - ( GotEditorMsg subMsg, Editor slug editor ) -> - Editor.update subMsg editor - |> updateWith (Editor slug) GotEditorMsg model - ( GotSession session, Redirect _ ) -> ( Redirect session , Route.replaceUrl (Session.navKey session) Route.Home @@ -315,9 +301,6 @@ subscriptions model = Redirect _ -> Session.changes GotSession (Session.navKey (toSession model)) - Editor _ editor -> - Sub.map GotEditorMsg (Editor.subscriptions editor) - Stack session stackmodel -> Sub.batch [ Sub.map StackMsg (stack.subscriptions session stackmodel) diff --git a/src/Page/Article/Editor.elm b/src/Page/Article/Editor.elm index d339cbfd26..2a39678bef 100644 --- a/src/Page/Article/Editor.elm +++ b/src/Page/Article/Editor.elm @@ -1,4 +1,4 @@ -module Page.Article.Editor exposing (Model, Msg, initEdit, initNew, subscriptions, toSession, update, view) +module Page.Article.Editor exposing (Model, Msg, page) import Api exposing (Cred) import Api.Endpoint as Endpoint @@ -6,6 +6,7 @@ import Article exposing (Article, Full) import Article.Body exposing (Body) import Article.Slug as Slug exposing (Slug) import Browser.Navigation as Nav +import Effect exposing (Effect) import Html exposing (..) import Html.Attributes exposing (attribute, class, disabled, href, id, placeholder, type_, value) import Html.Events exposing (onInput, onSubmit) @@ -17,8 +18,19 @@ import Page import Profile exposing (Profile) import Route import Session exposing (Session) +import Spa.Page import Task exposing (Task) import Time +import View exposing (View) + + +page session = + Spa.Page.element + { init = init session + , update = update session + , subscriptions = subscriptions + , view = view session + } @@ -26,8 +38,7 @@ import Time type alias Model = - { session : Session - , status : Status + { status : Status } @@ -57,10 +68,19 @@ type alias Form = } -initNew : Session -> ( Model, Cmd msg ) +init : Session -> Maybe Slug -> ( Model, Effect Session.Msg Msg ) +init session slug = + case slug of + Just s -> + initEdit session s + + Nothing -> + initNew session + + +initNew : Session -> ( Model, Effect Session.Msg Msg ) initNew session = - ( { session = session - , status = + ( { status = EditingNew [] { title = "" , body = "" @@ -68,23 +88,22 @@ initNew session = , tags = "" } } - , Cmd.none + , Effect.none ) -initEdit : Session -> Slug -> ( Model, Cmd Msg ) +initEdit : Session -> Slug -> ( Model, Effect Session.Msg Msg ) initEdit session slug = - ( { session = session - , status = Loading slug + ( { status = Loading slug } - , Cmd.batch + , Effect.batch [ Article.fetch (Session.cred session) slug |> Http.toTask -- If init fails, store the slug that failed in the msg, so we can -- at least have it later to display the page's title properly! |> Task.mapError (\httpError -> ( slug, httpError )) - |> Task.attempt CompletedArticleLoad - , Task.perform (\_ -> PassedSlowLoadThreshold) Loading.slowThreshold + |> Effect.attempt CompletedArticleLoad + , Effect.perform (\_ -> PassedSlowLoadThreshold) Loading.slowThreshold ] ) @@ -93,8 +112,8 @@ initEdit session slug = -- VIEW -view : Model -> { title : String, content : Html Msg } -view model = +view : Session -> Model -> View Msg +view session model = { title = case getSlug model.status of Just slug -> @@ -102,8 +121,15 @@ view model = Nothing -> "New Article" + , page = + case getSlug model.status of + Just slug -> + Page.Other + + Nothing -> + Page.NewArticle , content = - case Session.cred model.session of + case Session.cred session of Just cred -> viewAuthenticated cred model @@ -247,12 +273,11 @@ type Msg | CompletedCreate (Result Http.Error (Article Full)) | CompletedEdit (Result Http.Error (Article Full)) | CompletedArticleLoad (Result ( Slug, Http.Error ) (Article Full)) - | GotSession Session | PassedSlowLoadThreshold -update : Msg -> Model -> ( Model, Cmd Msg ) -update msg model = +update : Session -> Msg -> Model -> ( Model, Effect Session.Msg Msg ) +update session msg model = case msg of ClickedSave cred -> model.status @@ -274,28 +299,30 @@ update msg model = CompletedCreate (Ok article) -> ( model , Route.Article (Article.slug article) - |> Route.replaceUrl (Session.navKey model.session) + |> Route.replaceUrl (Session.navKey session) + |> Effect.fromCmd ) CompletedCreate (Err error) -> ( { model | status = savingError error model.status } - , Cmd.none + , Effect.none ) CompletedEdit (Ok article) -> ( model , Route.Article (Article.slug article) - |> Route.replaceUrl (Session.navKey model.session) + |> Route.replaceUrl (Session.navKey session) + |> Effect.fromCmd ) CompletedEdit (Err error) -> ( { model | status = savingError error model.status } - , Cmd.none + , Effect.none ) CompletedArticleLoad (Err ( slug, error )) -> ( { model | status = LoadingFailed slug } - , Cmd.none + , Effect.none ) CompletedArticleLoad (Ok article) -> @@ -313,12 +340,7 @@ update msg model = } in ( { model | status = status } - , Cmd.none - ) - - GotSession session -> - ( { model | session = session } - , Route.replaceUrl (Session.navKey session) Route.Home + , Effect.none ) PassedSlowLoadThreshold -> @@ -333,10 +355,10 @@ update msg model = other -> other in - ( { model | status = status }, Cmd.none ) + ( { model | status = status }, Effect.none ) -save : Cred -> Status -> ( Status, Cmd Msg ) +save : Cred -> Status -> ( Status, Effect Session.Msg Msg ) save cred status = case status of Editing slug _ form -> @@ -345,11 +367,12 @@ save cred status = ( Saving slug form , edit slug validForm cred |> Http.send CompletedEdit + |> Effect.fromCmd ) Err problems -> ( Editing slug problems form - , Cmd.none + , Effect.none ) EditingNew _ form -> @@ -358,11 +381,12 @@ save cred status = ( Creating form , create validForm cred |> Http.send CompletedCreate + |> Effect.fromCmd ) Err problems -> ( EditingNew problems form - , Cmd.none + , Effect.none ) _ -> @@ -372,7 +396,7 @@ save cred status = -- -- If we had an error logging service, we would send -- something to it here! - ( status, Cmd.none ) + ( status, Effect.none ) savingError : Http.Error -> Status -> Status @@ -393,7 +417,7 @@ savingError error status = {-| Helper function for `update`. Updates the form, if there is one, -and returns Cmd.none. +and returns Effect.none. Useful for recording form fields! @@ -401,7 +425,7 @@ This could also log errors to the server if we are trying to record things in the form and we don't actually have a form. -} -updateForm : (Form -> Form) -> Model -> ( Model, Cmd Msg ) +updateForm : (Form -> Form) -> Model -> ( Model, Effect Session.Msg Msg ) updateForm transform model = let newModel = @@ -427,7 +451,7 @@ updateForm transform model = Creating form -> { model | status = Creating (transform form) } in - ( newModel, Cmd.none ) + ( newModel, Effect.none ) @@ -435,8 +459,8 @@ updateForm transform model = subscriptions : Model -> Sub Msg -subscriptions model = - Session.changes GotSession (Session.navKey model.session) +subscriptions _ = + Sub.none @@ -561,15 +585,6 @@ edit articleSlug (Trimmed form) cred = --- EXPORT - - -toSession : Model -> Session -toSession model = - model.session - - - -- INTERNAL diff --git a/src/Route.elm b/src/Route.elm index f40e606e8c..ed9c9b1111 100644 --- a/src/Route.elm +++ b/src/Route.elm @@ -1,4 +1,4 @@ -module Route exposing (Route(..), fromUrl, href, matchArticle, matchHome, matchLogin, matchProfile, matchRegister, matchSettings, replaceUrl) +module Route exposing (Route(..), fromUrl, href, matchArticle, matchEditor, matchHome, matchLogin, matchProfile, matchRegister, matchSettings, replaceUrl) import Article.Slug as Slug exposing (Slug) import Browser.Navigation as Nav @@ -159,3 +159,16 @@ matchArticle route = _ -> Nothing + + +matchEditor : Route -> Maybe (Maybe Slug) +matchEditor route = + case route of + NewArticle -> + Just Nothing + + EditArticle slug -> + Just (Just slug) + + _ -> + Nothing