feat(forum): add the reference forum widgets
Port the six forum widgets from the reference theme: posts list, multi-tab posts, plate list (default and card), plate info, moderator list and topic list. They join the schema widget catalog under a forum group that stays hidden while the forum module is off, reuse the shared forum cards, paginate through the widget REST client contract, and pull the forum stylesheet/runtime onto any sidebar that hosts them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
376827ea97
commit
eceddb5f7d
12 files changed
+724
-13
No files matched your search
@@ -0,0 +1,86 @@
|
||||
const test = require('node:test')
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..')
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8')
|
||||
|
||||
const SLUGS = ['forum_posts', 'forum_tab_posts', 'forum_plates', 'forum_plate_info', 'forum_moderators', 'forum_topics']
|
||||
|
||||
test('every reference forum widget is catalogued with a schema and a renderer', () => {
|
||||
const catalog = read('src/WidgetSystem/WidgetCatalog.php')
|
||||
const registry = read('src/WidgetSystem/RendererRegistry.php')
|
||||
const schemas = read('src/Forum/WidgetSchemas.php')
|
||||
const renderer = read('src/Forum/WidgetRenderer.php')
|
||||
for (const slug of SLUGS) {
|
||||
assert.ok(catalog.includes(`['${slug}',`), `${slug} missing from the widget catalog`)
|
||||
assert.ok(registry.includes(`'${slug}' => \\Jio\\Forum\\WidgetRenderer::class`), `${slug} missing from the renderer registry`)
|
||||
}
|
||||
// The plate info card is configuration-free, like the reference widget.
|
||||
for (const slug of SLUGS.filter((slug) => slug !== 'forum_plate_info')) {
|
||||
assert.ok(schemas.includes(`case '${slug}':`), `${slug} missing a field schema`)
|
||||
}
|
||||
for (const slug of SLUGS) {
|
||||
assert.ok(renderer.includes(`case '${slug}':`), `${slug} renderer missing`)
|
||||
}
|
||||
assert.match(catalog, /\$forum \? \\Jio\\Forum\\WidgetSchemas::for\(\$slug\) : WidgetSchemas::for\(\$slug\)/)
|
||||
})
|
||||
|
||||
test('forum widgets reuse the shared reference cards instead of forking markup', () => {
|
||||
const renderer = read('src/Forum/WidgetRenderer.php')
|
||||
for (const helper of ['Cards::post_detail(', 'Cards::post_mini(', 'Cards::title(', 'Cards::plate_item(', 'Cards::plate_slide(', 'Cards::follow_button(']) {
|
||||
assert.ok(renderer.includes(helper), `forum widgets must reuse ${helper}`)
|
||||
}
|
||||
assert.doesNotMatch(renderer, /zib|zibll|Qinver/i)
|
||||
})
|
||||
|
||||
test('forum widget lists paginate through the widget REST client contract', () => {
|
||||
const renderer = read('src/Forum/WidgetRenderer.php')
|
||||
const query = read('src/Forum/WidgetQuery.php')
|
||||
const registry = read('src/WidgetSystem/RendererRegistry.php')
|
||||
const rest = read('src/WidgetSystem/RestController.php')
|
||||
// The container carries the attributes frontend.js reads, with the skeleton inside it.
|
||||
assert.match(renderer, /class="widget-ajaxpager"/)
|
||||
assert.match(renderer, /data-widget-items data-widget=/)
|
||||
assert.match(renderer, /post_ajax_loader/)
|
||||
assert.doesNotMatch(renderer, /post_ajax_trigger/)
|
||||
// Item payloads resolve through the forum query builder, not the article one.
|
||||
assert.match(rest, /\\Jio\\Forum\\WidgetQuery::payload/)
|
||||
assert.match(registry, /WidgetRenderer::SUPPORTS_ITEMS/)
|
||||
assert.match(query, /jio_forum_list/)
|
||||
// Pagination exposes the widget client's page hooks and the reference modes.
|
||||
assert.match(query, /data-widget-page=/)
|
||||
assert.match(query, /data-next-page=/)
|
||||
assert.match(query, /ajaxpager-target="\.widget-ajaxpager"/)
|
||||
const schemas = read('src/Forum/WidgetSchemas.php')
|
||||
assert.match(schemas, /'ajax_lists'/)
|
||||
assert.match(schemas, /'default' => '数字翻页按钮'/)
|
||||
})
|
||||
|
||||
test('plate-scoped forum widgets stay silent outside plate and post pages', () => {
|
||||
const renderer = read('src/Forum/WidgetRenderer.php')
|
||||
const core = read('src/Forum/Core.php')
|
||||
assert.match(core, /public static function current_plate_id\(\)/)
|
||||
for (const method of ['plate_info', 'moderators']) {
|
||||
const start = renderer.indexOf(`private static function ${method}(`)
|
||||
const body = renderer.slice(start, renderer.indexOf('private static function', start + 10))
|
||||
assert.match(body, /Core::current_plate_id\(\)/)
|
||||
assert.match(body, /Core::PLATE/)
|
||||
}
|
||||
})
|
||||
|
||||
test('forum widgets load the forum card styles and runtime on any sidebar', () => {
|
||||
const core = read('src/Forum/Core.php')
|
||||
const runtime = read('assets/js/forum-runtime.js')
|
||||
assert.match(core, /add_action\('wp_enqueue_scripts', \[self::class, 'widget_assets'\]/)
|
||||
assert.match(core, /public static function enqueue_css\(\)/)
|
||||
assert.match(core, /is_active_widget\(false, false, 'jio_widget_' \. \$slug, true\)/)
|
||||
assert.match(runtime, /document\.getElementById\('forum'\) \|\| document\.body/)
|
||||
})
|
||||
|
||||
test('forum widgets keep the module off until it is enabled', () => {
|
||||
const catalog = read('src/WidgetSystem/WidgetCatalog.php')
|
||||
assert.match(catalog, /if \(\$group === 'forum' && !\$forum_on\)/)
|
||||
assert.match(catalog, /function_exists\('jio_get_setting'\) && \\Jio\\Forum\\Core::enabled\(\)/)
|
||||
})
|
||||
Reference in new issue
Block a user