(post updated to share clear instructions)
Instructions
- Follow @mentaloid’s instructions to set up Kits: Edit and run javascript code inside Logseq itself
- Create a page titled
ScrollToLastBlock
in Logseq. - In a code block in that page, add the following code:
const Kits = logseq.Module.Kits; const doClick = new MouseEvent('click', { view: window, bubbles: true, cancelable: true, }); logseq.kits.scrolltolastblock = Kits.addClickEventToButton.bind( null, function onClickScrollToLastBlock(e) { const div = e.target.closest('.blocks-container > div > div').lastChild; div.scrollIntoView(); // to scroll only until div aligns with the bottom of the viewport, change to `div.scrollIntoView({ block: 'end' })` if (div.classList.contains('w-full')) { const link = div.querySelector(':scope > a'); if (link) link.dispatchEvent(doClick); setTimeout(onClickScrollToLastBlock, 250, e); } } );
- Add the following in the
:macros
section ofconfig.edn
::scrolltolastblock "<button class='kit eval' data-kit='scrolltolastblock'>► Scroll to last block</button>"}
- Add
{{scrolltolastblock}}
as a block at the top of a lengthy page, and the button will scroll the page all the way to the last block. It even works on the sidebar, by simulating a mouse click on the “More” link!
Many thanks to @mentaloid for help. Feedback and suggestions welcome.
(Previous original post is below, for reference):
I wanted an automatic way to scroll to the last block of a long page, and to get around Logseq’s lazy-loading, so I made a button to do it.
Using @mentaloid 's Edit and run javascript code inside Logseq itself gave me the tools to get something working.
After setting up Kits per the instructions, I made a page titled ScrollToLastBlock with the following in a code block:
const Kits = logseq.Module.Kits;
const getBlocks = (el) => el.querySelectorAll("div.ls-block");
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
logseq.kits.scrolltolastblock = Kits.addClickEventToButton.bind(
null,
async function onClickScrollToLastBlock(e) {
const block = e.target.closest("div.ls-block");
const pageEl = block.closest(".page");
let blocks = getBlocks(pageEl);
let blockCount = blocks.length;
let prevBlockCount;
while (blockCount && blockCount !== prevBlockCount) {
const lastBlock = blocks[blockCount - 1];
lastBlock.scrollIntoView({ block: "end" });
await delay(250);
prevBlockCount = blockCount;
blocks = getBlocks(pageEl);
blockCount = blocks.length;
}
}
);
and added the following in the :macros
section of config.edn
:
:scrolltolastblock "<button class='kit eval' data-kit='scrolltolastblock'>► Scroll to last block</button>"}
Then by adding {{scrolltolastblock}}
at the top of a lengthy page, I have a button that scrolls all the way down for me, and Logseq lazy loads as it scrolls.
Any suggestions on improvements would be welcome!
It doesn’t work for long pages in the sidebar, because those require clicking the “more” link to load more blocks (sidebar doesn’t automatically lazy load).
I tried using the API to access the last block, which I found I could do, but I ran into trouble using the API to scroll to it. Relevant experimental section of code:
// api strategy: don't bother with unless scroll_to_block_in_page can work, but it doesn't.
// at top, add:
const LS = logseq.api;
// ...
const page = LS.get_current_page();
let childBlocks = LS.get_page_blocks_tree(page.uuid);
let hasChildren, lastBlock;
do {
lastBlock = childBlocks[childBlocks.length - 1];
childBlocks = lastBlock.children;
} while (lastBlock.children.length);
LS.scroll_to_block_in_page(page.name, lastBlock.uuid); //doesn't work
scrollToBlockInPage returned an error, using the underscore version scroll_to_block_in_page()
. If anyone has suggestions on how to get that working instead of the purely DOM method I’m using instead, I’m all ears.