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
This commit is contained in:
Dominik Picheta 2020-03-04 23:57:27 +01:00 • committed by GitHub
commit b91bdeb450
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 50 additions and 48 deletions

View file

@ -13,6 +13,7 @@ when defined(js):
State = ref object State = ref object
list: Option[CategoryList] list: Option[CategoryList]
loading: bool loading: bool
mainButtons: MainButtons
status: HttpCode status: HttpCode
addCategoryModal: AddCategoryModal addCategoryModal: AddCategoryModal
@ -22,6 +23,7 @@ when defined(js):
State( State(
list: none[CategoryList](), list: none[CategoryList](),
loading: false, loading: false,
mainButtons: newMainButtons(),
status: Http200, status: Http200,
addCategoryModal: newAddCategoryModal( addCategoryModal: newAddCategoryModal(
onAddCategory= onAddCategory=
@ -99,5 +101,5 @@ when defined(js):
proc renderCategoryList*(currentUser: Option[User]): VNode = proc renderCategoryList*(currentUser: Option[User]): VNode =
result = buildHtml(tdiv): result = buildHtml(tdiv):
renderMainButtons(currentUser) state.mainButtons.render(currentUser)
renderCategories(currentUser) renderCategories(currentUser)

View file

@ -105,8 +105,7 @@ when defined(js):
render(state.addCategoryModal) render(state.addCategoryModal)
proc render*(state: CategoryPicker, currentUser: Option[User], compact=true): VNode = proc render*(state: CategoryPicker, currentUser: Option[User], compact=true): VNode =
if currentUser.isAdmin(): state.setAddEnabled(currentUser.isAdmin())
state.setAddEnabled(true)
if state.status != Http200: if state.status != Http200:
return renderError("Couldn't retrieve categories.", state.status) return renderError("Couldn't retrieve categories.", state.status)

View file

@ -57,10 +57,6 @@ proc onPopState(event: dom.Event) =
state = newState() # Reload the state to remove stale data. state = newState() # Reload the state to remove stale data.
state.url = copyLocation(window.location) 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() redraw()
type Params = Table[string, string] type Params = Table[string, string]

View file

@ -32,41 +32,36 @@ when defined(js):
var var
state = newState() state = newState()
proc getStatus(logout=false, reload=false) proc getStatus(logout=false)
proc newState(): State = proc newState(): State =
State( State(
data: none[UserStatus](), data: none[UserStatus](),
loading: false, loading: false,
status: Http200, status: Http200,
loginModal: newLoginModal( loginModal: newLoginModal(
() => (state.lastUpdate = fromUnix(0); getStatus(reload=true)), () => (state.lastUpdate = fromUnix(0); getStatus()),
() => state.signupModal.show() () => state.signupModal.show()
), ),
signupModal: newSignupModal( signupModal: newSignupModal(
() => (state.lastUpdate = fromUnix(0); getStatus(reload=true)), () => (state.lastUpdate = fromUnix(0); getStatus()),
() => state.loginModal.show() () => state.loginModal.show()
), ),
userMenu: newUserMenu( 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) = proc onStatus(httpStatus: int, response: kstring) =
result = state.loading = false
proc (httpStatus: int, response: kstring) = state.status = httpStatus.HttpCode
state.loading = false if state.status != Http200: return
state.status = httpStatus.HttpCode
if state.status != Http200: return
let parsed = parseJson($response) let parsed = parseJson($response)
state.data = some(to(parsed, UserStatus)) state.data = some(to(parsed, UserStatus))
state.lastUpdate = getTime() state.lastUpdate = getTime()
if reload: proc getStatus(logout=false) =
window.location.reload()
proc getStatus(logout=false, reload=false) =
if state.loading: return if state.loading: return
let diff = getTime() - state.lastUpdate let diff = getTime() - state.lastUpdate
if diff.inMinutes < 5: if diff.inMinutes < 5:
@ -74,7 +69,7 @@ when defined(js):
state.loading = true state.loading = true
let uri = makeUri("status.json", [("logout", $logout)]) let uri = makeUri("status.json", [("logout", $logout)])
ajaxGet(uri, @[], onStatus(reload)) ajaxGet(uri, @[], onStatus)
proc getLoggedInUser*(): Option[User] = proc getLoggedInUser*(): Option[User] =
state.data.map(x => x.user).flatten state.data.map(x => x.user).flatten

View file

@ -97,7 +97,6 @@ when defined(js):
let url = n.getAttr("href") let url = n.getAttr("href")
navigateTo(url) navigateTo(url)
window.location.href = url
proc newFormData*(form: dom.Element): FormData proc newFormData*(form: dom.Element): FormData
{.importcpp: "new FormData(@)", constructor.} {.importcpp: "new FormData(@)", constructor.}

View file

@ -17,17 +17,20 @@ when defined(js):
navigateTo(uri) navigateTo(uri)
type type
State = ref object MainButtons* = ref object
categoryPicker: CategoryPicker categoryPicker: CategoryPicker
onCategoryChange*: CategoryChangeEvent
proc newState(): State = proc newMainButtons*(onCategoryChange: CategoryChangeEvent = onSelectedCategoryChanged): MainButtons =
State( new result
categoryPicker: newCategoryPicker(onCategoryChange=onSelectedCategoryChanged), result.onCategoryChange = onCategoryChange
result.categoryPicker = newCategoryPicker(
onCategoryChange = proc (oldCategory, newCategory: Category) =
onSelectedCategoryChanged(oldCategory, newCategory)
result.onCategoryChange(oldCategory, newCategory)
) )
let state = newState() proc render*(state: MainButtons, currentUser: Option[User], categoryId = none(int)): VNode =
proc renderMainButtons*(currentUser: Option[User], categoryIdOption = none(int)): VNode =
result = buildHtml(): result = buildHtml():
section(class="navbar container grid-xl", id="main-buttons"): section(class="navbar container grid-xl", id="main-buttons"):
section(class="navbar-section"): section(class="navbar-section"):
@ -38,8 +41,8 @@ when defined(js):
ul(class="menu"): ul(class="menu"):
li: text "community" li: text "community"
li: text "dev" ]# li: text "dev" ]#
if categoryIdOption.isSome: if categoryId.isSome:
state.categoryPicker.selectedCategoryID = categoryIdOption.get() state.categoryPicker.selectedCategoryID = categoryId.get()
render(state.categoryPicker, currentUser, compact=false) render(state.categoryPicker, currentUser, compact=false)
for btn in buttons: for btn in buttons:

View file

@ -26,6 +26,7 @@ proc isModerated*(thread: Thread): bool =
thread.author.rank <= Moderated thread.author.rank <= Moderated
when defined(js): when defined(js):
import sugar
include karax/prelude include karax/prelude
import karax / [vstyles, kajax, kdom] import karax / [vstyles, kajax, kdom]
@ -34,18 +35,25 @@ when defined(js):
type type
State = ref object State = ref object
list: Option[ThreadList] list: Option[ThreadList]
refreshList: bool
loading: bool loading: bool
status: HttpCode status: HttpCode
mainButtons: MainButtons
var state: State
proc newState(): State = proc newState(): State =
State( State(
list: none[ThreadList](), list: none[ThreadList](),
loading: false, 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 = proc visibleTo*[T](thread: T, user: Option[User]): bool =
## Determines whether the specified thread (or post) should be ## Determines whether the specified thread (or post) should be
@ -147,11 +155,11 @@ when defined(js):
else: else:
state.list = some(list) 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 state.loading = true
let start = state.list.get().threads.len let start = state.list.get().threads.len
if categoryIdOption.isSome: if categoryId.isSome:
ajaxGet(makeUri("threads.json?start=" & $start & "&categoryId=" & $categoryIdOption.get()), @[], onThreadList) ajaxGet(makeUri("threads.json?start=" & $start & "&categoryId=" & $categoryId.get()), @[], onThreadList)
else: else:
ajaxGet(makeUri("threads.json?start=" & $start), @[], onThreadList) ajaxGet(makeUri("threads.json?start=" & $start), @[], onThreadList)
@ -178,15 +186,15 @@ when defined(js):
isNew: thread.creation > previousVisitAt 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: if state.status != Http200:
return renderError("Couldn't retrieve threads.", state.status) return renderError("Couldn't retrieve threads.", state.status)
if state.list.isNone: if state.list.isNone:
if not state.loading: if not state.loading:
state.loading = true state.loading = true
if categoryIdOption.isSome: if categoryId.isSome:
ajaxGet(makeUri("threads.json?categoryId=" & $categoryIdOption.get()), @[], onThreadList) ajaxGet(makeUri("threads.json?categoryId=" & $categoryId.get()), @[], onThreadList)
else: else:
ajaxGet(makeUri("threads.json"), @[], onThreadList) ajaxGet(makeUri("threads.json"), @[], onThreadList)
@ -229,10 +237,10 @@ when defined(js):
tdiv(class="loading loading-lg") tdiv(class="loading loading-lg")
else: else:
td(colspan="6", 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") 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): result = buildHtml(tdiv):
renderMainButtons(currentUser, categoryIdOption=categoryIdOption) state.mainButtons.render(currentUser, categoryId=categoryId)
genThreadList(currentUser, categoryIdOption) genThreadList(currentUser, categoryId)