Răsfoiți Sursa

remove old srs implementation

Tienson Qin 4 zile în urmă
părinte
comite
5490824cfa

+ 2 - 12
src/main/frontend/components/content.cljs

@@ -11,7 +11,6 @@
             [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.extensions.fsrs :as fsrs]
-            [frontend.extensions.srs :as srs]
             [frontend.handler.common.developer :as dev-common-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.notification :as notification]
@@ -100,9 +99,7 @@
      (when (state/enable-flashcards?)
        (shui/dropdown-menu-item
         {:key "Make a Card"
-         :on-click #(if (config/db-based-graph? (state/get-current-repo))
-                      (fsrs/batch-make-cards!)
-                      (srs/batch-make-cards!))}
+         :on-click (fsrs/batch-make-cards!)}
         (t :context-menu/make-a-flashcard)))
 
      (shui/dropdown-menu-item
@@ -285,17 +282,10 @@
            (block-template block-id))
 
          (cond
-           (srs/card-block? block)
-           (shui/dropdown-menu-item
-            {:key      "Preview Card"
-             :on-click #(srs/preview (:db/id block))}
-            (t :context-menu/preview-flashcard))
            (state/enable-flashcards?)
            (shui/dropdown-menu-item
             {:key      "Make a Card"
-             :on-click #(if (config/db-based-graph? (state/get-current-repo))
-                          (fsrs/batch-make-cards! [block-id])
-                          (srs/batch-make-cards! [block-id]))}
+             :on-click #(fsrs/batch-make-cards! [block-id])}
             (t :context-menu/make-a-flashcard))
            :else
            nil)

+ 50 - 10
src/main/frontend/extensions/fsrs.cljs

@@ -3,14 +3,13 @@
   (:require [clojure.string :as string]
             [frontend.common.missionary :as c.m]
             [frontend.components.block :as component-block]
-            [frontend.config :as config]
+            [frontend.components.macro :as component-macro]
             [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db-mixins :as db-mixins]
             [frontend.db.async :as db-async]
             [frontend.db.model :as db-model]
             [frontend.db.query-dsl :as query-dsl]
-            [frontend.extensions.srs :as srs]
             [frontend.handler.block :as block-handler]
             [frontend.handler.property :as property-handler]
             [frontend.modules.shortcut.core :as shortcut]
@@ -305,14 +304,12 @@
   "Return a task that update `:srs/cards-due-count` periodically."
   (m/sp
     (let [repo (state/get-current-repo)]
-      (if (config/db-based-graph? repo)
-        (m/?
-         (m/reduce
-          (fn [_ _]
-            (p/let [due-cards (<get-due-card-block-ids repo nil)]
-              (state/set-state! :srs/cards-due-count (count due-cards))))
-          (c.m/clock (* 3600 1000))))
-        (srs/update-cards-due-count!)))))
+      (m/?
+       (m/reduce
+        (fn [_ _]
+          (p/let [due-cards (<get-due-card-block-ids repo nil)]
+            (state/set-state! :srs/cards-due-count (count due-cards))))
+        (c.m/clock (* 3600 1000)))))))
 
 (defn update-due-cards-count
   []
@@ -344,6 +341,49 @@
         :block/tags
         (:db/id (db/entity :logseq.class/Card)))))))
 
