- 删除 AksrtFrontend registry/rehydrate 双路架构及 build/public.js 拼包入口,
前台唯一初始路径为 PHP 本地栈(jQuery 1.9.1 → Bootstrap 3.4.1)
→ loader_js(_win/aksrtData 唯一注入)→ tbquire(['main']) → runtime/main.min.js
- window.auto_fun = debounce(z_auto_fun, 100) 为唯一重扫入口;所有模块改为
执行一次 + off/on('auto_fun.aksrt-*') 命名空间重扫,data/class 标记幂等
- 局部更新协议统一:HTML 注入 → post_ajax.ed → auto_fun();
远程 modal → loaded.bs.modal → auto_fun();JSON 成功 → zib_ajax.success
- 灯箱恢复 Miniimgbox/imgbox 唯一 owner(imgbox-container、a[data-imgbox]、
imgbox_data),删除 AksrtLightbox/data-aksrt-lightbox 第二实现及 CSS/overlay,
_win.imgbox* 重新接上 post-display 设置
- 死代码清理:runtime 下 11 组被自有实现替代的旧模块副本、无消费 vendored 库、
顶层 grade.min.js、revenue.js、无调用方的 aksrt_get_win_runtime_config(),
以及 loader 中 16 条死 mapping
- PHP 入队改为本地栈 + loader_js,routed/widget/submit 依赖统一换绑;
用户卡片发布按钮恢复 nav_user_newposts_btn 设置门控
- 测试对齐:新增 frontend-lifecycle-contract,重写 navigation/lazyload/toast/
auth-source/comment/page-display/post-visual 等断言为目标架构契约
验证:node --test widget-system+navigation 223 通过 0 失败;
构建脚本重建 main/imgbox min 与 CSS bundles;改动 PHP php -l、JS node --check
全部通过;git diff --check 干净;credits 重入 harness 通过。
132 lines
6.0 KiB
JavaScript
132 lines
6.0 KiB
JavaScript
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const test = require('node:test');
|
|
|
|
const root = path.resolve(__dirname, '..', '..');
|
|
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
|
|
|
test('front submit enqueues the WordPress editor before wp_head is rendered', () => {
|
|
const source = read('templates/pages/page-submit.php');
|
|
const enqueueAt = source.indexOf('wp_enqueue_editor();');
|
|
const headerAt = source.indexOf('\nget_header();');
|
|
|
|
assert.notEqual(enqueueAt, -1, 'front submit must explicitly enqueue the editor runtime');
|
|
assert.notEqual(headerAt, -1, 'front submit must render the theme header');
|
|
assert.ok(enqueueAt < headerAt, 'editor assets must be queued before get_header()/wp_head');
|
|
});
|
|
|
|
test('front submit uploads use the effective WordPress server limit', () => {
|
|
const controller = read('src/Core/FrontSubmit.php');
|
|
const page = read('templates/pages/page-submit.php');
|
|
|
|
assert.match(controller, /function upload_limit_bytes\(string \$kind\): int/);
|
|
assert.match(controller, /min\(\$configured_mb \* MB_IN_BYTES, \(int\) wp_max_upload_size\(\)\)/);
|
|
assert.match(controller, /UPLOAD_ERR_INI_SIZE/);
|
|
assert.match(controller, /UPLOAD_ERR_FORM_SIZE/);
|
|
assert.match(controller, /UPLOAD_ERR_PARTIAL/);
|
|
assert.match(controller, /\['status' => 413\]/);
|
|
assert.match(page, /FrontSubmit::upload_limit_bytes\('image'\)/);
|
|
assert.match(page, /FrontSubmit::upload_limit_bytes\('video'\)/);
|
|
assert.match(page, /FrontSubmit::upload_limit_bytes\('resource'\)/);
|
|
assert.doesNotMatch(page, /\$attachment_settings\s*=/);
|
|
});
|
|
|
|
test('published post content reaches the front submit editor unchanged', () => {
|
|
const context = read('templates/parts/submit/context.php');
|
|
const editor = read('templates/parts/submit/editor-main.php');
|
|
|
|
assert.match(context, /\$current_content\s*=\s*\$edit_post\s*\?\s*\$edit_post->post_content\s*:\s*'';/);
|
|
assert.match(editor, /wp_editor\(\(string\) \$ctx\['current_content'\], 'post_content', \$editor_settings\);/);
|
|
});
|
|
|
|
test('front submit uses the registered local jQuery runtime', () => {
|
|
const source = read('src/Core/ScriptsPart1b.php');
|
|
|
|
assert.match(source, /wp_register_script\('jquery', \$base_uri \. '\/assets\/js\/runtime\/libs\/jquery\.min\.js', \[\], '1\.9\.1', false\)/);
|
|
assert.doesNotMatch(source, /jquery-migrate/);
|
|
|
|
const page = read('templates/pages/page-submit.php');
|
|
assert.match(page, /\['loader_js', 'aksrt-front-submit-pay-download'\]/);
|
|
});
|
|
|
|
test('legacy runtime modules use jQuery explicitly without a dollar alias', () => {
|
|
const modules = [
|
|
'main',
|
|
'captcha',
|
|
'comment',
|
|
'input-expand',
|
|
'mini-touch',
|
|
'mini-upload',
|
|
'page-edit',
|
|
'page-navs',
|
|
'page-template',
|
|
'poster-share',
|
|
'section-navs',
|
|
'svg-icon',
|
|
'waterfall',
|
|
'weixin-share',
|
|
];
|
|
|
|
for (const module of modules) {
|
|
for (const suffix of ['.js', '.min.js']) {
|
|
const relative = `assets/js/runtime/${module}${suffix}`;
|
|
const absolute = path.join(root, relative);
|
|
if (!fs.existsSync(absolute) || fs.statSync(absolute).size === 0) continue;
|
|
const source = fs.readFileSync(absolute, 'utf8');
|
|
assert.doesNotMatch(source, /(^|[^\w$])\$(?:\(|\.)/, `${relative} must use jQuery explicitly`);
|
|
assert.doesNotMatch(source, /(?:window\.)?\$\s*=/, `${relative} must not create a dollar alias`);
|
|
}
|
|
}
|
|
});
|
|
|
|
test('theme runtime never changes native listener passivity for third-party editors', () => {
|
|
const scripts = read('src/Core/Scripts.php');
|
|
const scriptsPart2 = read('src/Core/ScriptsPart2.php');
|
|
const buildTool = read('tools/build-public-assets.mjs');
|
|
const publicRuntime = read('assets/js/runtime/main.min.js');
|
|
|
|
assert.doesNotMatch(scripts, /enqueue_passive_polyfill|aksrt-passive-events/);
|
|
assert.doesNotMatch(scriptsPart2, /enqueue_passive_polyfill|aksrt-passive-events/);
|
|
assert.doesNotMatch(buildTool, /passive-events\.js/);
|
|
assert.doesNotMatch(publicRuntime, /EventTarget\.prototype\.addEventListener|__passiveSupported/);
|
|
assert.equal(fs.existsSync(path.join(root, 'assets/js/passive-events.js')), false);
|
|
});
|
|
|
|
test('public theme does not inject a global focus-visible ring', () => {
|
|
const globalFocusRule = /(^|})\s*:focus-visible\s*\{/m;
|
|
const reset = read('assets/css/core/reset.css');
|
|
const publicCss = read('assets/css/build/public.css');
|
|
const publicMinCss = read('assets/css/build/public.min.css');
|
|
|
|
assert.doesNotMatch(reset, globalFocusRule);
|
|
assert.doesNotMatch(publicCss, globalFocusRule);
|
|
assert.doesNotMatch(publicMinCss, globalFocusRule);
|
|
});
|
|
|
|
test('non-draft front-submit updates require one server captcha admission', () => {
|
|
const controller = read('src/Core/FrontSubmit.php');
|
|
const start = controller.indexOf('public function ajax_update_post(): void');
|
|
const end = controller.indexOf('\n public function ajax_delete_draft', start);
|
|
const body = controller.slice(start, end);
|
|
|
|
assert.match(body, /\$action = \(\(\$data\['status'\] \?\? ''\) === 'draft'\) \? 'posts_draft' : 'posts_save';/);
|
|
assert.match(body, /if \(\$action !== 'posts_draft'\) \{\s*\$this->verify_captcha\(\);\s*\}/);
|
|
assert.match(controller, /get_error_code\(\)/);
|
|
assert.match(controller, /get_error_message\(\)/);
|
|
});
|
|
|
|
test('front submit TinyMCE status bar shows one live character counter', () => {
|
|
const editor = read('assets/js/front-submit-editor.js');
|
|
const submitCss = read('assets/css/frontend/pages/submit.css');
|
|
const legacyPageEdit = read('assets/js/page-edit.js');
|
|
|
|
assert.match(editor, /querySelector\('\.mce-statusbar \.mce-container-body'\)/);
|
|
assert.match(editor, /data-submit-word-count/);
|
|
assert.match(editor, /textContent\s*=\s*'字数:'\s*\+\s*count/);
|
|
assert.match(editor, /editor\.on\('init SetContent input keyup change Undo Redo'/);
|
|
assert.match(editor, /replace\(\/\\s\+\/g, ''\)\.length/);
|
|
assert.match(submitCss, /\.newposts-editor \.aksrt-submit-word-count\s*{[^}]*float:\s*right;/);
|
|
assert.doesNotMatch(legacyPageEdit, /initWordCount|updateWordCount|aksrt-page-edit__word-count|字数:/);
|
|
});
|