Skip to content
View in the app

A better way to browse. Learn more.

ernestdefoe.online

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
ernestdefoe.online

Extensions, themes & support for Flarum and Invision Community

Vibe coding for the community web. Report a bug, request a feature, or dig into the source — this is where the tools you use get built, in the open.

We do custom Bespoke Invision Community apps. If you have an idea for something you want then use the contact form to get in touch with us.
Knowledge base

Things that cost me a day, so they cost you none

Working notes from building Invision Community and Flarum applications. Mostly the failures that give no error at all — the ones where everything installs cleanly and quietly does the wrong thing.

92 articles

Invision Community 5

86 articles

Extensions and contracts

39

What each extension point is for, what it must declare, and what happens when it is wrong — which is usually nothing visible.

Languages and text

5

The string table, translation, and the places where text does not appear where you expected it to.

Theming, templates and forms

9

Theme hooks, CSS that survives both colour schemes, and building forms that do not throw on render.

Background work and scheduled tasks

5

The queue system, work that has to happen after the response, and jobs that finish without doing anything.

Data, settings and storage

11

The database layer, settings, tags, file storage, and backing up a live site.

AI features and expectations

5

What these features do, what they cost, and what buyers reasonably but wrongly assume they do.

Application structure and releases

11

The JSON files an application is made of, versioning and upgrade steps, and testing from the command line.

Realtime, chat and calls

1

WebSocket gateways, relays and the server-side pieces live features depend on — where "it works when I test it" and "it works for your members" are different claims.

Nothing matches that.

Your editor toolbar button never appears, and nothing is logged

Invision Community 5's rich-text editor is TipTap, shipped as a compiled bundle. There is no source and no npm package, but there is a real third-party plugin API — and almost every way of getting it wrong fails silently. The editor loads perfectly, your button is simply absent, and there is nothing in any log to tell you why.

How an application ships editor JavaScript

Put plain .js files in applications/<app>/dev/editor/. Building the application writes them into data/editor.xml, and at runtime Invision concatenates every enabled application's plugins into one file.

Two things about that folder matter. Files must sit directly in dev/editor/ — a js/ subdirectory is skipped — and anything not ending .js is ignored.

Trap 1: the API is on ips.ui.editorv5

There is no ips.ui.editor at all. The whole editor is registered with ips.createModule( 'ips.ui.editorv5', … ).

/* WRONG — returns immediately, forever */
if ( !ips.ui.editor.registerExtension ) { return; }

Guarding on the wrong name means your file compiles, minifies, ships, installs and serves correctly while registering nothing. Invision wraps each plugin in a try/catch, but an early return is not a throw, so even that has nothing to report.

function editorApi() {
    if ( !window.ips || !ips.ui ) { return null; }

    var candidates = [ ips.ui.editorv5, ips.ui.editor ];

    for ( var i = 0; i < candidates.length; i++ ) {
        if ( candidates[ i ] && typeof candidates[ i ].registerExtension === 'function' ) {
            return candidates[ i ];
        }
    }

    return null;
}

Accept both names so a future rename cannot break it the same way, and retry briefly — createModule can define lazily.

Trap 2: the file is minified by a pre-ES6 minifier

Plugins are run through Garfix JsMinify, a JSMin descendant older than ES6. Template literals and regex literals do not survive it. Use string concatenation and new RegExp. Do not let a linter "modernise" the file.

Trap 3: locations is not a list of preferences

addButtons() {
    return {
        equation: {
            html:      '<span class="my-trigger"><i class="fa-solid fa-square-root-variable"></i></span>',
            command:   function ( props ) { /* … */ return true; },
            locations: [ null ]
        }
    };
}

A single null appends to the end of the toolbar. Naming an anchor — { after: 'link' } — is prettier, but the placement loop skips a button whose named anchor is absent. An administrator who hides that anchor makes your button vanish entirely, with no error. Unless the position genuinely matters, append.

Trap 4: your markup is sanitised, hard

What you return is injected inside Invision's own <button>, so the root element must not itself be a button. The tags script link style pre code iframe object embed noscript video are stripped, and every attribute except class style id src title rel alt is removed recursively. The element must have non-empty innerHTML or it throws.

The one that will actually cost you the afternoon

Before concluding your button is missing, check whether any toolbar exists:

document.querySelectorAll( '.ipsEditor__toolbar-item' ).length

A topic's reply box renders no toolbar at all until it is clicked. Load a topic, query for your button, and you get zero — not because registration failed, but because there is nothing there yet. Not one of Invision's own buttons is present either.

This looks identical to a broken plugin. It cost three rounds of debugging on an application whose button had been working the whole time; the tell was that the count above was 0 rather than 82. Open the editor first, then count.

When it really has failed

A broken plugin reports only to window.Debug?.error — no PHP error, no console error unless Debug is on. Two checks worth having:

  • Is your code in the served bundle at all? Fetch applications/core/interface/editor/index.php and search it for your application key. If it is absent, the problem is the build or dev/editor/, not your JavaScript.
  • Did your code run? Set a marker such as window.__myappDebug at the top of the file and again after registerExtension, then read it in the console. That distinguishes "never loaded" from "loaded and returned early" from "registered fine" — three failures that otherwise look the same.

The bundle is cached

Changes do not appear until Application::resetEditorPlugins() runs. It fires automatically on install, enable and upgrade, so during development reinstall the application rather than wondering why an edit had no effect.

User Feedback

Recommended Comments

There are no comments to display.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.