+;;; register cloze macro
+
+(def ^:private cloze-cue-separator "\\\\")
+
+(defn- cloze-parse
+  "Parse the cloze content, and return [answer cue]."
+  [content]
+  (let [parts (string/split content cloze-cue-separator -1)]
+    (if (<= (count parts) 1)
+      [content nil]
+      (let [cue (string/trim (last parts))]
+        ;; If there are more than one separator, only the last component is considered the cue.
+        [(string/trimr (string/join cloze-cue-separator (drop-last parts))) cue]))))
+
+(rum/defcs cloze-macro-show < rum/reactive
+  {:init (fn [state]
+           (let [config (first (:rum/args state))
+                 shown? (atom (:show-cloze? config))]
+             (assoc state :shown? shown?)))}
+  [state config options]
+  (let [shown?* (:shown? state)
+        shown? (rum/react shown?*)
+        toggle! #(swap! shown?* not)
+        [answer cue] (cloze-parse (string/join ", " (:arguments options)))]
+    (if (or shown? (:show-cloze? config))
+      [:a.cloze-revealed {:on-click toggle!}
+       (util/format "[%s]" answer)]
+      [:a.cloze {:on-click toggle!}
+       (if (string/blank? cue)
+         "[...]"
+         (str "(" cue ")"))])))
+
+(def cloze-macro-name
+  "cloze syntax: {{cloze: ...}}"
+  "cloze")
+
+;; TODO: support {{cards ...}}
+;; (def query-macro-name
+;;   "{{cards ...}}"
+;;   "cards")
+
+(component-macro/register cloze-macro-name cloze-macro-show)
+
 (comment
   (defn- cards-in-time-range
     [cards start-instant end-instant]

+ 0 - 798
src/main/frontend/extensions/srs.cljs

@@ -1,798 +0,0 @@
-(ns frontend.extensions.srs
-  "SRS fns for file based graphs. Will be deprecated in db-based version.
-  See also `frontend.extensions.fsrs`"
-  (:require [cljs-time.coerce :as tc]
-            [cljs-time.core :as t]
-            [cljs-time.local :as tl]
-            [clojure.string :as string]
-            [frontend.commands :as commands]
-            [frontend.components.block :as component-block]
-            [frontend.components.editor :as editor]
-            [frontend.components.macro :as component-macro]
-            [frontend.components.select :as component-select]
-            [frontend.components.svg :as svg]
-            [frontend.config :as config]
-            [frontend.context.i18n :refer [t]]
-            [frontend.date :as date]
-            [frontend.db :as db]
-            [frontend.db-mixins :as db-mixins]
-            [frontend.db.query-dsl :as query-dsl]
-            [frontend.db.query-react :as query-react]
-            [frontend.format.mldoc :as mldoc]
-            [frontend.handler.editor :as editor-handler]
-            [frontend.handler.property :as property-handler]
-            [frontend.handler.property.file :as property-file]
-            [frontend.modules.shortcut.core :as shortcut]
-            [frontend.state :as state]
-            [frontend.template :as template]
-            [frontend.ui :as ui]
-            [frontend.util :as util]
-            [frontend.util.file-based.drawer :as drawer]
-            [frontend.util.persist-var :as persist-var]
-            [logseq.graph-parser.property :as gp-property]
-            [logseq.shui.ui :as shui]
-            [medley.core :as medley]
-            [rum.core :as rum]))
-
-;;; ================================================================
-;;; Commentary
-;;; - One block with tag "#card" or "[[card]]" is treated as a card.
-;;; - {{cloze content}} show as "[...]" when reviewing cards
-
-;;; ================================================================
-;;; const & vars
-
-;; TODO: simplify state
-
-(defonce global-cards-mode? (atom false))
-
-(def card-hash-tag "card")
-
-(def card-last-interval-property        :card-last-interval)
-(def card-repeats-property              :card-repeats)
-(def card-last-reviewed-property        :card-last-reviewed)
-(def card-next-schedule-property        :card-next-schedule)
-(def card-last-easiness-factor-property :card-ease-factor)
-(def card-last-score-property           :card-last-score)
-
-(def default-card-properties-map {card-last-interval-property -1
-                                  card-repeats-property 0
-                                  card-last-easiness-factor-property 2.5})
-
-(def cloze-macro-name
-  "cloze syntax: {{cloze: ...}}"
-  "cloze")
-
-(def query-macro-name
-  "{{cards ...}}"
-  "cards")
-
-(def learning-fraction-default
-  "any number between 0 and 1 (the greater it is the faster the changes of the OF matrix)"
-  0.5)
-
-(defn- get-learning-fraction []
-  (if-let [learning-fraction (:srs/learning-fraction (state/get-config))]
-    (if (and (number? learning-fraction)
-             (< learning-fraction 1)
-             (> learning-fraction 0))
-      learning-fraction
-      learning-fraction-default)
-    learning-fraction-default))
-
-(def srs-of-matrix (persist-var/persist-var nil "srs-of-matrix"))
-
-(def initial-interval-default 4)
-
-(defn- get-initial-interval []
-  (if-let [initial-interval (:srs/initial-interval (state/get-config))]
-    (if (and (number? initial-interval)
-             (> initial-interval 0))
-      initial-interval
-      initial-interval-default)
-    initial-interval-default))
-
-;;; ================================================================
-;;; utils
-
-;; FIXME: All uses of properties in this namespace for db
-(defn- get-block-card-properties
-  [block]
-  (when-let [properties (:block/properties block)]
-    (merge
-     default-card-properties-map
-     (select-keys properties  [card-last-interval-property
-                               card-repeats-property
-                               card-last-reviewed-property
-                               card-next-schedule-property
-                               card-last-easiness-factor-property
-                               card-last-score-property]))))
-
-(defn- save-block-card-properties!
-  [block props]
-  (editor-handler/save-block-if-changed!
-   block
-   (property-file/insert-properties-when-file-based
-    (state/get-current-repo) (:block/format block) (:block/title block) props)
-   {:force? true}))
-
-(defn- reset-block-card-properties!
-  [block]
-  (save-block-card-properties! block {card-last-interval-property -1
-                                      card-repeats-property 0
-                                      card-last-easiness-factor-property 2.5
-                                      card-last-reviewed-property "nil"
-                                      card-next-schedule-property "nil"
-                                      card-last-score-property "nil"}))
-
-;;; used by other ns
-
-(defn card-block?
-  [block]
-  (let [card-entity (db/get-page card-hash-tag)
-        refs (into #{} (:block/refs block))]
-    (contains? refs card-entity)))
-
-(declare get-root-block)
-
-;;; ================================================================
-;;; sr algorithm (sm-5)
-;;; https://www.supermemo.com/zh/archives1990-2015/english/ol/sm5
-
-(defn- fix-2f
-  [n]
-  (/ (Math/round (* 100 n)) 100))
-
-(defn- get-of [of-matrix n ef]
-  (or (get-in of-matrix [n ef])
-      (if (<= n 1)
-        (get-initial-interval)
-        ef)))
-
-(defn- set-of [of-matrix n ef of]
-  (->>
-   (fix-2f of)
-   (assoc-in of-matrix [n ef])))
-
-(defn- interval
-  [n ef of-matrix]
-  (if (<= n 1)
-    (get-of of-matrix 1 ef)
-    (* (get-of of-matrix n ef)
-       (interval (- n 1) ef of-matrix))))
-
-(defn- get-next-ef
-  [ef quality]
-  (let [ef* (+ ef (- 0.1 (* (- 5 quality) (+ 0.08 (* 0.02 (- 5 quality))))))]
-    (if (< ef* 1.3) 1.3 ef*)))
-
-(defn- get-next-of-matrix
-  [of-matrix n quality fraction ef]
-  (let [of (get-of of-matrix n ef)
-        of* (* of (+ 0.72 (* quality 0.07)))
-        of** (+ (* (- 1 fraction) of) (* of* fraction))]
-    (set-of of-matrix n ef of**)))
-
-(defn calc-next-interval
-  "return [next-interval repeats next-ef of-matrix]"
-  [_last-interval repeats ef quality of-matrix]
-  (assert (and (<= quality 5) (>= quality 0)))
-  (let [ef (or ef 2.5)
-        next-ef (get-next-ef ef quality)
-        next-of-matrix (get-next-of-matrix of-matrix repeats quality (get-learning-fraction) ef)
-        next-interval (interval repeats next-ef next-of-matrix)]
-
-    (if (< quality 3)
-      ;; If the quality response was lower than 3
-      ;; then start repetitions for the item from
-      ;; the beginning without changing the E-Factor
-      [-1 1 ef next-of-matrix]
-      [(fix-2f next-interval) (+ 1 repeats) (fix-2f next-ef) next-of-matrix])))
-
-;;; ================================================================
-;;; card protocol
-
-(defprotocol ICard
-  (get-root-block [this]))
-
-(defprotocol ICardShow
-  ;; return {:value blocks :next-phase next-phase}
-  (show-cycle [this phase])
-
-  (show-cycle-config [this phase]))
-
-(defn- has-cloze?
-  [blocks]
-  (->> (map :block/title blocks)
-       (some #(string/includes? % "{{cloze "))))
-
-(defn- clear-collapsed-property
-  "Clear block's collapsed property if exists"
-  [blocks]
-  (let [result (map (fn [block]
-                      (-> block
-                          (dissoc :block/collapsed?)
-                          (medley/dissoc-in [:block/properties :collapsed]))) blocks)]
-    result))
-
-;;; ================================================================
-;;; card impl
-
-(deftype Sided-Cloze-Card [block]
-  ICard
-  (get-root-block [_this] (db/pull [:block/uuid block]))
-  ICardShow
-  (show-cycle [_this phase]
-    (let [block-id (:db/id block)
-          blocks (-> [(db/entity block-id)]
-                     clear-collapsed-property)
-          cloze? (has-cloze? blocks)]
-      (case phase
-        1
-        (let [blocks-count (count blocks)]
-          {:value [(first blocks)] :next-phase (if (or (> blocks-count 1) cloze?) 2 3)})
-        2
-        {:value blocks :next-phase (if cloze? 3 1)}
-        3
-        {:value blocks :next-phase 1})))
-
-  (show-cycle-config [_this phase]
-    (case phase
-      1
-      {:hide-children? true}
-      2
-      {}
-      3
-      {:show-cloze? true})))
-
-(defn- ->card [block]
-  (let [block' (db/pull (:db/id block))]
-    (->Sided-Cloze-Card block')))
-
-;;; ================================================================
-;;;
-
-(defn- query
-  "Use same syntax as frontend.db.query-dsl.
-  Add an extra condition: block's :block/refs contains `#card or [[card]]'"
-  ([repo query-string]
-   (query repo query-string {}))
-  ([repo query-string {:keys [use-cache?]
-                       :or {use-cache? true}}]
-   (when (string? query-string)
-     (let [result (if (string/blank? query-string)
-                    (:block/_refs (db/get-page card-hash-tag))
-                    (let [query-string (template/resolve-dynamic-template! query-string)
-                          {query* :query :keys [sort-by rules]} (query-dsl/parse query-string {:db-graph? (config/db-based-graph? repo)})]
-                      (when-let [query' (query-dsl/query-wrapper query*
-                                                                 {:blocks? true
-                                                                  :block-attrs [:db/id :block/properties]})]
-                        (let [result (last (query-react/react-query repo
-                                                                    {:query (with-meta query' {:cards-query? true})
-                                                                     :rules (or rules [])}
-                                                                    (merge
-                                                                     {:use-cache? use-cache?}
-                                                                     (when sort-by
-                                                                       {:transform-fn sort-by}))))]
-                          (when result
-                            (flatten (util/react result)))))))]
-       (vec result)))))
-
-(defn- query-scheduled
-  "Return blocks scheduled to 'time' or before"
-  [blocks time]
-  (let [filtered-result (filterv (fn [b]
-                                   (let [props (:block/properties b)
-                                         next-sched (get props card-next-schedule-property)
-                                         next-sched* (tc/from-string next-sched)
-                                         repeats (get props card-repeats-property)]
-                                     (or (nil? repeats)
-                                         (< repeats 1)
-                                         (nil? next-sched)
-                                         (nil? next-sched*)
-                                         (t/before? next-sched* time))))
-                                 blocks),
-        sort-by-next-schedule   (sort-by (fn [b]
-                                           (get (get b :block/properties) card-next-schedule-property)) filtered-result)]
-    {:total (count blocks)
-     :result sort-by-next-schedule}))
-
-;;; ================================================================
-;;; operations
-
-(defn- get-next-interval
-  [card score]
-  {:pre [(and (<= score 5) (>= score 0))
-         (satisfies? ICard card)]}
-  (let [block (.-block card)
-        props (get-block-card-properties block)
-        last-interval (or
-                       (when-let [v (get props card-last-interval-property)]
-                         (util/safe-parse-float v))
-                       0)
-        repeats (or (when-let [v (get props card-repeats-property)]
-                      (util/safe-parse-int v))
-                    0)
-        last-ef (or (when-let [v (get props card-last-easiness-factor-property)]
-                      (util/safe-parse-float v)) 2.5)
-        [next-interval next-repeats next-ef of-matrix*]
-        (calc-next-interval last-interval repeats last-ef score @srs-of-matrix)
-        next-interval* (if (< next-interval 0) 0 next-interval)
-        next-schedule (tc/to-string (t/plus (tl/local-now) (t/hours (* 24 next-interval*))))
-        now (tc/to-string (tl/local-now))]
-    {:next-of-matrix of-matrix*
-     card-last-interval-property next-interval
-     card-repeats-property next-repeats
-     card-last-easiness-factor-property next-ef
-     card-next-schedule-property next-schedule
-     card-last-reviewed-property now
-     card-last-score-property score}))
-
-(defn- operation-score!
-  [card score]
-  {:pre [(and (<= score 5) (>= score 0))
-         (satisfies? ICard card)]}
-  (let [block (.-block card)
-        result (get-next-interval card score)
-        next-of-matrix (:next-of-matrix result)]
-    (reset! srs-of-matrix next-of-matrix)
-    (save-block-card-properties! (db/pull (:db/id block))
-                                 (select-keys result
-                                              [card-last-interval-property
-                                               card-repeats-property
-                                               card-last-easiness-factor-property
-                                               card-next-schedule-property
-                                               card-last-reviewed-property
-                                               card-last-score-property]))))
-
-(defn- operation-reset!
-  [card]
-  {:pre [(satisfies? ICard card)]}
-  (let [block (.-block card)]
-    (reset-block-card-properties! (db/pull (:db/id block)))))
-
-(defn- operation-card-info-summary!
-  [review-records review-cards card-query-block]
-  (when card-query-block
-    (let [review-count (count (flatten (vals review-records)))
-          review-cards-count (count review-cards)
-          score-remembered-count (+ (count (get review-records 5))
-                                    (count (get review-records 3)))
-          score-forgotten-count (count (get review-records 1))]
-      (editor-handler/insert-block-tree-after-target
-       (:db/id card-query-block) false
-       [{:content (util/format "Summary: %d items, %d review counts [[%s]]"
-                               review-cards-count review-count (date/today))
-         :children [{:content
-                     (util/format "Remembered:   %d (%d%%)" score-remembered-count (* 100 (/ score-remembered-count review-count)))}
-                    {:content
-                     (util/format "Forgotten :   %d (%d%%)" score-forgotten-count (* 100 (/ score-forgotten-count review-count)))}]}]
-       (:block/format card-query-block)
-       false))))
-
-;;; ================================================================
-;;; UI
-
-(defn- dec-cards-due-count!
-  []
-  (state/update-state! :srs/cards-due-count
-                       (fn [n]
-                         (if (> n 0)
-                           (dec n)
-                           n))))
-
-(defn- score-and-next-card [score card *card-index finished? *phase *review-records cb]
-  (operation-score! card score)
-  (swap! *review-records #(update % score (fn [ov] (conj ov card))))
-  (if finished?
-    (when cb (cb @*review-records))
-    (reset! *phase 1))
-  (swap! *card-index inc)
-  (when @global-cards-mode?
-    (dec-cards-due-count!)))
-
-(defn- skip-card [card *card-index finished? *phase *review-records cb]
-  (swap! *review-records #(update % "skip" (fn [ov] (conj ov card))))
-  (swap! *card-index inc)
-  (if finished?
-    (when cb (cb @*review-records))
-    (reset! *phase 1)))
-
-(def review-finished
-  [:p.p-2 (t :flashcards/modal-finished)])
-
-(defn- btn-with-shortcut [{:keys [shortcut id btn-text background on-click class]}]
-  (ui/button
-   [:span btn-text (when-not (util/sm-breakpoint?)
-                     [" " (ui/render-keyboard-shortcut shortcut {:theme :text})])]
-   :id id
-   :class (str id " " class)
-   :background background
-   :on-pointer-down (fn [e] (util/stop-propagation e))
-   :on-click (fn [_e]
-               (js/setTimeout #(on-click) 10))))
-
-(rum/defcs view < rum/reactive db-mixins/query
-  (rum/local 1 ::phase)
-  (rum/local {} ::review-records)
-  [state blocks {preview? :preview?
-                 cards? :cards?
-                 modal? :modal?
-                 cb :callback}
-   card-index]
-  (let [review-records (::review-records state)
-        current-block (util/nth-safe blocks @card-index)
-        card (when current-block (->card current-block))
-        finished? (= (inc @card-index) (count blocks))]
-    (if (nil? card)
-      review-finished
-      (let [phase (::phase state)
-            {current-blocks :value next-phase :next-phase} (show-cycle card @phase)
-            root-block (.-block card)
-            root-block-id (:block/uuid root-block)]
-        [:div.ls-card.content
-         {:class (when (or preview? modal?)
-                   (str (util/hiccup->class ".flex.flex-col.resize.overflow-y-auto")
-                        (when modal? " modal-cards")))}
-         (let [repo (state/get-current-repo)]
-           [:div {:style {:margin-top 20}}
-            (component-block/breadcrumb {} repo root-block-id {})])
-         (component-block/blocks-container
-          (merge (show-cycle-config card @phase)
-                 {:id (str root-block-id)
-                  :editor-box editor/box
-                  :review-cards? true})
-          current-blocks)
-         (if (or preview? modal?)
-           [:div.flex.my-4.justify-between
-            (when-not (and (not preview?) (= next-phase 1))
-              (btn-with-shortcut {:btn-text (case next-phase
-                                              1 (t :flashcards/modal-btn-hide-answers)
-                                              2 (t :flashcards/modal-btn-show-answers)
-                                              3 (t :flashcards/modal-btn-show-clozes))
-                                  :shortcut  "s"
-                                  :id "card-answers"
-                                  :class "mr-2"
-                                  :on-click #(reset! phase next-phase)}))
-            (when (and (not= @card-index (count blocks))
-                       cards?
-                       preview?)
-              (btn-with-shortcut {:btn-text (t :flashcards/modal-btn-next-card)
-                                  :shortcut "n"
-                                  :id       "card-next"
-                                  :class    "mr-2"
-                                  :on-click (fn [e]
-                                              (util/stop e)
-                                              (skip-card card card-index finished? phase review-records cb))}))
-
-            (when (and (not preview?) (= 1 next-phase))
-              [:<>
-               (btn-with-shortcut {:btn-text   (t :flashcards/modal-btn-forgotten)
-                                   :shortcut   "f"
-                                   :id         "card-forgotten"
-                                   :background "red"
-                                   :on-click   (fn []
-                                                 (score-and-next-card 1 card card-index finished? phase review-records cb)
-                                                 (let [tomorrow (tc/to-string (t/plus (t/today) (t/days 1)))]
-                                                   (property-handler/set-block-property! (state/get-current-repo) root-block-id card-next-schedule-property tomorrow)))})
-
-               (btn-with-shortcut {:btn-text (if (util/mobile?) "Hard" (t :flashcards/modal-btn-recall))
-                                   :shortcut "t"
-                                   :id       "card-recall"
-                                   :on-click #(score-and-next-card 3 card card-index finished? phase review-records cb)})
-
-               (btn-with-shortcut {:btn-text   (t :flashcards/modal-btn-remembered)
-                                   :shortcut   "r"
-                                   :id         "card-remembered"
-                                   :background "green"
-                                   :on-click   #(score-and-next-card 5 card card-index finished? phase review-records cb)})])
-
-            (when preview?
-              (ui/tooltip
-               (ui/button [:span (t :flashcards/modal-btn-reset)]
-                          :id "card-reset"
-                          :class (util/hiccup->class "opacity-60.hover:opacity-100.card-reset")
-                          :on-click (fn [e]
-                                      (util/stop e)
-                                      (operation-reset! card)))
-
-               [:div.text-sm
-                (t :flashcards/modal-btn-reset-tip)]
-               {:trigger-props {:as-child false}}))]
-           [:div.my-3 (ui/button "Review cards" :small? true)])]))))
-
-(rum/defc view-modal <
-  (shortcut/mixin :shortcut.handler/cards false)
-  [blocks option card-index]
-  [:div#cards-modal
-   (if (seq blocks)
-     (rum/with-key
-       (view blocks option card-index)
-       (str "ls-card-" (:db/id (first blocks))))
-     review-finished)])
-
-(rum/defc preview-cp < rum/reactive db-mixins/query
-  [block-id]
-  (let [blocks [(db/entity block-id)]]
-    (view-modal blocks {:preview? true} (atom 0))))
-
-(defn preview
-  [block-id]
-  (shui/dialog-open! #(preview-cp block-id) {:id :srs}))
-
-;;; ================================================================
-;;; register some external vars & related UI
-
-;;; register cloze macro
-
-(def ^:private cloze-cue-separator "\\\\")
-
-(defn- cloze-parse
-  "Parse the cloze content, and return [answer cue]."
-  [content]
-  (let [parts (string/split content cloze-cue-separator -1)]
-    (if (<= (count parts) 1)
-      [content nil]
-      (let [cue (string/trim (last parts))]
-        ;; If there are more than one separator, only the last component is considered the cue.
-        [(string/trimr (string/join cloze-cue-separator (drop-last parts))) cue]))))
-
-(rum/defcs cloze-macro-show < rum/reactive
-  {:init (fn [state]
-           (let [config (first (:rum/args state))
-                 shown? (atom (:show-cloze? config))]
-             (assoc state :shown? shown?)))}
-  [state config options]
-  (let [shown?* (:shown? state)
-        shown? (rum/react shown?*)
-        toggle! #(swap! shown?* not)
-        [answer cue] (cloze-parse (string/join ", " (:arguments options)))]
-    (if (or shown? (:show-cloze? config))
-      [:a.cloze-revealed {:on-click toggle!}
-       (util/format "[%s]" answer)]
-      [:a.cloze {:on-click toggle!}
-       (if (string/blank? cue)
-         "[...]"
-         (str "(" cue ")"))])))
-
-(component-macro/register cloze-macro-name cloze-macro-show)
-
-(def cards-total (atom 0))
-
-(defn get-srs-cards-total
-  []
-  (try
-    (let [repo (state/get-current-repo)
-          query-string ""
-          blocks (query repo query-string {:use-cache?        false})]
-      (when (seq blocks)
-        (let [{:keys [result]} (query-scheduled blocks (tl/local-now))
-              count (count result)]
-          (reset! cards-total count)
-          count)))
-    (catch :default e
-      (js/console.error e) 0)))
-
-(declare cards)
-
-;; TODO: FIXME: macros have been deleted
-(rum/defc cards-select
-  [{:keys [on-chosen]}]
-  (let [items [(t :flashcards/modal-select-all)]]
-    (component-select/select {:items items
-                              :on-chosen on-chosen
-                              :close-modal? false
-                              :input-default-placeholder (t :flashcards/modal-select-switch)
-                              :extract-fn nil})))
-
-;;; register cards macro
-(rum/defcs ^:large-vars/cleanup-todo cards-inner < rum/reactive db-mixins/query
-  (rum/local 0 ::card-index)
-  (rum/local false ::random-mode?)
-  (rum/local false ::preview-mode?)
-  [state config options {:keys [query-atom query-string query-result due-result]}]
-  (let [*random-mode? (::random-mode? state)
-        *preview-mode? (::preview-mode? state)
-        *card-index (::card-index state)]
-    (if (seq query-result)
-      (let [{:keys [total result]} due-result
-            review-cards (if @*preview-mode? query-result result)
-            card-query-block (db/entity [:block/uuid (:block/uuid config)])
-            filtered-total (count result)
-            modal? (:modal? config)
-            callback-fn (fn [review-records]
-                          (when-not @*preview-mode?
-                            (operation-card-info-summary!
-                             review-records review-cards card-query-block)
-                            (persist-var/persist-save srs-of-matrix)))]
-        [:div.flex-1.cards-review {:style (when modal? {:height "100%"})}
-         [:div.flex.flex-row.items-center.justify-between.cards-title
-          [:div.flex.flex-row.items-center
-           (ui/icon "infinity" {:style {:font-size 20}})
-           (ui/dropdown
-            (fn [{:keys [toggle-fn]}]
-              [:div.ml-1.text-sm.font-medium.cursor
-               {:on-pointer-down (fn [e]
-                                   (util/stop e)
-                                   (toggle-fn))}
-               [:span.flex (if (string/blank? query-string) (t :flashcards/modal-select-all) query-string)
-                [:span {:style {:margin-top 2}}
-                 (svg/caret-down)]]])
-            (fn [{:keys [toggle-fn]}]
-              (cards-select {:on-chosen (fn [query']
-                                          (let [query'' (if (= query' (t :flashcards/modal-select-all)) "" query')]
-                                            (reset! query-atom query'')
-                                            (toggle-fn)))}))
-            {:modal-class (util/hiccup->class
-                           "origin-top-right.absolute.left-0.mt-2.ml-2.rounded-md.shadow-lg")})]
-
-          [:div.flex.flex-row.items-center
-
-           ;; FIXME: CSS issue
-           (if @*preview-mode?
-             (ui/tooltip
-              [:div.opacity-60.text-sm.mr-2
-               @*card-index
-               [:span "/"]
-               total]
-              [:div.text-sm (t :flashcards/modal-current-total)])
-             (ui/tooltip
-              [:div.opacity-60.text-sm.mr-2
-               (max 0 (- filtered-total @*card-index))
-               [:span "/"]
-               total]
-              [:div.text-sm (t :flashcards/modal-overdue-total)]))
-
-           (ui/tooltip
-            (ui/button
-             (merge
-              {:icon "letter-a"
-               :intent "link"
-               :on-click (fn [e]
-                           (util/stop e)
-                           (swap! *preview-mode? not)
-                           (reset! *card-index 0))
-               :button-props {:id "preview-all-cards"}
-               :small? true}
-              (when @*preview-mode?
-                {:icon-props {:style {:color "var(--ls-button-background)"}}})))
-            [:div.text-sm (t :flashcards/modal-toggle-preview-mode)]
-            {:trigger-props {:as-child false}})
-
-           (ui/tooltip
-            (ui/button
-             (merge
-              {:icon "arrows-shuffle"
-               :intent "link"
-               :on-click (fn [e]
-                           (util/stop e)
-                           (swap! *random-mode? not))
-               :small? true}
-              (when @*random-mode?
-                {:icon-props {:style {:color "var(--ls-button-background)"}}})))
-            [:div.text-sm (t :flashcards/modal-toggle-random-mode)]
-            {:trigger-props {:as-child false}})]]
-         [:div.px-1
-          (when (and (not modal?) (not @*preview-mode?))
-            {:on-click (fn []
-                         (shui/dialog-open!
-                          #(cards (assoc config :modal? true) {:query-string query-string})
-                          {:id :srs}))})
-          (let [view-fn (if modal? view-modal view)
-                blocks (if @*preview-mode? query-result review-cards)
-                blocks (if @*random-mode? (shuffle blocks) blocks)]
-            (view-fn blocks
-                     (merge config
-                            (merge options
-                                   {:random-mode? @*random-mode?
-                                    :preview? @*preview-mode?
-                                    :callback callback-fn}))
-                     *card-index))]])
-      (if (:global? config)
-        [:div.ls-card.content
-         [:h1.title (t :flashcards/modal-welcome-title)]
-
-         [:div
-          [:p (t :flashcards/modal-welcome-desc-1 "#card")]
-          [:img.my-4 {:src "https://docs.logseq.com/assets/2021-07-22_22.28.02_1626964258528_0.gif"}]
-          [:p (t :flashcards/modal-welcome-desc-2)
-           [:a {:href "https://docs.logseq.com/#/page/Flashcards" :target "_blank"}
-            (t :flashcards/modal-welcome-desc-3)]
-           (t :flashcards/modal-welcome-desc-4)]]]
-        [:div.opacity-60.custom-query-title.ls-card.content
-         [:div.w-full.flex-1
-          [:code.p-1 (str "Cards: " query-string)]]
-         [:div.mt-2.ml-2.font-medium "No matched cards"]]))))
-
-(rum/defcs cards <
-  (rum/local nil ::query)
-  {:will-mount (fn [state]
-                 (state/set-state! :srs/mode? true)
-                 state)
-   :will-unmount (fn [state]
-                   (state/set-state! :srs/mode? false)
-                   state)}
-  [state config options]
-  (let [*query (::query state)
-        repo (state/get-current-repo)
-        query-string (or @*query
-                         (:query-string options)
-                         (string/join ", " (:arguments options)))
-        query-result (query repo query-string)
-        due-result (query-scheduled query-result (tl/local-now))]
-    (cards-inner config (assoc options :cards? true)
-                 {:query-atom *query
-                  :query-string query-string
-                  :query-result query-result
-                  :due-result due-result})))
-
-(rum/defc global-cards <
-  {:will-mount (fn [state]
-                 (reset! global-cards-mode? true)
-                 state)
-   :will-unmount (fn [state]
-                   (reset! global-cards-mode? false)
-                   state)}
-  []
-  (cards {:modal? true
-          :global? true} {}))
-
-(component-macro/register query-macro-name cards)
-
-;;; register builtin properties
-(gp-property/register-built-in-properties #{card-last-interval-property
-                                            card-repeats-property
-                                            card-last-reviewed-property
-                                            card-next-schedule-property
-                                            card-last-easiness-factor-property
-                                            card-last-score-property})
-
-;;; register slash commands
-(commands/register-slash-command ["Cards"
-                                  [[:editor/input "{{cards }}" {:backward-pos 2}]]
-                                  "Create a cards query"
-                                  {:icon :icon/cards
-                                   :db-graph? false}])
-
-(commands/register-slash-command ["Cloze"
-                                  [[:editor/input "{{cloze }}" {:backward-pos 2}]]
-                                  "Create a cloze"
-                                  {:icon :icon/eye-question}])
-
-;; handlers
-(defn add-card-tag-to-block
-  "given a block struct, adds the #card to title and returns
-   a seq of [original-block new-content-string]"
-  [block]
-  (when-let [content (:block/title block)]
-    (let [format (get block :block/format :markdown)
-          content (-> (property-file/remove-built-in-properties-when-file-based
-                       (state/get-current-repo) format content)
-                      (drawer/remove-logbook))
-          [title body] (mldoc/get-title&body content format)]
-      [block (str title " #" card-hash-tag "\n" body)])))
-
-(defn batch-make-cards!
-  ([] (batch-make-cards! (state/get-selection-block-ids)))
-  ([block-ids]
-   (let [valid-blocks (->> block-ids
-                           (map #(db/entity [:block/uuid %]))
-                           (remove card-block?)
-                           (map #(db/pull [:block/uuid (:block/uuid %)])))
-         blocks (map add-card-tag-to-block valid-blocks)]
-     (when-not (empty? blocks)
-       (editor-handler/save-blocks! blocks)))))
-
-(defonce *due-cards-interval (atom nil))
-
-(defn update-cards-due-count!
-  []
-  (when (state/enable-flashcards?)
-    (let [f (fn []
-              (let [total (get-srs-cards-total)]
-                (state/set-state! :srs/cards-due-count total)))]
-      (js/setTimeout f 1000)
-      (when (nil? @*due-cards-interval)
-        ;; refresh every hour
-        (let [interval' (js/setInterval f (* 3600 1000))]
-          (reset! *due-cards-interval interval'))))))

+ 0 - 24
src/main/frontend/extensions/srs.css

@@ -1,24 +0,0 @@
-/******************************************************************************/
-/** Review widget *************************************************************/
-/******************************************************************************/
-.cards-review {
-  padding: 12px;
-}
-
-.cards-title {
-  border-radius: 4px;
-  background: var(--color-level-1);
-  padding: 4px 6px;
-}
-
-.cp__right-sidebar .cards-title,
-
-/******************************************************************************/
-/** Card blocks ***************************************************************/
-/******************************************************************************/
-div[data-refs-self*='"card"'] {
-  margin-bottom: 8px;
-  padding-top: 12px;
-  padding-bottom: 12px;
-  border-radius: 4px;
-}

+ 4 - 6
src/main/frontend/handler/events/ui.cljs

@@ -17,7 +17,6 @@
             [frontend.config :as config]
             [frontend.db :as db]
             [frontend.extensions.fsrs :as fsrs]
-            [frontend.extensions.srs :as srs]
             [frontend.handler.db-based.rtc :as rtc-handler]
             [frontend.handler.editor :as editor-handler]
             [frontend.handler.events :as events]
@@ -91,11 +90,10 @@
    (component-page/batch-delete-dialog selected-rows ok-handler)))
 
 (defmethod events/handle :modal/show-cards [[_ cards-id]]
-  (let [db-based? (config/db-based-graph? (state/get-current-repo))]
-    (shui/dialog-open!
-     (if db-based? (fn [] (fsrs/cards-view cards-id)) srs/global-cards)
-     {:id :srs
-      :label "flashcards__cp"})))
+  (shui/dialog-open!
+   (fn [] (fsrs/cards-view cards-id))
+   {:id :srs
+    :label "flashcards__cp"}))
 
 (defmethod events/handle :modal/show-themes-modal [[_ classic?]]
   (if classic?