mirror of https://github.com/logseq/logseq
refactor: use :block/order for whiteboard blocks
parent
3c1299c20a
commit
3bbcc8cd68
|
@ -96,7 +96,7 @@ export class HTMLShape extends TLBoxShape<HTMLShapeProps> {
|
|||
React.useEffect(() => {
|
||||
if (this.props.size[1] === 0) {
|
||||
this.onResetBounds({ zoom: app.viewport.camera.zoom })
|
||||
app.persist(true)
|
||||
app.persist({replace: true})
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
|
|||
size: [this.props.size[0], newHeight],
|
||||
})
|
||||
|
||||
if (loaded) app.persist(true)
|
||||
if (loaded) app.persist({replace: true})
|
||||
}
|
||||
}
|
||||
}, [innerHeight, this.props.isAutoResizing])
|
||||
|
@ -305,7 +305,7 @@ export class LogseqPortalShape extends TLBoxShape<LogseqPortalShapeProps> {
|
|||
if (!this.initialHeightCalculated) {
|
||||
setTimeout(() => {
|
||||
this.onResetBounds()
|
||||
app.persist(true)
|
||||
app.persist({replace: true})
|
||||
})
|
||||
}
|
||||
}, [this.initialHeightCalculated])
|
||||
|
|
|
@ -61,7 +61,7 @@ export class TweetShape extends TLBoxShape<TweetShapeProps> {
|
|||
this.update({
|
||||
size: [this.props.size[0], newHeight],
|
||||
})
|
||||
app.persist(true)
|
||||
app.persist({replace: true})
|
||||
}
|
||||
}, [innerHeight])
|
||||
|
||||
|
@ -69,7 +69,7 @@ export class TweetShape extends TLBoxShape<TweetShapeProps> {
|
|||
if (!this.initialHeightCalculated) {
|
||||
setTimeout(() => {
|
||||
this.onResetBounds()
|
||||
app.persist(true)
|
||||
app.persist({replace: true})
|
||||
})
|
||||
}
|
||||
}, [this.initialHeightCalculated])
|
||||
|
|
|
@ -450,7 +450,7 @@ export class TLApi<S extends TLShape = TLShape, K extends TLEventMap = TLEventMa
|
|||
this.app.currentPage.removeShapes(...selectedGroups)
|
||||
|
||||
// group all shapes
|
||||
const selectedShapes = shapes.filter(s => s.type !== 'group')
|
||||
let selectedShapes = shapes.filter(s => s.type !== 'group')
|
||||
if (selectedShapes.length > 1) {
|
||||
const ShapeGroup = this.app.getShapeClass('group')
|
||||
const group = new ShapeGroup({
|
||||
|
@ -461,11 +461,12 @@ export class TLApi<S extends TLShape = TLShape, K extends TLEventMap = TLEventMa
|
|||
})
|
||||
this.app.currentPage.addShapes(group)
|
||||
this.app.setSelectedShapes([group])
|
||||
selectedShapes.push(group)
|
||||
// the shapes in the group should also be moved to the bottom of the array (to be on top on the canvas)
|
||||
this.app.bringForward(selectedShapes)
|
||||
}
|
||||
this.app.history.resume()
|
||||
this.app.persist()
|
||||
this.app.persist(this.app.currentPage.persistInfo)
|
||||
}
|
||||
|
||||
unGroup = (shapes: S[] = this.app.allSelectedShapesArray) => {
|
||||
|
|
|
@ -28,9 +28,9 @@ export class TLHistory<S extends TLShape = TLShape, K extends TLEventMap = TLEve
|
|||
this.isPaused = false
|
||||
}
|
||||
|
||||
@action persist = (replace = false) => {
|
||||
@action persist = (info) => {
|
||||
if (this.isPaused || this.creating) return
|
||||
this.app.notify('persist', { replace })
|
||||
this.app.notify('persist', info)
|
||||
}
|
||||
|
||||
@action undo = () => {
|
||||
|
|
|
@ -33,6 +33,7 @@ export class TLPage<S extends TLShape = TLShape, E extends TLEventMap = TLEventM
|
|||
this.bindings = Object.assign({}, bindings) // make sure it is type of object
|
||||
this.app = app
|
||||
this.nonce = nonce || 0
|
||||
this.persistInfo = null
|
||||
this.addShapes(...shapes)
|
||||
makeObservable(this)
|
||||
|
||||
|
@ -137,50 +138,30 @@ export class TLPage<S extends TLShape = TLShape, E extends TLEventMap = TLEventM
|
|||
}
|
||||
|
||||
@action bringForward = (shapes: S[] | string[]): this => {
|
||||
const shapesToMove = this.parseShapesArg(shapes)
|
||||
shapesToMove
|
||||
.sort((a, b) => this.shapes.indexOf(b) - this.shapes.indexOf(a))
|
||||
.map(shape => this.shapes.indexOf(shape))
|
||||
.forEach(index => {
|
||||
if (index === this.shapes.length - 1) return
|
||||
const next = this.shapes[index + 1]
|
||||
if (shapesToMove.includes(next)) return
|
||||
const t = this.shapes[index]
|
||||
this.shapes[index] = this.shapes[index + 1]
|
||||
this.shapes[index + 1] = t
|
||||
})
|
||||
this.app.persist()
|
||||
this.bringToFront(shapes)
|
||||
return this
|
||||
}
|
||||
|
||||
@action sendBackward = (shapes: S[] | string[]): this => {
|
||||
const shapesToMove = this.parseShapesArg(shapes)
|
||||
shapesToMove
|
||||
.sort((a, b) => this.shapes.indexOf(a) - this.shapes.indexOf(b))
|
||||
.map(shape => this.shapes.indexOf(shape))
|
||||
.forEach(index => {
|
||||
if (index === 0) return
|
||||
const next = this.shapes[index - 1]
|
||||
if (shapesToMove.includes(next)) return
|
||||
const t = this.shapes[index]
|
||||
this.shapes[index] = this.shapes[index - 1]
|
||||
this.shapes[index - 1] = t
|
||||
})
|
||||
this.app.persist()
|
||||
this.sendToBack(shapes)
|
||||
return this
|
||||
}
|
||||
|
||||
@action bringToFront = (shapes: S[] | string[]): this => {
|
||||
const shapesToMove = this.parseShapesArg(shapes)
|
||||
this.shapes = this.shapes.filter(shape => !shapesToMove.includes(shape)).concat(shapesToMove)
|
||||
this.app.persist()
|
||||
let others = this.shapes.filter(shape => !shapesToMove.includes(shape))
|
||||
this.shapes = others.concat(shapesToMove)
|
||||
const info = {op: "bringToFront", shapes: shapesToMove, before: others[others.length - 1]}
|
||||
this.app.persist(info)
|
||||
this.persistInfo = info
|
||||
return this
|
||||
}
|
||||
|
||||
@action sendToBack = (shapes: S[] | string[]): this => {
|
||||
const shapesToMove = this.parseShapesArg(shapes)
|
||||
this.shapes = shapesToMove.concat(this.shapes.filter(shape => !shapesToMove.includes(shape)))
|
||||
this.app.persist()
|
||||
let others = this.shapes.filter(shape => !shapesToMove.includes(shape))
|
||||
this.shapes = shapesToMove.concat(others)
|
||||
this.app.persist({op: "sendToBack", shapes: shapesToMove, next: others[0]})
|
||||
return this
|
||||
}
|
||||
|
||||
|
|
|
@ -178,7 +178,7 @@
|
|||
(p/let [_ @*transact-result
|
||||
result (p/do!
|
||||
(state/set-state! [:whiteboard/last-persisted-at (state/get-current-repo)] (util/time-ms))
|
||||
(whiteboard-handler/<transact-tldr-delta! page-name app (.-replace info)))]
|
||||
(whiteboard-handler/<transact-tldr-delta! page-name app info))]
|
||||
(reset! *transact-result result))
|
||||
(p/catch (fn [^js error]
|
||||
(js/console.error error)
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
[clojure.set :as set]
|
||||
[clojure.string :as string]
|
||||
[cljs-bean.core :as bean]
|
||||
[logseq.db.sqlite.util :as sqlite-util]))
|
||||
[logseq.db.sqlite.util :as sqlite-util]
|
||||
[logseq.db.frontend.order :as db-order]
|
||||
[logseq.outliner.core :as outliner-core]))
|
||||
|
||||
(defn js->clj-keywordize
|
||||
[obj]
|
||||
|
@ -29,16 +31,12 @@
|
|||
(gp-whiteboard/shape->block repo shape page-id)))
|
||||
|
||||
(defn- build-shapes
|
||||
[page-block blocks]
|
||||
(let [page-metadata (pu/get-block-property-value page-block :logseq.property.tldraw/page)
|
||||
shapes-index (:shapes-index page-metadata)
|
||||
shape-id->index (zipmap shapes-index (range 0 (count shapes-index)))]
|
||||
[blocks]
|
||||
(let [blocks (db/sort-by-order blocks)]
|
||||
(->> blocks
|
||||
(map (fn [block]
|
||||
(assoc block :index (get shape-id->index (str (:block/uuid block)) 0))))
|
||||
(db/sort-by-order blocks)
|
||||
(filter pu/shape-block?)
|
||||
(map pu/block->shape)
|
||||
(sort-by :index)
|
||||
(map (fn [shape]
|
||||
(if-let [page-id (:pageId shape)]
|
||||
(let [page (db/get-page page-id)]
|
||||
|
@ -48,7 +46,7 @@
|
|||
|
||||
(defn- whiteboard-clj->tldr [page-block blocks]
|
||||
(let [id (str (:block/uuid page-block))
|
||||
shapes (build-shapes page-block blocks)
|
||||
shapes (build-shapes blocks)
|
||||
tldr-page (pu/page-block->tldr-page page-block)
|
||||
assets (:assets tldr-page)
|
||||
tldr-page (dissoc tldr-page :assets)]
|
||||
|
@ -61,14 +59,13 @@
|
|||
:shapes shapes})]})))
|
||||
|
||||
(defn db-build-page-block
|
||||
[page-entity page-name tldraw-page assets shapes-index]
|
||||
[page-entity page-name tldraw-page assets]
|
||||
(let [get-k #(gobj/get tldraw-page %)
|
||||
tldraw-page {:id (get-k "id")
|
||||
:name (get-k "name")
|
||||
:bindings (js->clj-keywordize (get-k "bindings"))
|
||||
:nonce (get-k "nonce")
|
||||
:assets (js->clj-keywordize assets)
|
||||
:shapes-index shapes-index}]
|
||||
:assets (js->clj-keywordize assets)}]
|
||||
{:db/id (:db/id page-entity)
|
||||
:block/original-name page-name
|
||||
:block/name (util/page-name-sanity-lc page-name)
|
||||
|
@ -81,7 +78,7 @@
|
|||
(util/time-ms))}))
|
||||
|
||||
(defn file-build-page-block
|
||||
[page-entity page-name tldraw-page assets shapes-index]
|
||||
[page-entity page-name tldraw-page assets]
|
||||
(let [get-k #(gobj/get tldraw-page %)]
|
||||
{:block/original-name page-name
|
||||
:block/name (util/page-name-sanity-lc page-name)
|
||||
|
@ -94,37 +91,36 @@
|
|||
:name (get-k "name")
|
||||
:bindings (js->clj-keywordize (get-k "bindings"))
|
||||
:nonce (get-k "nonce")
|
||||
:assets (js->clj-keywordize assets)
|
||||
:shapes-index shapes-index}}
|
||||
:assets (js->clj-keywordize assets)}}
|
||||
:block/updated-at (util/time-ms)
|
||||
:block/created-at (or (:block/created-at page-entity)
|
||||
(util/time-ms))}))
|
||||
|
||||
(defn build-page-block
|
||||
[page-entity page-name tldraw-page assets shapes-index]
|
||||
[page-entity page-name tldraw-page assets]
|
||||
(let [f (if (config/db-based-graph? (state/get-current-repo))
|
||||
db-build-page-block
|
||||
file-build-page-block)]
|
||||
(f page-entity page-name tldraw-page assets shapes-index)))
|
||||
(f page-entity page-name tldraw-page assets)))
|
||||
|
||||
(defn- compute-tx
|
||||
[^js app ^js tl-page new-id-nonces db-id-nonces page-uuid replace?]
|
||||
(let [page-entity (db/get-page page-uuid)
|
||||
assets (js->clj-keywordize (.getCleanUpAssets app))
|
||||
new-shapes (.-shapes tl-page)
|
||||
shapes-index (map #(gobj/get % "id") new-shapes)
|
||||
shape-id->index (zipmap shapes-index (range (.-length new-shapes)))
|
||||
upsert-shapes (->> (set/difference new-id-nonces db-id-nonces)
|
||||
(map (fn [{:keys [id]}]
|
||||
(-> (.-serialized ^js (.getShapeById tl-page id))
|
||||
js->clj-keywordize
|
||||
(assoc :index (get shape-id->index id)))))
|
||||
js->clj-keywordize)))
|
||||
(set))
|
||||
old-ids (set (map :id db-id-nonces))
|
||||
new-ids (set (map :id new-id-nonces))
|
||||
created-ids (->> (set/difference new-ids old-ids)
|
||||
(remove string/blank?)
|
||||
(set))
|
||||
new-orders (when (seq created-ids)
|
||||
(let [max-key (last (sort (map :block/order (:block/_page page-entity))))]
|
||||
(db-order/gen-n-keys (count created-ids) max-key nil)))
|
||||
new-id->order (when (seq created-ids) (zipmap created-ids new-orders))
|
||||
created-shapes (set (filter #(created-ids (:id %)) upsert-shapes))
|
||||
deleted-ids (->> (set/difference old-ids new-ids)
|
||||
(remove string/blank?))
|
||||
|
@ -136,9 +132,13 @@
|
|||
deleted-shapes-tx (mapv (fn [id] [:db/retractEntity [:block/uuid (uuid id)]]) deleted-ids)
|
||||
upserted-blocks (->> upsert-shapes
|
||||
(map #(shape->block % (:db/id page-entity)))
|
||||
(map sqlite-util/block-with-timestamps))
|
||||
(map sqlite-util/block-with-timestamps)
|
||||
(map (fn [block]
|
||||
(if-let [new-order (when new-id->order (get new-id->order (str (:block/uuid block))))]
|
||||
(assoc block :block/order new-order)
|
||||
block))))
|
||||
page-name (or (:block/original-name page-entity) (str page-uuid))
|
||||
page-block (build-page-block page-entity page-name tl-page assets shapes-index)]
|
||||
page-block (build-page-block page-entity page-name tl-page assets)]
|
||||
(when (or (seq upserted-blocks)
|
||||
(seq deleted-shapes-tx)
|
||||
(not= (:block/properties page-block)
|
||||
|
@ -153,12 +153,51 @@
|
|||
|
||||
(defonce *last-shapes-nonce (atom {}))
|
||||
|
||||
(defn- get-shape-block-id
|
||||
[^js shape]
|
||||
(uuid (.-id shape)))
|
||||
|
||||
(defn- handle-order-update!
|
||||
[page info]
|
||||
(let [op (:op info)
|
||||
moved-shapes (:shapes info)
|
||||
shape-ids (mapv get-shape-block-id moved-shapes)]
|
||||
(case op
|
||||
"sendToBack"
|
||||
(let [next-order (when-let [id (get-shape-block-id (:next info))]
|
||||
(:block/order (db/entity [:block/uuid id])))
|
||||
new-orders (db-order/gen-n-keys (count shape-ids) nil next-order)
|
||||
tx-data (conj
|
||||
(map-indexed (fn [idx id]
|
||||
{:block/uuid id
|
||||
:block/order (nth new-orders idx)}) shape-ids)
|
||||
(outliner-core/block-with-updated-at {:db/id (:db/id page)}))]
|
||||
tx-data)
|
||||
|
||||
"bringToFront"
|
||||
(let [before-order (when-let [id (get-shape-block-id (:before info))]
|
||||
(:block/order (db/entity [:block/uuid id])))
|
||||
new-orders (db-order/gen-n-keys (count shape-ids) before-order nil)
|
||||
tx-data (conj
|
||||
(->>
|
||||
(map-indexed (fn [idx id]
|
||||
(when (db/entity [:block/uuid id])
|
||||
{:block/uuid id
|
||||
:block/order (nth new-orders idx)})) shape-ids)
|
||||
(remove nil?))
|
||||
(outliner-core/block-with-updated-at {:db/id (:db/id page)}))]
|
||||
tx-data))))
|
||||
|
||||
;; FIXME: it seems that nonce for the page block will not be updated with new updates for the whiteboard
|
||||
(defn <transact-tldr-delta!
|
||||
[page-uuid ^js app replace?]
|
||||
(let [tl-page ^js (second (first (.-pages app)))
|
||||
shapes (.-shapes ^js tl-page)
|
||||
[page-uuid ^js app ^js info*]
|
||||
(let [info (bean/->clj info*)
|
||||
replace? (:replace info)
|
||||
tl-page ^js (second (first (.-pages app)))
|
||||
page-block (model/get-page page-uuid)
|
||||
order-tx-data (when (contains? #{"bringToFront" "sendToBack"} (:op info))
|
||||
(handle-order-update! page-block info))
|
||||
shapes (.-shapes ^js tl-page)
|
||||
new-id-nonces (set (map-indexed (fn [_idx shape]
|
||||
(let [id (.-id shape)]
|
||||
{:id id
|
||||
|
@ -170,8 +209,8 @@
|
|||
(map #(update % :id str)))))
|
||||
{:keys [page-block new-shapes deleted-shapes upserted-blocks delete-blocks metadata] :as result}
|
||||
(compute-tx app tl-page new-id-nonces db-id-nonces page-uuid replace?)]
|
||||
(when (seq result)
|
||||
(let [tx-data (concat delete-blocks [page-block] upserted-blocks)
|
||||
(when (or (seq result) (seq order-tx-data))
|
||||
(let [tx-data (concat delete-blocks [page-block] upserted-blocks order-tx-data)
|
||||
metadata' (cond
|
||||
;; group
|
||||
(some #(= "group" (:type %)) new-shapes)
|
||||
|
@ -313,7 +352,7 @@
|
|||
([{:keys [pages blocks]} api]
|
||||
(let [page-block (first pages)
|
||||
;; FIXME: should also clone normal blocks
|
||||
shapes (build-shapes page-block blocks)
|
||||
shapes (build-shapes blocks)
|
||||
tldr-page (pu/page-block->tldr-page page-block)
|
||||
assets (:assets tldr-page)
|
||||
bindings (:bindings tldr-page)]
|
||||
|
@ -342,8 +381,8 @@
|
|||
(let [tl-page ^js (second (first (.-pages app)))]
|
||||
(when tl-page
|
||||
(when-let [page (db/get-page page-uuid)]
|
||||
(let [page-metadata (pu/get-block-property-value page :logseq.property.tldraw/page)
|
||||
shapes-index (:shapes-index page-metadata)]
|
||||
(let [shapes-index (->> (db/sort-by-order (:block/_page page))
|
||||
(map (comp str :block/uuid)))]
|
||||
(when (seq shapes-index)
|
||||
(.updateShapesIndex tl-page (bean/->js shapes-index)))))))))
|
||||
|
||||
|
|
Loading…
Reference in New Issue