Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Latest commit

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

js-runtime

JavaScript runtime and optional AJAX navigation library. The runtime was built to solve two common problems:

  • Make working with lightweight reactive view libraries such as petite-vue more ergonomic, with no need to wait for app instances to mount and with simpler component registration.
  • Provide a consistent way to write JavaScript that works whether AJAX navigation is enabled or not.

See https://www.leetimmins.com/blog/building-a-javascript-runtime-for-ajax-navigation-and-traditional-page-loads.htm for more information.

Vue Integration

Component registration happens before the app is mounted, which means modules can register components up front and the runtime can then mount the app with the complete registry.

import{register}from'./runtime.js';importCounterfrom'./components/counter.js';register('Counter',Counter);

Getting Started

In modern frameworks, JavaScript modules (<script type="module">) are now the entry point for writing JavaScript. They have a few important advantages:

  • They wait until the DOM is ready before running.
  • They only execute once, no matter how many times they are referenced.
  • They make it easy to import code from other libraries.

That solves part of the problem, but not all of it. In many applications the HTML is not truly static and may be replaced or inserted at runtime. Event delegation can help when you are attaching a listener to an element that already exists and will continue to exist, such as document:

document.addEventListener('click',e=>{if(!e.target.closest('[data-action="delete"]'))return;// Handle click.});

This works because document exists when the code runs, and the delegated handler can react to matching descendants that are added later. But it only solves that event-listening case: module scripts and DOM lookups such as querySelector() still only work with the elements that exist when they run, so later HTML updates from AJAX navigation or dynamic content insertion need a different approach.

The runtime introduces page hooks and load hooks to make this easier. These hooks let you write initialization code once and have it behave correctly across normal page loads, AJAX navigation, and dynamically added HTML. They also wait until the DOM has mounted before they run, which helps avoid timing problems when working with Vue state.

Once the runtime is configured, you can use the hooks it provides to initialize and manage behavior at the right point in the page lifecycle:

  • Use page hooks when behavior should run each time a page navigation occurs.
  • Use load hooks when behavior should run for DOM that has just been mounted, whether that is on initial load or after it has been processed, e.g. after it is dyanmically inserted.

Page Hooks

Page hooks are registered against the active module script whose import.meta you pass in. In practice, that means a module script can register page hooks once and those hooks will automatically apply on any page that includes that module.

Register page hooks from module files, not from inline scripts. Inline scripts, including inline module scripts, are executed each time they are encountered during AJAX navigation, so hooks declared there will be registered again on every visit.

Use static module loading when you want to pull in a file that registers hooks. Both of the following work:

<scripttype="module" src="/js/page.js"></script>
import'/js/page.js';

Avoid using a dynamic import for hook registration:

import('/js/page.js');

A dynamically imported module is asynchronous, so its hook registration is not guaranteed to happen before the initial hook phases run. Even await import('/js/page.js') does not guarantee that the imported module has registered its hooks before those lifecycle events have already been triggered.

If a page includes the module, its page hooks will run on the initial page load and on later AJAX navigations to other pages that also include that same module. onPageLoad() and onPageUnload() therefore follow page navigation, not module addition and removal. onPageUnload() is useful for persistence or other non-DOM cleanup. If the DOM is being replaced, element-bound listeners usually do not need explicit teardown.

These hooks run for standard page loads and enhanced AJAX navigations. onPageLoad() runs after the page DOM has been mounted, so it is safe to work with mounted Vue state and DOM produced by Vue.

onPageLoad() receives an isCacheRestore boolean. It is true when the page was restored from the browser back-forward cache (bfcache) and false for normal loads and AJAX navigations. By default, onPageLoad() skips bfcache restores. This helps avoid re-attaching DOM event handlers on pages restored from the browser cache.

onPageLoad(import.meta,()=>{document.getElementById('foo').addEventListener('change', ...);});

If you want the callback to also run on bfcache restores, set includeCacheRestore: true:

onPageLoad(import.meta,context=>{if(context.isCacheRestore){
...
}},{includeCacheRestore: true});

Dynamic HTML

onLoad() runs for both the HTML present on the initial page load and any HTML added dynamically later, so you can safely work with the DOM in either case. It also runs after the runtime has mounted, so you can safely access Vue state inside the callback.

import{onLoad}from'./runtime.js';onLoad(context=>{context.querySelectorAll('.slug').forEach(slug=>{
...
});});

If you manually add an HTML block after startup and want the runtime to process it, call process() for that root element.

import{process}from'./runtime.js';constelement=document.getElementById('new-content');awaitprocess(element);

AJAX Navigation

AJAX navigation is optional. The runtime works without it, and standard browser navigation will continue to behave normally unless you also load the AJAX navigation library.

Testing

npm test

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages