From b91bdeb450b0afe9fcb24aba4f383f5d22143b79 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Wed, 4 Mar 2020 23:57:27 +0100 Subject: [PATCH] Remove reloading and fix issues with state not being refreshed (#232) * Remove reloading and fix issues with state not being refreshed * Fix PR comments * Remove unnecessary closure * Change proc to anonymous proc * categoryIdOption -> categoryId --- src/frontend/categorylist.nim | 4 +++- src/frontend/categorypicker.nim | 3 +-- src/frontend/forum.nim | 4 ---- src/frontend/header.nim | 31 +++++++++++++----------------- src/frontend/karaxutils.nim | 1 - src/frontend/mainbuttons.nim | 21 +++++++++++--------- src/frontend/threadlist.nim | 34 ++++++++++++++++++++------------- 7 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/frontend/categorylist.nim b/src/frontend/categorylist.nim index b61694a..3c0e533 100644 --- a/src/frontend/categorylist.nim +++ b/src/frontend/categorylist.nim @@ -13,6 +13,7 @@ when defined(js): State = ref object list: Option[CategoryList] loading: bool + mainButtons: MainButtons status: HttpCode addCategoryModal: AddCategoryModal @@ -22,6 +23,7 @@ when defined(js): State( list: none[CategoryList](), loading: false, + mainButtons: newMainButtons(), status: Http200, addCategoryModal: newAddCategoryModal( onAddCategory= @@ -99,5 +101,5 @@ when defined(js): proc renderCategoryList*(currentUser: Option[User]): VNode = result = buildHtml(tdiv): - renderMainButtons(currentUser) + state.mainButtons.render(currentUser) renderCategories(currentUser) diff --git a/src/frontend/categorypicker.nim b/src/frontend/categorypicker.nim index 38f9300..f26f6c1 100644 --- a/src/frontend/categorypicker.nim +++ b/src/frontend/categorypicker.nim @@ -105,8 +105,7 @@ when defined(js): render(state.addCategoryModal) proc render*(state: CategoryPicker, currentUser: Option[User], compact=true): VNode = - if currentUser.isAdmin(): - state.setAddEnabled(true) + state.setAddEnabled(currentUser.isAdmin()) if state.status != Http200: return renderError("Couldn't retrieve categories.", state.status) diff --git a/src/frontend/forum.nim b/src/frontend/forum.nim index bccbcf6..da74eab 100644 --- a/src/frontend/forum.nim +++ b/src/frontend/forum.nim @@ -57,10 +57,6 @@ proc onPopState(event: dom.Event) = state = newState() # Reload the state to remove stale data. state.url = copyLocation(window.location) - # For some reason this is needed so that the back/forward buttons reload - # the post list when different categories are selected - window.location.reload() - redraw() type Params = Table[string, string] diff --git a/src/frontend/header.nim b/src/frontend/header.nim index 679c8fa..cde48de 100644 --- a/src/frontend/header.nim +++ b/src/frontend/header.nim @@ -32,41 +32,36 @@ when defined(js): var state = newState() - proc getStatus(logout=false, reload=false) + proc getStatus(logout=false) proc newState(): State = State( data: none[UserStatus](), loading: false, status: Http200, loginModal: newLoginModal( - () => (state.lastUpdate = fromUnix(0); getStatus(reload=true)), + () => (state.lastUpdate = fromUnix(0); getStatus()), () => state.signupModal.show() ), signupModal: newSignupModal( - () => (state.lastUpdate = fromUnix(0); getStatus(reload=true)), + () => (state.lastUpdate = fromUnix(0); getStatus()), () => state.loginModal.show() ), userMenu: newUserMenu( - () => (state.lastUpdate = fromUnix(0); getStatus(logout=true, reload=true)) + () => (state.lastUpdate = fromUnix(0); getStatus(logout=true)) ) ) - proc onStatus(reload: bool=false): proc (httpStatus: int, response: kstring) = - result = - proc (httpStatus: int, response: kstring) = - state.loading = false - state.status = httpStatus.HttpCode - if state.status != Http200: return + proc onStatus(httpStatus: int, response: kstring) = + state.loading = false + state.status = httpStatus.HttpCode + if state.status != Http200: return - let parsed = parseJson($response) - state.data = some(to(parsed, UserStatus)) + let parsed = parseJson($response) + state.data = some(to(parsed, UserStatus)) - state.lastUpdate = getTime() + state.lastUpdate = getTime() - if reload: - window.location.reload() - - proc getStatus(logout=false, reload=false) = + proc getStatus(logout=false) = if state.loading: return let diff = getTime() - state.lastUpdate if diff.inMinutes < 5: @@ -74,7 +69,7 @@ when defined(js): state.loading = true let uri = makeUri("status.json", [("logout", $logout)]) - ajaxGet(uri, @[], onStatus(reload)) + ajaxGet(uri, @[], onStatus) proc getLoggedInUser*(): Option[User] = state.data.map(x => x.user).flatten diff --git a/src/frontend/karaxutils.nim b/src/frontend/karaxutils.nim index cc26cd0..f70ec5d 100644 --- a/src/frontend/karaxutils.nim +++ b/src/frontend/karaxutils.nim @@ -97,7 +97,6 @@ when defined(js): let url = n.getAttr("href") navigateTo(url) - window.location.href = url proc newFormData*(form: dom.Element): FormData {.importcpp: "new FormData(@)", constructor.} diff --git a/src/frontend/mainbuttons.nim b/src/frontend/mainbuttons.nim index 9f4d4f8..c91d354 100644 --- a/src/frontend/mainbuttons.nim +++ b/src/frontend/mainbuttons.nim @@ -17,17 +17,20 @@ when defined(js): navigateTo(uri) type - State = ref object + MainButtons* = ref object categoryPicker: CategoryPicker + onCategoryChange*: CategoryChangeEvent - proc newState(): State = - State( - categoryPicker: newCategoryPicker(onCategoryChange=onSelectedCategoryChanged), + proc newMainButtons*(onCategoryChange: CategoryChangeEvent = onSelectedCategoryChanged): MainButtons = + new result + result.onCategoryChange = onCategoryChange + result.categoryPicker = newCategoryPicker( + onCategoryChange = proc (oldCategory, newCategory: Category) = + onSelectedCategoryChanged(oldCategory, newCategory) + result.onCategoryChange(oldCategory, newCategory) ) - let state = newState() - - proc renderMainButtons*(currentUser: Option[User], categoryIdOption = none(int)): VNode = + proc render*(state: MainButtons, currentUser: Option[User], categoryId = none(int)): VNode = result = buildHtml(): section(class="navbar container grid-xl", id="main-buttons"): section(class="navbar-section"): @@ -38,8 +41,8 @@ when defined(js): ul(class="menu"): li: text "community" li: text "dev" ]# - if categoryIdOption.isSome: - state.categoryPicker.selectedCategoryID = categoryIdOption.get() + if categoryId.isSome: + state.categoryPicker.selectedCategoryID = categoryId.get() render(state.categoryPicker, currentUser, compact=false) for btn in buttons: diff --git a/src/frontend/threadlist.nim b/src/frontend/threadlist.nim index f300cf9..8a2a5ed 100644 --- a/src/frontend/threadlist.nim +++ b/src/frontend/threadlist.nim @@ -26,6 +26,7 @@ proc isModerated*(thread: Thread): bool = thread.author.rank <= Moderated when defined(js): + import sugar include karax/prelude import karax / [vstyles, kajax, kdom] @@ -34,18 +35,25 @@ when defined(js): type State = ref object list: Option[ThreadList] + refreshList: bool loading: bool status: HttpCode + mainButtons: MainButtons + + var state: State proc newState(): State = State( list: none[ThreadList](), loading: false, - status: Http200 + status: Http200, + mainButtons: newMainButtons( + onCategoryChange = + (oldCategory: Category, newCategory: Category) => (state.list = none[ThreadList]()) + ) ) - var - state = newState() + state = newState() proc visibleTo*[T](thread: T, user: Option[User]): bool = ## Determines whether the specified thread (or post) should be @@ -147,11 +155,11 @@ when defined(js): else: state.list = some(list) - proc onLoadMore(ev: Event, n: VNode, categoryIdOption: Option[int]) = + proc onLoadMore(ev: Event, n: VNode, categoryId: Option[int]) = state.loading = true let start = state.list.get().threads.len - if categoryIdOption.isSome: - ajaxGet(makeUri("threads.json?start=" & $start & "&categoryId=" & $categoryIdOption.get()), @[], onThreadList) + if categoryId.isSome: + ajaxGet(makeUri("threads.json?start=" & $start & "&categoryId=" & $categoryId.get()), @[], onThreadList) else: ajaxGet(makeUri("threads.json?start=" & $start), @[], onThreadList) @@ -178,15 +186,15 @@ when defined(js): isNew: thread.creation > previousVisitAt ) - proc genThreadList(currentUser: Option[User], categoryIdOption: Option[int]): VNode = + proc genThreadList(currentUser: Option[User], categoryId: Option[int]): VNode = if state.status != Http200: return renderError("Couldn't retrieve threads.", state.status) if state.list.isNone: if not state.loading: state.loading = true - if categoryIdOption.isSome: - ajaxGet(makeUri("threads.json?categoryId=" & $categoryIdOption.get()), @[], onThreadList) + if categoryId.isSome: + ajaxGet(makeUri("threads.json?categoryId=" & $categoryId.get()), @[], onThreadList) else: ajaxGet(makeUri("threads.json"), @[], onThreadList) @@ -229,10 +237,10 @@ when defined(js): tdiv(class="loading loading-lg") else: td(colspan="6", - onClick = (ev: Event, n: VNode) => (onLoadMore(ev, n, categoryIdOption))): + onClick = (ev: Event, n: VNode) => (onLoadMore(ev, n, categoryId))): span(text "load more threads") - proc renderThreadList*(currentUser: Option[User], categoryIdOption = none(int)): VNode = + proc renderThreadList*(currentUser: Option[User], categoryId = none(int)): VNode = result = buildHtml(tdiv): - renderMainButtons(currentUser, categoryIdOption=categoryIdOption) - genThreadList(currentUser, categoryIdOption) + state.mainButtons.render(currentUser, categoryId=categoryId) + genThreadList(currentUser, categoryId)