diff --git a/frontend/src/uxbox/main.cljs b/frontend/src/uxbox/main.cljs index 63bf8a1b0..aff80f4bc 100644 --- a/frontend/src/uxbox/main.cljs +++ b/frontend/src/uxbox/main.cljs @@ -20,7 +20,6 @@ [uxbox.main.ui.modal :refer [modal]] [uxbox.main.worker] [uxbox.util.dom :as dom] - [uxbox.util.html.history :as html-history] [uxbox.util.i18n :as i18n] [uxbox.util.theme :as theme] [uxbox.util.router :as rt] @@ -29,38 +28,33 @@ (declare reinit) -(defn- on-navigate +(defn on-navigate [router path] (let [match (rt/match router path) profile (:profile storage)] (cond (and (= path "") (not profile)) - (st/emit! (rt/nav :login)) + (rt/nav :login) (and (= path "") profile) - (st/emit! (rt/nav :dashboard-team {:team-id (:default-team-id profile)})) + (rt/nav :dashboard-team {:team-id (:default-team-id profile)}) (nil? match) - (st/emit! (rt/nav :not-found)) + (rt/nav :not-found) :else - (st/emit! #(assoc % :route match))))) + #(assoc % :route match)))) (defn init-ui [] - (let [router (rt/init ui/routes) - cpath (deref html-history/path)] + (st/emit! (rt/initialize-router ui/routes) + (rt/initialize-history on-navigate)) - (st/emit! #(assoc % :router router)) - (add-watch html-history/path ::main #(on-navigate router %4)) + (when (:profile storage) + (st/emit! udu/fetch-profile)) - (when (:profile storage) - (st/emit! udu/fetch-profile)) - - (mf/mount (mf/element ui/app) (dom/get-element "app")) - (mf/mount (mf/element modal) (dom/get-element "modal")) - - (on-navigate router cpath))) + (mf/mount (mf/element ui/app) (dom/get-element "app")) + (mf/mount (mf/element modal) (dom/get-element "modal"))) (defn ^:export init [] @@ -73,7 +67,6 @@ (defn reinit [] - (remove-watch html-history/path ::main) (mf/unmount (dom/get-element "app")) (mf/unmount (dom/get-element "modal")) (init-ui)) diff --git a/frontend/src/uxbox/main/fonts.cljs b/frontend/src/uxbox/main/fonts.cljs index 2b89e33c6..0780bfd13 100644 --- a/frontend/src/uxbox/main/fonts.cljs +++ b/frontend/src/uxbox/main/fonts.cljs @@ -83,7 +83,7 @@ (group-by :backend (vals db))))) (add-watch fontsdb "main" (fn [_ _ _ db] - (ts/schedule-on-idle #(materialize-fontsview db)))) + (ts/schedule #(materialize-fontsview db)))) (defn register! [backend fonts] diff --git a/frontend/src/uxbox/main/ui/components/chunked_list.cljs b/frontend/src/uxbox/main/ui/components/chunked_list.cljs index e2a13cd93..ad8d0694e 100644 --- a/frontend/src/uxbox/main/ui/components/chunked_list.cljs +++ b/frontend/src/uxbox/main/ui/components/chunked_list.cljs @@ -12,7 +12,7 @@ (:require [beicon.core :as rx] [rumext.alpha :as mf] - [uxbox.util.timers :refer [schedule-on-idle]])) + [uxbox.util.timers :refer [schedule]])) (mf/defc chunked-list [{:keys [items children initial-size chunk-size] @@ -34,7 +34,7 @@ :pending-num (- pending-num chunk-size)})) (after-render [state] (when (pos? (:pending-num @state)) - (let [sem (schedule-on-idle (fn [] (swap! state update-state)))] + (let [sem (schedule (fn [] (swap! state update-state)))] #(rx/cancel! sem))))] (let [initial (mf/use-memo initial-state) diff --git a/frontend/src/uxbox/util/browser_history.js b/frontend/src/uxbox/util/browser_history.js new file mode 100644 index 000000000..74e263b06 --- /dev/null +++ b/frontend/src/uxbox/util/browser_history.js @@ -0,0 +1,49 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This Source Code Form is "Incompatible With Secondary Licenses", as + * defined by the Mozilla Public License, v. 2.0. + * + * Copyright (c) 2020 UXBOX Labs SL + */ + +"use strict"; + +goog.provide("uxbox.util.browser_history"); +goog.require("goog.history.Html5History"); + + +goog.scope(function() { + const self = uxbox.util.browser_history; + const Html5History = goog.history.Html5History; + + class TokenTransformer { + retrieveToken(pathPrefix, location) { + return location.pathname.substr(pathPrefix.length) + location.search; + } + + createUrl(token, pathPrefix, location) { + return pathPrefix + token; + } + } + + self.create = function() { + const instance = new Html5History(null, new TokenTransformer()); + instance.setUseFragment(true); + return instance; + }; + + self.enable_BANG_ = function(instance) { + instance.setEnabled(true); + }; + + self.disable_BANG_ = function(instance) { + instance.setEnabled(false); + }; + + self.set_token_BANG_ = function(instance, token) { + instance.setToken(token); + } +}); diff --git a/frontend/src/uxbox/util/components.cljs b/frontend/src/uxbox/util/components.cljs index c343910dd..1b3d78f20 100644 --- a/frontend/src/uxbox/util/components.cljs +++ b/frontend/src/uxbox/util/components.cljs @@ -9,7 +9,7 @@ (:require [beicon.core :as rx] [rumext.alpha :as mf] - [uxbox.util.timers :refer [schedule-on-idle]])) + [uxbox.util.timers :refer [schedule]])) ;; TODO: this file is DEPRECATED (pending deletion) @@ -33,7 +33,7 @@ :pending-num (- pending-num chunk-size)})) (after-render [state] (when (pos? (:pending-num @state)) - (let [sem (schedule-on-idle (fn [] (swap! state update-state)))] + (let [sem (schedule (fn [] (swap! state update-state)))] #(rx/cancel! sem))))] (let [initial (mf/use-memo initial-state) diff --git a/frontend/src/uxbox/util/html/TokenTransformer.js b/frontend/src/uxbox/util/html/TokenTransformer.js deleted file mode 100644 index be81568bb..000000000 --- a/frontend/src/uxbox/util/html/TokenTransformer.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * TokenTransformer - * - * @author Paul Anderson , 2018 - * @license BSD License - */ - -goog.provide('uxbox.util.html.TokenTransformer'); -goog.require('goog.history.Html5History'); - -goog.scope(function() { - /** - * A goog.history.Html5History.TokenTransformer implementation that - * includes the query string in the token. - * - * The implementation of token<->url transforms in - * `goog.history.Html5History`, when useFragment is false and no custom - * transformer is supplied, assumes that a token is equivalent to - * `window.location.pathname` minus any configured path prefix. Since - * bide allows constructing urls that include a query string, we want - * to be able to store those as tokens. - * - * Addresses funcool/bide#15. - * - * @constructor - * @implements {goog.history.Html5History.TokenTransformer} - */ - uxbox.util.html.TokenTransformer = function () {}; - - /** - * Retrieves a history token given the path prefix and - * `window.location` object. - * - * @param {string} pathPrefix The path prefix to use when storing token - * in a path; always begin with a slash. - * @param {Location} location The `window.location` object. - * Treat this object as read-only. - * @return {string} token The history token. - */ - uxbox.util.html.TokenTransformer.prototype.retrieveToken = function(pathPrefix, location) { - return location.pathname.substr(pathPrefix.length) + location.search; - }; - - /** - * Creates a URL to be pushed into HTML5 history stack when storing - * token without using hash fragment. - * - * @param {string} token The history token. - * @param {string} pathPrefix The path prefix to use when storing token - * in a path; always begin with a slash. - * @param {Location} location The `window.location` object. - * Treat this object as read-only. - * @return {string} url The complete URL string from path onwards - * (without {@code protocol://host:port} part); must begin with a - * slash. - */ - uxbox.util.html.TokenTransformer.prototype.createUrl = function(token, pathPrefix, location) { - return pathPrefix + token; - }; -}); diff --git a/frontend/src/uxbox/util/html/history.cljs b/frontend/src/uxbox/util/html/history.cljs deleted file mode 100644 index e41c6824e..000000000 --- a/frontend/src/uxbox/util/html/history.cljs +++ /dev/null @@ -1,31 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) 2019 Andrey Antukh - -(ns uxbox.util.html.history - "A singleton abstraction for the html5 fragment based history." - (:require [goog.events :as e]) - (:import uxbox.util.html.TokenTransformer - goog.history.Html5History - goog.history.EventType)) - -(defonce ^:private +instance+ - (doto (Html5History. nil (TokenTransformer.)) - (.setUseFragment true) - (.setEnabled true))) - -(defonce path (atom (.getToken +instance+))) - -(defonce ^:private +instance-sem+ - (e/listen +instance+ EventType.NAVIGATE - #(reset! path (.-token %)))) - -(defn set-path! - [path] - (.setToken +instance+ path)) - -(defn replace-path! - [path] - (.replaceToken +instance+ path)) diff --git a/frontend/src/uxbox/util/router.cljs b/frontend/src/uxbox/util/router.cljs index d38bf610a..3fee9cce1 100644 --- a/frontend/src/uxbox/util/router.cljs +++ b/frontend/src/uxbox/util/router.cljs @@ -7,16 +7,19 @@ (ns uxbox.util.router (:refer-clojure :exclude [resolve]) (:require + [beicon.core :as rx] + [rumext.alpha :as mf] [reitit.core :as r] + [goog.events :as e] [cuerdas.core :as str] [potok.core :as ptk] - [uxbox.common.data :as d] - [uxbox.util.html.history :as html-history]) + [uxbox.util.browser-history :as bhistory] + [uxbox.common.data :as d]) (:import goog.Uri goog.Uri.QueryData)) -;; --- API +;; --- Router API (defn- parse-query-data [^QueryData qdata] @@ -50,10 +53,17 @@ (.setQueryData uri qdt) (.toString uri)))))) -(defn init +(defn create [routes] (r/router routes)) +(defn initialize-router + [routes] + (ptk/reify ::initialize-router + ptk/UpdateEvent + (update [_ state] + (assoc state :router (create routes))))) + (defn query-params "Given goog.Uri, read query parameters into Clojure map." [^goog.Uri uri] @@ -63,13 +73,6 @@ (map (juxt keyword #(.get q %))) (into {})))) -(defn navigate! - ([router id] (navigate! router id {} {})) - ([router id params] (navigate! router id params {})) - ([router id params qparams] - (-> (resolve router id params qparams) - (html-history/set-path!)))) - (defn match "Given routing tree and current path, return match with possibly coerced parameters. Return nil if no match found." @@ -87,8 +90,10 @@ (deftype Navigate [id params qparams] ptk/EffectEvent (effect [_ state stream] - (let [router (:router state)] - (navigate! router id params qparams)))) + (let [router (:router state) + history (:history state) + path (resolve router id params qparams)] + (bhistory/set-token! history path)))) (defn nav ([id] (nav id nil nil)) @@ -99,3 +104,30 @@ (def navigate nav) +;; --- History API + +(defn initialize-history + [on-change] + (ptk/reify ::initialize-history + ptk/UpdateEvent + (update [_ state] + (let [history (bhistory/create)] + (assoc state :history history))) + + ptk/WatchEvent + (watch [_ state stream] + (let [stoper (rx/filter (ptk/type? ::initialize-history) stream) + history (:history state) + router (:router state)] + (->> (rx/create (fn [sink] + (let [key (e/listen history "navigate" #(sink (.-token %)))] + (bhistory/enable! history) + (fn [] + (bhistory/disable! history) + (e/unlistenByKey key))))) + (rx/map #(on-change router %)) + (rx/take-until stoper)))))) + + + + diff --git a/frontend/src/uxbox/util/timers.cljs b/frontend/src/uxbox/util/timers.cljs index fb91729fa..57531058c 100644 --- a/frontend/src/uxbox/util/timers.cljs +++ b/frontend/src/uxbox/util/timers.cljs @@ -2,7 +2,10 @@ ;; License, v. 2.0. If a copy of the MPL was not distributed with this ;; file, You can obtain one at http://mozilla.org/MPL/2.0/. ;; -;; Copyright (c) 2016-2019 Andrey Antukh +;; This Source Code Form is "Incompatible With Secondary Licenses", as +;; defined by the Mozilla Public License, v. 2.0. +;; +;; Copyright (c) 2020 UXBOX Labs SL (ns uxbox.util.timers (:require [beicon.core :as rx]))