Edit and run javascript code inside Logseq itself

  • There is no such thread. There are (at this time) around 30 relevant threads. Either:
    • look at the end of the OP for a list of backlinks
    • search the forum for “kits”
  • People usually write very customized code, which they rarely make it generic enough for sharing.

Thank you! Will look

I understand. I wasn’t really expecting code… Just short descriptions (maybe with a couple of screenshots), to have a feel for what people have been doing!

I’d definitely be interested in seeing some use general descriptions or screenshots of use cases as well. Really curious about this functionality

I am also interested in seeing other examples, so I will start. (I’m unsure if this is starting a subtopic, please spin it off if so).

I use kits to create “functions” as templates. To make them more usable, I specify what is input at the beginning. It seems like a workaround for which there is likely a better option, but I do not know better.

For instance, one that may be of broader user:

/* INPUT */
let present = 5000, intrate = 5, n = 1, depo = 200, ndepo = 12, time = 8;
let type = 0; // 0 = ordinary, 1 = due

/* METHOD */
let perrate = intrate / 100 / n;
let perdepo = depo * ndepo;
let USD = new Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD',});

let fut = present * (Math.pow((1 + perrate), n * time));
let futper = perdepo * (Math.pow((1 + perrate), n * time) - 1) / perrate * (1 + perrate * type);
let future = fut + futper;
    
/* OUTPUT */
return("FV of Principal = " + USD.format(fut) + "\n" 
       + "FV of Periodic Deposits = " + USD.format(futper) + "\n" 
       + "FV = " + USD.format(future));
1 Like

I see what you mean about the calculations.

  • I have tried both
    • the macro option you suggested with kits
      • (an excellent usage example)
    • the full house templates approach from @stdword
      • I use these extensively, though not to their maximum potential
  • Yet, I use a template such as above for more exploratory calculations
    • where I may want to rapidly test changing inputs
    • and compare the different results.

The Synthesis approach I have not tested yet, but it is beautiful. I look forward to your further development and the next tutorial threads.

1 Like

It works great! (once I started to get the hang of it :laughing:) Thank you for the awesome work!

The only thing I find a bit inconvenient is that every macro needs it’s own page. If I understand it right, they cannot even have their own namespace (like kits/macro1), because the entry function needs to have the same name as the page name, right? That means a lot of extra pages on my graph if I want many small macros. :worried:
Or maybe I am missing something, or understanding something wrong?

Thank you again for the great work!


Also thanks to @adxsoft for the demo graph (super helpful!) and to @dannylin108 for the question below which saved me quite a bit of headache :sweat_smile:)

1 Like
  • This is the convention for routing a macro to some code that has not been loaded yet.
  • For more flexibility, either:
    • use a routing macro that redirects execution based on either:
      • its first parameter
        • Thus instead of e.g. {{m1 arg1 arg2}} to use e.g. {{k m1 arg1 arg2}}
      • some html attribute in the macro’s definition
        • read in the entry function with .dataset or .getAttribute
    • implement your own routing by modifying e.g. function runPageByName
      • For example, you could possibly force all code-pages under namespace kits, e.g. with logseq.api.get_page("kits/" + pageName)
        • This is just some untested idea.
    • move to Synthesis
      • It can run code just like kits, but at the level of blocks.
1 Like

I will try it out. Thanks again!

I’ve noticed that from time to time, the buttons I have defined using your suggested code stop working. This seems to happen more often on my iPhone than on my Mac, but it does happen on both.

It only happens in an already-running Logseq instance, usually after it’s been running for awhile, and after I’ve been doing other things on the device. Restarting Logseq always fixes the problem. Any idea what may be causing this, or how to diagnose and/or fix it?

I need something reproducible.

  • What about re-running the macro?
    • editing the block
    • reopening the page
  • Do you use multiple identical buttons?
  • Do you have multiple buttons in the same block?
  • Do you have buttons on the sidebar?
  • Generally, anything suspicious that could lead to something reproducible.

Thanks. I was about to update my question, because I realized that I’m having two separate issues.

On the Mac, it’s this one, specifically related to an updated version of my query and your MassDelete script. My other button continues to always work on the Mac.

So the issue with buttons in general stopping working is so far limited to the iPhone.

I’ll check this next time it happens on the iPhone

Not in the same page.

No

No (now that we’re just talking about the iPhone)

I’ll keep my eye out for anything reportable. There’s no way I know of to access the console on the iPhone, so options are limited.

Is there a way to embed one of these macro buttons within HTML and have it run the JS on another page when clicked or create a slash command that can run the JS on another page?

When I paste this button tag within LogSeq, it runs when the button is rendered but not when I click on it. Is there a way to have it run only when clicked?
<button class='kit run' data-kit='JS/Hello World'>Click Me</button>

Edit: The below button setup only runs when clicked.
<button class='kit run' data-kit='runpage' data-page-name='JS/Hello World'>Hello World</button>

I’m still curious if there’s a way to run a page using a slash command instead of needing to click a button

1 Like

To run page JS/Hello World:

  • with a button, the provided way is {{runpage JS/Hello World}}
  • on demand without a button, consider using the console for something that calls logseq.Module.Kits.runPageByName("JS/Hello World")

Using {{runpage JS/Hello World}} is a decent solution for what I’ve been doing. Many times, it requires accessing the “current block”, so using the console isn’t ideal - console also isn’t supported on mobile.

I was curious if there was a way to register a slash command through logseq’s native API (which is different from the plugin API) to run a JS page. Having a slash command reduces the steps from adding the button and clicking on it to running the slash command.

Consider implementing a keyboard listener (e.g. like this one) that makes the above call, potentially reading any arguments (e.g. page name) from the textarea.

That’s a neat idea on how to add a customizable keyboard shortcut; I’ll have to look into it.

Thanks for sharing!

I really like working with this paradigm, it allows me to be extensible with logseq in a very useful way. A quick question/suggestion I had was would it be possible to have the functionality that {{evalparent}} has (in terms of displaying outputs and images) to the other macros?

I made a quick expense tracker within logseq itself using basic queries, and used this to generate a graph through python. The code runs with all the options, but only {{evalparent}} can display the outputs. Since the code is somewhat long, I wanted to move it to another file and run it using {{runpage mypage}} setup, which runs the page, but the output is not passed on to where the button is. What is a good way to go about this?

I’ve come up with a few options (I’ve not implemented any, and I don’t know the full structure of the code yet, and I’m not sure what would be in line with the structure used here):

  1. Write the output to a file and link it under the {{runpage ...}} button in logseq
  2. Have someway to pipe the output of the code and implement the same thing {{evalparent}} has to other options
  3. Use the logseq api to write the image to a specific block

Welcome.

  • Your suggestion is not as straightforward as it sounds.
    • Because usually a page doesn’t produce a single result.
  • One way to achieve it is through the following steps:
    • Add a separate macro like this one:
      :fromrunpage "<button class='kit run' data-kit='runpage' data-page-name='$1' data-show-res>► Result from running code of page $1</button>"
      
    • Find the following line of code in file custom.js :
          Kits.runPageByName(pageName);
      
    • Replace it with these lines:
          const button = e.target;
          const divRow = button.hasAttribute("data-show-res") && Kits.onParentEvalStarted(button.closest("div.ls-block"));
          Kits.runPageByName(pageName).then( (res)=>{
              if (divRow) Kits.onParentEvalFinished(divRow, res);
          });
      
    • Use the new macro like this: {{fromrunpage mypage}}

This works, its absolutely great! Thank you so much!