About Frame Integrations

The Frame plugin offers several hooks for authors interested in extending the behavior of federated wiki. JavaScript programs in the framed content can use the postMessage() protocol to tell the wiki client to follow a collaborative link, create a ghost page, or import pages into the hosting wiki.

The following examples attach a click handler to a button in the framed page.

//dobbs.github.io/wiki-plugin-frame/assets/integrations.html HEIGHT 350

Note: The keepLineup property enables the button inside the frame to treat the shift key the same way wiki readers have come to expect from links and buttons.

# Open an Existing Page

document.querySelector("button") .addEventListener("click", event => { window.parent.postMessage({ action:"doInternalLink", title: "About Frame Plugin", keepLineup: event.shiftKey }, "*"); });

# Create a Ghost Page

document.querySelector("button") .addEventListener("click", event => { window.parent.postMessage({ action:"showResult", page: { title: "Hello, World!", story: [ { type: "paragraph", text: "Greetings from frame content!", id: Math.abs(Math.random()*1e20|0) .toString(16) } ]}, keepLineup: event.shiftKey }, "*"); });

# Import Many Pages

function itemId() { return Math.abs(Math.random()*1e20|0).toString(16) } document.querySelector("button") .addEventListener("click", event => { window.parent.postMessage({ action:"import", pages: { "hello-world": { title: "Hello, World!", story: [ { type: "paragraph", text: "Greetings from frame content!", id: itemId() } ]}, "greetings-programs": { title: "Greetings, Programs!", story: [ { type: "paragraph", text: "We're inside the MCP cone!", id: itemId() } ]} }, keepLineup: event.shiftKey }, "*"); });

# Send Frame Context

In some cases, authors construct framed content that needs to know about other items on the hosting page. This requires that the framed content install a message listener to receive the context information.

window.addEventListener("message", event => { const {data} = event if (data.action == "frameContext") { const {slug, item, page} = data let code = page.story.find(it => { return it.type == "code" }) console.log(code.text) } }) window.addEventListener( "DOMContentLoaded", () => window.parent.postMessage({ action: "sendFrameContext" }, "*") )

# URL Includes Identifiers

const identifiers = Object.fromEntries( new URLSearchParams( window.location.hash.substr(1) ).entries() ) console.log({ slug: identifiers.slug, pageKey: identifiers.pageKey, itemId: identifiers.itemId })

There are many other resources around the federation about extending wiki in interesting and novel ways.

We define the schema for federated wiki pages to the depth that we know it. We use a BNF-like notation to suggest JSON elements. Any ambiguity will be resolved by examining the example. We close with a brief reflection on the successes of the format.

We built the federation based on the promiscuous sharing of simple things with the hope that this would lead the community to save indefinitely things worth saving. Within a year we had moved from ruby to node without leaving ruby sites behind. Now, in the federation's ninth year, we consider how this process might be further distributed.

We explain federated wiki plugins. We define their role interpreting content, recount our experience writing many, describe principles and strategies for future plugins, and offer a step-by-step guide for new plugin authors. We'll also collect pointers here to good plugins when they emerge.