Kit to automatically populate a block with content of parent block

Is it possible to populate a block with the content of the parent block using kits? For example

- [[Parent Block Title]]
  - TODO Some task #someone needs to do
    agency-name:: {{parentref}}

Yes:

  • Ensure that kits is functional.
  • Add the following macro inside file config.edn , inside macros{} :
    :pp "<span class='kit' data-kit='parentprop' data-prop='$1'>$1:: parent</span>"
    
    • Can replace pp with a name of your preference.
  • Inside page ParentProp in Logseq, put the following code in a javascript code-block:
    logseq.kits.setStatic(function parentprop(span){
    	if (span.closest('.ls-block:has(a[data-ref=template])')) return
    
        const blockId = span.closest(".ls-block").getAttribute("blockId")
        const block = logseq.api.get_block(blockId)
    
        const content = block.content
        const macroName = span.closest(".macro").dataset.macroName
        const macroStart = content.indexOf("{{" + macroName)
        const macroEnd = content.indexOf("}}", macroStart) + 2
    
        const prop = span.dataset.prop
        const text = logseq.api.get_block(block.parent.id).content
        const replace = (prop === '$1' ? text : '')
        const newContent = content.slice(0, macroStart) + replace + content.slice(macroEnd)
        logseq.api.update_block(blockId, newContent.replace('{{' + macroName + '}}', ''))
        if (!replace) logseq.api.upsert_block_property(blockId, prop, text)
    })
    
  • Now to add the content of parent block to e.g. property propname:: of a block:
    • don’t type this: propname:: {{pp}}
    • type instead this: {{pp propname}}
  • To ignore the property and instead have the content of the parent directly replace the macro, type {{pp}}
    • To replace a macro inside a query, add one more {{pp}} at the end of the block.

You are absolutely awesome! Thanks.

I tried on my own but didn’t have any luck. Can I have a version of the function that only gives me the contents of the parent block? May I also have the corresponding config.edn entry? I tried just making a copying your function and giving it a different name but calling it gave no output.

I’m not sure of what you expect. Please be more specific. Maybe describe the steps that you made, so as to find the misunderstanding.

Thanks for responding. Your current script takes one argument and provides an output like this: $1:: [[parent block]] (example, agency:: [[ENAGB]]). I would like a version that just gives me the parent block content by itself with no argument. For example,

- [[Parent Block Content]]
  -{{pq}}

will give me

- [[Parent Block Content]]
  -[[Parent Block Content]]

My plan is to use this function to dynamically provide the value for block/name in an advanced query based on the value of the parent block. That way, I can query all the tasks and linked tasks for that page. For example

- [[ENAGBE]]
  - #+BEGIN_QUERY
    {:title [:h3 "Tasks with page reference"]
    :query [:find (pull ?b [*])
        :where
           [?p :block/name "{{pq}}"]
           [?b :block/refs ?p]
           [?b :block/marker "TODO"]]}
     #+END_QUERY

I have updated the code to support your scenario with the same macro. Read the additional instructions at the end.

Hello again,
I tried this out today, because I want to try to auto-evaluate LaTex equasions using JavaScript, but it just seems to return

$1:: parent

or

macro-argument:: parent

I’ve tried all three versions of the code, I have it in my config.edn, I have the page you gave me, but somehow it just always returns parent no matter what I giveconfig.edn:

 :macros {
  :pp "<span class='kit' data-kit='parentprop' data-prop='$1'>$1:: parent</span>"
}

ParentProp.md:

  logseq.kits.setStatic(function parentprop(span){
  	if (span.closest('.ls-block:has(a[data-ref=template])')) return
  
      const blockId = span.closest(".ls-block").getAttribute("blockId")
      const block = logseq.api.get_block(blockId)
  
      const content = block.content
      const macroName = span.closest(".macro").dataset.macroName
      const macroStart = content.indexOf("{{" + macroName)
      const macroEnd = content.indexOf("}}", macroStart) + 2
  
      const prop = span.dataset.prop
      const text = logseq.api.get_block(block.parent.id).content
      const replace = (prop === '$1' ? text : '')
      const newContent = content.slice(0, macroStart) + replace + content.slice(macroEnd)
      logseq.api.update_block(blockId, newContent.replace('{{' + macroName + '}}', ''))
      if (!replace) logseq.api.upsert_block_property(blockId, prop, text)
  })

Test JavaScript.md

-
$$3*3$$
-```runjs
  // Load Evaluatex.js dynamically
  const script = document.createElement('script');
  script.src = 'https://cdn.jsdelivr.net/npm/evaluatex@latest/dist/evaluatex.min.js';
  document.head.appendChild(script);
  script.onload = async () => {
  try {
    const latex = "3*3"
    // Evaluate the LaTeX expression
    const fn = evaluatex(latex);
    const result = fn();
  // Display the result in this block
    setOutput(result);
  } catch (err) {
    setOutput('Error: ' + err.message);
  }
  };
  ```
- Test
	- {{pp}}
	-

Does the format of the macro section in config.edn matter? Does the formatting of the JavaScript matter? Does it not actually have a parent and I’m stupid?

Thanks in advance, all answers are welcome

Welcome.

  • Ensure that when you restart Logseq you get the “kits ok” message.
    • Mind that runjs and kits are independent from each-other.
  • Ensure that the code in file ParentProp.md is placed inside a Javascript code-block.
  • Check the log for any errors (Ctrl + Shift + i).