diff --git a/src/main/frontend/components/container.cljs b/src/main/frontend/components/container.cljs index a42e4c853..6c7443b15 100644 --- a/src/main/frontend/components/container.cljs +++ b/src/main/frontend/components/container.cljs @@ -15,6 +15,9 @@ [frontend.components.dnd :as dnd-component] [frontend.components.icon :as icon] [frontend.components.handbooks :as handbooks] + [dommy.core :as d] + [frontend.components.page-menu :as page-menu] + [frontend.components.content :as cp-content] [frontend.config :as config] [frontend.context.i18n :refer [t]] [frontend.db :as db] @@ -32,6 +35,9 @@ [frontend.handler.user :as user-handler] [frontend.handler.whiteboard :as whiteboard-handler] [frontend.handler.recent :as recent-handler] + [frontend.handler.property :as property-handler] + [frontend.handler.property.util :as pu] + [frontend.components.export :as export] [frontend.mixins :as mixins] [frontend.mobile.action-bar :as action-bar] [frontend.mobile.footer :as footer] @@ -42,6 +48,8 @@ [frontend.state :as state] [frontend.ui :as ui] [logseq.shui.ui :as shui] + [logseq.common.util.block-ref :as block-ref] + [frontend.util.url :as url-util] [logseq.shui.toaster.core :as shui-toaster] [logseq.shui.dialog.core :as shui-dialog] [logseq.shui.popup.core :as shui-popup] @@ -127,10 +135,12 @@ (if whiteboard-page? (route-handler/redirect-to-whiteboard! name {:click-from-recent? recent?}) (route-handler/redirect-to-page! name {:click-from-recent? recent?}))))) - :on-context-menu #(shui/popup-show! (.-target %) (x-menu-content) - {:as-dropdown? true - :content-props {:on-click (fn [] (shui/popup-hide!)) - :class "w-60"}})} + :on-context-menu (fn [^js e] + (shui/popup-show! e (x-menu-content) + {:as-dropdown? true + :content-props {:on-click (fn [] (shui/popup-hide!)) + :class "w-60"}}) + (util/stop e))} [:span.page-icon.ml-3.justify-center (if whiteboard-page? (ui/icon "whiteboard" {:extension? true}) icon)] [:span.page-title {:class (when untitled? "opacity-50")} (if untitled? (t :untitled) @@ -728,6 +738,16 @@ :left (str (first position) "px") :top (str (second position) "px")}} links]])) +(rum/defc page-title-custom-context-menu-content + [page] + (when-not (string/blank? page) + (let [page-menu-options (page-menu/page-menu page)] + [:.menu-links-wrapper + (for [{:keys [title options]} page-menu-options] + (rum/with-key + (ui/menu-link options title) + title))]))) + (rum/defc custom-context-menu < rum/reactive [] (let [show? (state/sub :custom-context-menu/show?) @@ -822,6 +842,74 @@ (when handbooks-open? (handbooks/handbooks-popup))])) +(rum/defc app-context-menu-observer + < rum/static + (mixins/event-mixin + (fn [state] + ;; fixme: this mixin will register global event listeners on window + ;; which might cause unexpected issues + (mixins/listen state js/window "contextmenu" + (fn [e] + (let [target (gobj/get e "target") + block-el (.closest target ".bullet-container[blockid]") + block-id (some-> block-el (.getAttribute "blockid")) + {:keys [block block-ref]} (state/sub :block-ref/context) + {:keys [page]} (state/sub :page-title/context)] + + (let [handled (cond + page + (do + (shui/popup-show! + e + (fn [{:keys [id]}] + [:div + {:on-click #(shui/popup-hide! id)} + (cp-content/page-title-custom-context-menu-content page)]) + {:content-props {:class "ls-context-menu-content"}}) + (state/set-state! :page-title/context nil)) + + block-ref + (do + (shui/popup-show! + e + (fn [{:keys [id]}] + [:div + {:on-click #(shui/popup-hide! id)} + (cp-content/block-ref-custom-context-menu-content block block-ref)]) + {:content-props {:class "ls-context-menu-content"}}) + (state/set-state! :block-ref/context nil)) + + ;; block selection + (and (state/selection?) (not (d/has-class? target "bullet"))) + (shui/popup-show! + e + (fn [{:keys [id]}] + [:div + {:on-click #(shui/popup-hide! id)} + (cp-content/custom-context-menu-content)]) + {:content-props {:class "ls-context-menu-content"}}) + + ;; block bullet + (and block-id (parse-uuid block-id)) + (let [block (.closest target ".ls-block")] + (when block + (state/clear-selection!) + (state/conj-selection-block! block :down)) + (shui/popup-show! + e + (fn [{:keys [id]}] + [:div + {:on-click #(shui/popup-hide! id)} + (cp-content/block-context-menu-content target (uuid block-id))]) + {:content-props {:class "ls-context-menu-content"}})) + + :else + false)] + (when (not (false? handled)) + (util/stop e)))))))) + [] + nil) + (rum/defcs ^:large-vars/cleanup-todo sidebar < (mixins/modal :modal/show?) rum/reactive @@ -944,10 +1032,13 @@ (select/select-modal) (custom-context-menu) - (plugins/custom-js-installer {:t t - :current-repo current-repo - :nfs-granted? granted? - :db-restoring? db-restoring?}) + (plugins/custom-js-installer + {:t t + :current-repo current-repo + :nfs-granted? granted? + :db-restoring? db-restoring?}) + (app-context-menu-observer) + [:a#download.hidden] (when (and (not config/mobile?) (not config/publishing?)) diff --git a/src/main/frontend/components/content.cljs b/src/main/frontend/components/content.cljs index 2675a3cdc..05a349537 100644 --- a/src/main/frontend/components/content.cljs +++ b/src/main/frontend/components/content.cljs @@ -386,64 +386,6 @@ ;; Also, keyboard bindings should only be activated after ;; blocks were already selected. (rum/defc hiccup-content < rum/static - (mixins/event-mixin - (fn [state] - ;; fixme: this mixin will register global event listeners on window - ;; which might cause unexpected issues - (mixins/listen state js/window "contextmenu" - (fn [e] - (let [target (gobj/get e "target") - block-el (.closest target ".bullet-container[blockid]") - block-id (some-> block-el (.getAttribute "blockid")) - {:keys [block block-ref]} (state/sub :block-ref/context) - {:keys [page]} (state/sub :page-title/context)] - (cond - page - (do - (shui/popup-show! - e - (fn [{:keys [id]}] - [:div - {:on-click #(shui/popup-hide! id)} - (page-title-custom-context-menu-content page)]) - {:content-props {:class "ls-context-menu-content"}}) - (state/set-state! :page-title/context nil)) - - block-ref - (do - (shui/popup-show! - e - (fn [{:keys [id]}] - [:div - {:on-click #(shui/popup-hide! id)} - (block-ref-custom-context-menu-content block block-ref)]) - {:content-props {:class "ls-context-menu-content"}}) - (state/set-state! :block-ref/context nil)) - - (and (state/selection?) (not (d/has-class? target "bullet"))) - (shui/popup-show! - e - (fn [{:keys [id]}] - [:div - {:on-click #(shui/popup-hide! id)} - (custom-context-menu-content)]) - {:content-props {:class "ls-context-menu-content"}}) - - (and block-id (parse-uuid block-id)) - (let [block (.closest target ".ls-block")] - (when block - (state/clear-selection!) - (state/conj-selection-block! block :down)) - (shui/popup-show! - e - (fn [{:keys [id]}] - [:div - {:on-click #(shui/popup-hide! id)} - (block-context-menu-content target (uuid block-id))]) - {:content-props {:class "ls-context-menu-content"}})) - - :else - nil)))))) [id {:keys [hiccup]}] [:div {:id id} (if hiccup