diff --git a/ts/modules/accounts.ts b/ts/modules/accounts.ts index 0d1a8b7..cbf6209 100644 --- a/ts/modules/accounts.ts +++ b/ts/modules/accounts.ts @@ -7,8 +7,6 @@ import { SearchConfiguration, QueryType, SearchableItem, SearchableItemDataAttri import { HiddenInputField } from "./ui" import { PaginatedList } from "./list" -// FIXME: Find and define a threshold after which searches are no longer performed on input (or just in general by the browser). - declare var window: GlobalWindow; const USER_DEFAULT_SORT_FIELD = "name"; @@ -976,9 +974,6 @@ export class accountsList extends PaginatedList { }); this._populateNumbers(); - // FIXME: Remove! - (window as any).acc = this; - let searchConfig: SearchConfiguration = { filterArea: this._c.filterArea, sortingByButton: this._sortingByButton, diff --git a/ts/modules/activity.ts b/ts/modules/activity.ts index 708199a..94af779 100644 --- a/ts/modules/activity.ts +++ b/ts/modules/activity.ts @@ -533,9 +533,6 @@ export class activityList extends PaginatedList { } }); - // FIXME: Remove! - (window as any).act = this; - this._container = document.getElementById("activity-card-list") document.addEventListener("activity-reload", () => this.reload()); @@ -583,7 +580,7 @@ export class activityList extends PaginatedList { // Setting default sort makes sense, since this is the only sort ever being done. this._c.defaultSortAscending = this.ascending; this._sortDirection.innerHTML = `${window.lang.strings("sortDirection")} `; - // FIXME?: We don't actually re-sort the list here, instead just use setOrdering to apply this.ascending before a reload. + // NOTE: We don't actually re-sort the list here, instead just use setOrdering to apply this.ascending before a reload. this._search.setOrdering(this._search.ordering, this._c.defaultSortField, this.ascending); if (this._hasLoaded) { if (this._search.inServerSearch) { diff --git a/ts/modules/common.ts b/ts/modules/common.ts index e417431..768591f 100644 --- a/ts/modules/common.ts +++ b/ts/modules/common.ts @@ -1,4 +1,5 @@ declare var window: GlobalWindow; +import dateParser from "any-date-parser"; export function toDateString(date: Date): string { const locale = window.language || (window as any).navigator.userLanguage || window.navigator.language; @@ -21,6 +22,20 @@ export function toDateString(date: Date): string { return date.toLocaleDateString(locale, args1) + " " + date.toLocaleString(locale, args2); } +export const parseDateString = (value: string): ParsedDate => { + let out: ParsedDate = { + text: value, + // Used just to tell use what fields the user passed. + attempt: dateParser.attempt(value), + // note Date.fromString is also provided by dateParser. + date: (Date as any).fromString(value) as Date + }; + out.attempt.offsetMinutesFromUTC = out.date.getTimezoneOffset(); + // Month in Date objects is 0-based, so make our parsed date that way too + if ("month" in out.attempt) out.attempt.month -= 1; + return out; +} + export const _get = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, noConnectionError: boolean = false): void => { let req = new XMLHttpRequest(); if (window.pages) { url = window.pages.Base + url; } diff --git a/ts/modules/list.ts b/ts/modules/list.ts index 9b0d6a4..4c25366 100644 --- a/ts/modules/list.ts +++ b/ts/modules/list.ts @@ -4,6 +4,10 @@ import "@af-utils/scrollend-polyfill"; declare var window: GlobalWindow; +export interface ListItem { + asElement: () => HTMLElement; +}; + export class RecordCounter { private _container: HTMLElement; private _totalRecords: HTMLElement; @@ -342,7 +346,7 @@ export abstract class PaginatedList { this.lastPage = resp.last_page; appendFunc(resp); - + this._counter.loaded = this._search.ordering.length; if (post) post(resp); diff --git a/ts/modules/search.ts b/ts/modules/search.ts index 3b2a871..8d4d139 100644 --- a/ts/modules/search.ts +++ b/ts/modules/search.ts @@ -1,4 +1,5 @@ -const dateParser = require("any-date-parser"); +import { ListItem } from "./list"; +import { parseDateString } from "./common"; declare var window: GlobalWindow; @@ -176,20 +177,6 @@ export class StringQuery extends Query { } } -export interface DateAttempt { - year?: number; - month?: number; - day?: number; - hour?: number; - minute?: number -} - -export interface ParsedDate { - attempt: DateAttempt; - date: Date; - text: string; -}; - const dateGetters: Map number> = (() => { let m = new Map number>(); m.set("year", Date.prototype.getFullYear); @@ -222,24 +209,15 @@ export class DateQuery extends Query { ${subject.name}: ${dateText != "" ? dateText+" " : ""}${value.text} `; } + public static paramsFromString(valueString: string): [ParsedDate, QueryOperator, boolean] { - // FIXME: Validate this! let op = QueryOperator.Equal; if ((Object.values(QueryOperator) as string[]).includes(valueString.charAt(0))) { op = valueString.charAt(0) as QueryOperator; // Trim the operator from the string valueString = valueString.substring(1); } - - let out: ParsedDate = { - text: valueString, - // Used just to tell use what fields the user passed. - attempt: dateParser.attempt(valueString), - // note Date.fromString is also provided by dateParser. - date: (Date as any).fromString(valueString) as Date - }; - // Month in Date objects is 0-based, so make our parsed date that way too - if ("month" in out.attempt) out.attempt.month -= 1; + let out = parseDateString(valueString); let isValid = true; if ("invalid" in (out.date as any)) { isValid = false; }; @@ -278,10 +256,8 @@ export class DateQuery extends Query { } } -export interface SearchableItem { +export interface SearchableItem extends ListItem { matchesSearch: (query: string) => boolean; - // FIXME: SearchableItem should really be ListItem or something, this isn't for search! - asElement: () => HTMLElement; } export const SearchableItemDataAttribute = "data-search-item"; @@ -598,7 +574,6 @@ export class Search { this._c.search.oninput(null as any); }; - // FIXME: Make XQuery classes less specifically for in-progress searches, and include this code for making info button things. generateFilterList = () => { // Generate filter buttons for (let queryName of Object.keys(this._c.queries)) { diff --git a/ts/typings/d.ts b/ts/typings/d.ts index a1df5c8..e3c5a3c 100644 --- a/ts/typings/d.ts +++ b/ts/typings/d.ts @@ -161,5 +161,20 @@ interface PaginatedReqDTO { ascending: boolean; }; +interface DateAttempt { + year?: number; + month?: number; + day?: number; + hour?: number; + minute?: number; + offsetMinutesFromUTC?: number; +} + +interface ParsedDate { + attempt: DateAttempt; + date: Date; + text: string; +}; + declare var config: Object; declare var modifiedConfig: Object; diff --git a/usercache.go b/usercache.go index 07e6868..b26be92 100644 --- a/usercache.go +++ b/usercache.go @@ -235,11 +235,12 @@ const ( }*/ type DateAttempt struct { - Year *int `json:"year,omitempty"` - Month *int `json:"month,omitempty"` - Day *int `json:"day,omitempty"` - Hour *int `json:"hour,omitempty"` - Minute *int `json:"minute,omitempty"` + Year *int `json:"year,omitempty"` + Month *int `json:"month,omitempty"` + Day *int `json:"day,omitempty"` + Hour *int `json:"hour,omitempty"` + Minute *int `json:"minute,omitempty"` + OffsetMinutesFromUTC *int `json:"offsetMinutesFromUTC,omitempty"` } // Compare roughly compares a time.Time to a DateAttempt. diff --git a/views.go b/views.go index be574b4..c13191f 100644 --- a/views.go +++ b/views.go @@ -67,9 +67,10 @@ func (app *appContext) pushResources(gc *gin.Context, page Page) { default: toPush = []string{} } + urlBase := app.getURLBase(gc) if pusher := gc.Writer.Pusher(); pusher != nil { for _, f := range toPush { - if err := pusher.Push(PAGES.Base+f, nil); err != nil { + if err := pusher.Push(urlBase+f, nil); err != nil { app.debug.Printf(lm.FailedServerPush, err) } } @@ -172,6 +173,10 @@ func (app *appContext) getLang(gc *gin.Context, page Page, chosen string) string func (app *appContext) AdminPage(gc *gin.Context) { app.pushResources(gc, AdminPage) + + // Pre-emptively (maybe) generate user cache + go app.userCache.MaybeSync(app) + lang := app.getLang(gc, AdminPage, app.storage.lang.chosenAdminLang) jfAdminOnly := app.config.Section("ui").Key("admin_only").MustBool(true) jfAllowAll := app.config.Section("ui").Key("allow_all").MustBool(false)