2023-08-29 17:32:02 +08:00

190 lines
5.0 KiB
TypeScript

import { partition } from "rambdax"
let language: string
export function setLanguage(val: string) {
language = val
}
export async function hash(text: string) {
if (!text) return ""
const bytes = new TextEncoder().encode(text)
const hashedArray = Array.from(
new Uint8Array(await crypto.subtle.digest("SHA-1", bytes)),
)
const hashed = hashedArray
.map((b) => b.toString(16).padStart(2, "0"))
.join("")
return hashed
}
export async function queryForSubItems(name: string) {
name = name.toLowerCase()
const namespaceChildren = (
await logseq.DB.datascriptQuery(
`[:find (pull ?p [:block/name :block/original-name :block/uuid :block/properties])
:in $ ?name
:where
[?t :block/name ?name]
[?p :block/namespace ?t]]`,
`"${name}"`,
)
).flat()
namespaceChildren.forEach((p: any) => {
const originalName = p["original-name"]
const trimStart = originalName.lastIndexOf("/")
p.displayName =
trimStart > -1 ? originalName.substring(trimStart + 1) : originalName
})
const hierarchyProperty = logseq.settings?.hierarchyProperty ?? "tags"
const taggedPages = (
await logseq.DB.datascriptQuery(
hierarchyProperty === "tags"
? `[:find (pull ?p [:block/name :block/original-name :block/uuid :block/properties])
:in $ ?name ?equals ?contains
:where
[?t :block/name ?name]
[?p :block/tags ?t]]`
: `[:find (pull ?p [:block/name :block/original-name :block/uuid :block/properties])
:in $ ?name ?equals ?contains
:where
[?p :block/original-name]
[?p :block/properties ?props]
[(get ?props :${hierarchyProperty}) ?v]
(or [(?equals ?v ?name)] [(?contains ?v ?name)])]`,
`"${name}"`,
equals,
contains,
)
).flat()
const quickFilters = await getQuickFilters(name)
if (
namespaceChildren.length === 0 &&
taggedPages.length === 0 &&
quickFilters.length === 0
)
return namespaceChildren
const list = namespaceChildren.concat(taggedPages).concat(quickFilters)
const [fixed, dynamic] = partition(
(p: any) => p.properties?.fixed != null,
list,
)
fixed.sort((a, b) => a.properties.fixed - b.properties.fixed)
dynamic.sort((a, b) =>
(a.displayName ?? a["original-name"]).localeCompare(
b.displayName ?? b["original-name"],
language,
),
)
const result = fixed
.concat(dynamic)
.slice(0, logseq.settings?.taggedPageLimit ?? 30)
return result
}
async function getQuickFilters(name: string) {
const [{ uuid: blockUUID }, { uuid: pageUUID }] = (
await logseq.DB.datascriptQuery(
`[:find (pull ?b [:block/uuid]) (pull ?p [:block/uuid])
:in $ ?name
:where
[?p :block/name ?name]
[?b :block/page ?p]
[?b :block/pre-block? true]]`,
`"${name}"`,
)
)[0] ?? [{}, {}]
if (blockUUID == null || pageUUID == null) return []
let quickFiltersStr
try {
quickFiltersStr = JSON.parse(
(await logseq.Editor.getBlockProperty(blockUUID, "quick-filters")) ??
'""',
)
} catch (err) {
console.error(err)
return []
}
if (!quickFiltersStr) return []
const groups = quickFiltersStr.match(/(?:\d+\s+)?(?:\[\[[^\]]+\]\]\s*)+/g)
if (groups == null) return []
const quickFilters = groups
.map((filterStr: string) => {
const matches = Array.from(
filterStr.matchAll(/\[\[([^\]]+)\]\]\s*|(\d+)/g),
)
const fixed = matches[0][2] ? +matches[0][2] : null
const tags = (fixed == null ? matches : matches.slice(1)).map((m) => m[1])
return [tags, fixed]
})
.filter(([tags, fixed]: any) => tags.length > 0)
.reduce((filter: any, [tags, fixed]: any) => {
if (filter[tags[0]] == null) {
filter[tags[0]] = {}
if (fixed != null) {
filter[tags[0]].properties = { fixed }
}
}
constructFilter(filter[tags[0]], name, blockUUID, pageUUID, tags, [])
return filter
}, {})
return Object.values(quickFilters)
}
function constructFilter(
obj: Record<string, any>,
name: string,
blockUUID: string,
pageUUID: string,
tags: string[],
path: string[],
) {
if (obj.displayName == null) {
obj.name = name
obj.blockUUID = blockUUID
obj.pageUUID = pageUUID
obj.displayName = tags[0]
obj.filters = [...path, tags[0]]
}
tags = tags.slice(1)
if (tags.length === 0) return
if (obj.subitems == null) {
obj.subitems = {}
}
if (obj.subitems[tags[0]] == null) {
obj.subitems[tags[0]] = {}
}
constructFilter(
obj.subitems[tags[0]],
name,
blockUUID,
pageUUID,
tags,
obj.filters,
)
}
function equals(prop: any, val: string) {
if (prop.toLowerCase == null) return false
return prop.toLowerCase() === val.toLowerCase()
}
function contains(prop: any, val: string) {
if (!Array.isArray(prop)) return false
const lowerVal = val.toLowerCase()
return prop.some((v) => v.toLowerCase().includes(lowerVal))
}