The post editor's download row only exposed address / button text / remark, leaving copy_key, copy_val and class as hidden inputs with no UI, so the reference copy area, custom button icon, text and color were unreachable. The submission popup already emitted those keys, which made the two write paths diverge from anything the editor could produce. Expose the full reference field set (地址/备注/复制名称/复制内容/图标/文案/ 颜色) as an accordion card with drag reordering, add the one genuinely new `icon` key through aksrt_sanitize_icon_value(), and teach both frontend download renderers to consume the fields they previously ignored. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
272 lines
14 KiB
JavaScript
272 lines
14 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('block and classic editors share the reference article extension fields', () => {
|
|
const meta = read('src/Core/PostMetaBox.php');
|
|
const fields = [
|
|
'thumbnail_url',
|
|
'cover_image',
|
|
'featured_slide',
|
|
'featured_video',
|
|
'featured_video_title',
|
|
'featured_video_episode',
|
|
'subtitle',
|
|
'views',
|
|
'like',
|
|
'show_layout',
|
|
'no_article-navs',
|
|
'article_maxheight_xz',
|
|
];
|
|
|
|
assert.ok(meta.includes("add_meta_box('post_main', __('文章扩展'"));
|
|
assert.match(meta, /\['post\.php', 'post-new\.php'\]/);
|
|
assert.match(meta, /wp_enqueue_media\(\)/);
|
|
fields.forEach((field) => assert.match(meta, new RegExp(field.replace('-', '\\-'))));
|
|
assert.doesNotMatch(meta, /custom_excerpt|header_image_mode|show_reading_progress|enable_lightbox|enable_pdf|copyright_text|is_featured/);
|
|
});
|
|
|
|
test('front submit follows the reference newposts shell and cards', () => {
|
|
const page = read('templates/pages/page-submit.php');
|
|
const main = read('templates/parts/submit/editor-main.php');
|
|
const terms = read('templates/parts/submit/sidebar-terms.php');
|
|
const pay = read('templates/parts/submit/sidebar-pay.php');
|
|
const submit = read('templates/parts/submit/sidebar-submit.php');
|
|
const submitJs = read('assets/js/front-submit.js');
|
|
const submitCss = read('assets/css/frontend/pages/submit.css');
|
|
const publicCss = read('assets/css/build/public.min.css');
|
|
const mainCss = read('assets/css/main.css');
|
|
const layout = read('inc/helpers/template-tags/site-layout.php');
|
|
const mobileSubmitCss = submitCss.slice(submitCss.indexOf('@media (max-width: 991px)'));
|
|
|
|
assert.match(page, /content-wrap newposts-wrap/);
|
|
assert.match(page, /class="content-layout"/);
|
|
assert.match(page, /<\/div>\s*<\/div>\s*<div class="sidebar show-sidebar">/);
|
|
assert.match(layout, /if \(is_page_template\('templates\/pages\/page-submit\.php'\)\) \{\s*return true;/);
|
|
assert.equal((page.match(/class="sidebar show-sidebar"/g) || []).length, 1);
|
|
assert.match(page, /'aksrt-submit',[\s\S]*?\['aksrt-public'\]/);
|
|
assert.match(main, /zib-widget full-widget-sm editor-main-box/);
|
|
assert.match(main, /relative newposts-title/);
|
|
assert.match(terms, /newpost-cat-drop drop-select dropdown dependency-box/);
|
|
assert.match(terms, /data-toggle-class="open" data-target="\.newpost-cat-drop"/);
|
|
assert.match(terms, /aksrt_submit_render_term_checks\(\$ctx\['categories'\], array_map\('intval', \$ctx\['current_cats'\]\), 'category'\)/);
|
|
assert.doesNotMatch(terms, /aria-expanded=/);
|
|
assert.doesNotMatch(submitJs, /bindDropSelect|term-select-box \[data-toggle-class/);
|
|
assert.doesNotMatch(submitCss, /\.term-select-box \.dropdown-menu|\.term-select-box \.drop-select\s*{/);
|
|
assert.match(mainCss, /\.drop-select \.dropdown-menu\s*{[^}]*box-shadow:\s*0 0 0 8000px/);
|
|
assert.match(mainCss, /\.open > \.dropdown-menu\s*{[^}]*visibility:\s*unset/);
|
|
assert.match(pay, /zib-widget dependency-box mb10-sm newpost-pay-box/);
|
|
assert.match(pay, /pay-dawnload-edit/);
|
|
assert.match(submit, /separator muted-3-color theme-box/);
|
|
assert.match(submit, /new-posts-submit/);
|
|
assert.equal((submit.match(/fa-fw/g) || []).length, 2);
|
|
assert.doesNotMatch(submit, /fa-(?:dot-circle|check-square) mr6/);
|
|
assert.match(publicCss, /\.but-average\s*>\s*\.but\s*{[^}]*flex:\s*auto/);
|
|
assert.match(submitCss, /#aksrt-submit-form \.new-posts-submit\s*{[^}]*white-space:\s*nowrap;/);
|
|
assert.match(submitCss, /#aksrt-submit-form \.but-average > \.new-posts-submit\s*{[^}]*min-width:\s*0;[^}]*flex:\s*1 1 50%;/);
|
|
assert.match(mobileSubmitCss, /body \.newposts-wrap\s*{[^}]*float:\s*none;/);
|
|
assert.match(mobileSubmitCss, /body \.sidebar\.show-sidebar\s*{[^}]*display:\s*unset;[^}]*width:\s*100%;[^}]*margin-left:\s*0;/);
|
|
assert.doesNotMatch(submitCss, /\.newposts-wrap\s*>\s*\.(?:content-layout|sidebar)/);
|
|
assert.doesNotMatch(submitCss, /\.newposts-wrap \.new-posts-submit/);
|
|
// The form wraps both float columns; flow-root is its only layout job.
|
|
assert.match(submitCss, /#aksrt-submit-form\s*{[^}]*display:\s*flow-root;/);
|
|
assert.doesNotMatch(submitCss, /#aksrt-submit-form\s*{[^}]*display:\s*(?:grid|flex);/);
|
|
// Submit chrome gating lives in footer.php; no dead filter/body-class duplicates.
|
|
assert.doesNotMatch(read('src/Core/FrontSubmit.php'), /aksrt_floating_buttons_enabled|aksrt_footer_tabbar_enabled|aksrt-hide-float|aksrt-hide-tabbar|disable_chrome_on_submit/);
|
|
});
|
|
|
|
test('front submit paid resources use the reference modal editor and compact list', () => {
|
|
const page = read('templates/pages/page-submit.php');
|
|
const pay = read('templates/parts/submit/sidebar-pay.php');
|
|
const submit = read('assets/js/front-submit.js');
|
|
const downloads = read('assets/js/front-submit-pay-download.js');
|
|
const model = read('src/Core/DomainModel.php');
|
|
|
|
assert.match(page, /aksrt-front-submit-pay-download/);
|
|
assert.match(submit, /aksrtSubmitPayDownloads\.init/);
|
|
assert.match(pay, /data-pay-download-add/);
|
|
assert.match(pay, /data-pay-download-edit/);
|
|
assert.match(pay, /data-pay-download-remove/);
|
|
assert.match(pay, /class="hidden-input"/);
|
|
assert.doesNotMatch(pay, /data-pay-download-upload|data-pay-download-tpl/);
|
|
|
|
['url', 'attachment_id', 'extract_code', 'copy_key', 'copy_val', 'label', 'class'].forEach((field) => {
|
|
assert.match(downloads, new RegExp(`['"]${field}['"]`));
|
|
assert.match(model, new RegExp(`['"]${field}['"]`));
|
|
});
|
|
assert.match(downloads, /pay-dawnload-edit-modal/);
|
|
assert.match(downloads, /data-pay-resource-upload/);
|
|
assert.match(downloads, /data-pay-resource-classes/);
|
|
assert.match(downloads, /提取码\|密码/);
|
|
assert.doesNotMatch(downloads, /shop|forum|bbs_/i);
|
|
});
|
|
|
|
test('the post editor resource row mirrors the reference seven fields with icon support', () => {
|
|
const meta = read('src/Core/ResourceMetaBox.php');
|
|
const model = read('src/Core/DomainModel.php');
|
|
const setup = read('src/Core/Setup.php');
|
|
|
|
['下载地址', '资源备注', '复制的名称', '复制的内容', '自定义按钮图标', '自定义按钮文案', '自定义按钮颜色'].forEach((label) => {
|
|
assert.ok(meta.includes(label), `missing label: ${label}`);
|
|
});
|
|
|
|
// copy_key / copy_val / class must be real inputs, not hidden-only leftovers.
|
|
['url', 'extract_code', 'copy_key', 'copy_val', 'icon', 'label', 'class'].forEach((field) => {
|
|
assert.match(meta, new RegExp(`\\[${field}\\]`));
|
|
assert.match(model, new RegExp(`'${field}'`));
|
|
});
|
|
// copy_key / copy_val must be real visible inputs, not hidden-only leftovers.
|
|
// The color field legitimately keeps a hidden store behind the swatch buttons.
|
|
assert.doesNotMatch(meta, /type="hidden"[^>]*name="[^"]*\[(?:copy_key|copy_val)\]"/);
|
|
|
|
// Accordion + drag reorder affordances.
|
|
assert.match(meta, /data-group-toggle/);
|
|
assert.match(meta, /data-group-drag/);
|
|
assert.match(meta, /aksrt-icon-picker_assets\(|aksrt_icon_picker_field\(/);
|
|
// The swatch palette and the sanitizer share one class whitelist.
|
|
assert.match(meta, /DomainModel::DOWNLOAD_BUTTON_CLASSES/);
|
|
assert.match(model, /const DOWNLOAD_BUTTON_CLASSES/);
|
|
|
|
const js = read('assets/js/admin-pay-meta-box.js');
|
|
assert.match(js, /dragstart/);
|
|
assert.match(js, /dragover/);
|
|
assert.match(js, /reindexRows/);
|
|
|
|
// Reindexing rewrites the row index for every field and is scoped to its own
|
|
// group, so dragging a download row can never renumber attributes/episodes.
|
|
const reindex = (group, name, index) =>
|
|
name.replace(new RegExp(`aksrt_pay\\[${group}\\]\\[\\d+\\]`), `aksrt_pay[${group}][${index}]`);
|
|
['url', 'label', 'extract_code', 'copy_key', 'copy_val', 'icon', 'class'].forEach((field) => {
|
|
assert.equal(reindex('downloads', `aksrt_pay[downloads][0][${field}]`, 3), `aksrt_pay[downloads][3][${field}]`);
|
|
});
|
|
assert.equal(reindex('downloads', 'aksrt_pay[downloads][5][url]', 1), 'aksrt_pay[downloads][1][url]');
|
|
assert.equal(reindex('downloads', 'aksrt_pay[attributes][0][key]', 9), 'aksrt_pay[attributes][0][key]');
|
|
assert.equal(reindex('downloads', 'aksrt_pay[video_episode][1][title]', 9), 'aksrt_pay[video_episode][1][title]');
|
|
|
|
assert.match(setup, /'icon' => \['type' => 'string'\]/);
|
|
});
|
|
|
|
test('front submit paid-content prices and switch use the reference alignment rules', () => {
|
|
const pay = read('templates/parts/submit/sidebar-pay.php');
|
|
const submitCss = read('assets/css/frontend/pages/submit.css');
|
|
|
|
assert.match(pay, /<div class="form-switch flex0"><\/div>/);
|
|
assert.match(submitCss, /\.newpost-pay-price \.line-form-input\s*{[^}]*text-align:\s*right;/);
|
|
assert.doesNotMatch(submitCss, /\.newpost-pay-price \.line-form-input\s*{[^}]*width:\s*130px;/);
|
|
assert.doesNotMatch(submitCss, /\.newpost-pay-box \.form-switch(?:::after)?\s*{/);
|
|
});
|
|
|
|
test('front submit image and visibility actions live in the TinyMCE toolbar', () => {
|
|
const main = read('templates/parts/submit/editor-main.php');
|
|
const page = read('templates/pages/page-submit.php');
|
|
const submit = read('assets/js/front-submit.js');
|
|
const editor = read('assets/js/front-submit-editor.js');
|
|
|
|
assert.match(main, /\$toolbar1\[\]\s*=\s*'aksrt_image'/);
|
|
assert.match(main, /\$toolbar1\[\]\s*=\s*'aksrt_hide'/);
|
|
assert.match(main, /mce_external_plugins/);
|
|
assert.match(main, /aksrt_editor_tools/);
|
|
assert.match(editor, /PluginManager\.add\('aksrt_editor_tools'/);
|
|
assert.match(editor, /addButton\('aksrt_image'/);
|
|
assert.match(editor, /addButton\('aksrt_hide'/);
|
|
assert.match(editor, /type:\s*'menubutton'/);
|
|
assert.match(editor, /data-editor-media-tab="upload"/);
|
|
assert.match(editor, /data-editor-media-tab="external"/);
|
|
assert.match(editor, /class="aksrt-editor-media__dialog" tabindex="-1"/);
|
|
assert.match(editor, /querySelector\('\.aksrt-editor-media__dialog'\)/);
|
|
assert.doesNotMatch(editor, /focusTarget\s*=\s*root\.querySelector\('\[data-editor-media-tab\]\.is-active'\)/);
|
|
assert.match(editor, /\(cfg\.uploads \|\| \{\}\)\.image/);
|
|
assert.match(page, /'canUploadImage'\s*=>\s*!empty\(\$ctx\['can_upload_img'\]\)/);
|
|
assert.doesNotMatch(main, /newposts-editor-tools|data-insert-shortcode|data-insert-upload-image/);
|
|
assert.doesNotMatch(submit, /bindShortcodes|data-insert-shortcode|data-insert-upload-image/);
|
|
assert.doesNotMatch(editor, /hidecontent|shop|forum|bbs_/i);
|
|
});
|
|
|
|
test('front submit exposes the complete reference media and formatting toolset', () => {
|
|
const main = read('templates/parts/submit/editor-main.php');
|
|
const page = read('templates/pages/page-submit.php');
|
|
const editor = read('assets/js/front-submit-editor.js');
|
|
const editorCss = read('assets/css/frontend/pages/submit-editor.css');
|
|
const submit = read('src/Core/FrontSubmit.php');
|
|
|
|
['aksrt_video', 'aksrt_file', 'aksrt_quote', 'aksrt_precode'].forEach((button) => {
|
|
assert.match(main, new RegExp(`['"]${button}['"]`));
|
|
assert.match(editor, new RegExp(`addButton\\(['"]${button}['"]`));
|
|
});
|
|
assert.doesNotMatch(main, /array_merge\(\$toolbar1, \['blockquote'/);
|
|
assert.match(main, /\['aksrt_quote', 'aksrt_precode', 'fullscreen', 'wp_adv'\]/);
|
|
assert.match(main, /toolbar2[\s\S]*forecolor/);
|
|
assert.match(main, /colorpicker,textcolor/);
|
|
|
|
assert.match(page, /'canUploadVideo'\s*=>\s*!empty\(\$ctx\['can_upload_video'\]\)/);
|
|
assert.match(page, /'canEmbedVideo'\s*=>\s*!empty\(\$ctx\['can_iframe'\]\)/);
|
|
assert.match(page, /'canUploadFile'\s*=>\s*!empty\(\$ctx\['can_upload_file'\]\)/);
|
|
assert.match(page, /'video'\s*=>\s*!empty\(\$ctx\['can_upload_video'\]\)/);
|
|
assert.match(submit, /\(\?P<kind>image\|video\|resource\)/);
|
|
assert.match(submit, /new_post_upload_video/);
|
|
|
|
assert.match(editor, /data-editor-media-tab="upload"/);
|
|
assert.match(editor, /data-editor-media-tab="external"/);
|
|
assert.match(editor, /data-editor-media-tab="embed"/);
|
|
assert.match(editor, /new-dplayer post-dplayer dplayer/);
|
|
assert.match(editor, /file-download-box/);
|
|
assert.match(editor, /wp-block-embed is-type-video/);
|
|
assert.match(editor, /data-enlighter-language/);
|
|
assert.match(editor, /data-enlighter-theme/);
|
|
assert.match(editor, /enlighter-pre/);
|
|
assert.match(editor, /qe_wzk_c-red/);
|
|
assert.match(editor, /qe_wzk_lan/);
|
|
assert.match(editor, /qe_wzk_lv/);
|
|
assert.match(editorCss, /\.quote_q/);
|
|
assert.match(editorCss, /\.quote_q \[contenteditable="true"\][\s\S]*?box-shadow:\s*none/);
|
|
assert.match(editorCss, /\.file-download-box/);
|
|
assert.match(editorCss, /\.enlighter-pre/);
|
|
assert.doesNotMatch(editor, /shop|forum|bbs_/i);
|
|
});
|
|
|
|
test('article paid-content metabox follows the reference field set without shop enhancements', () => {
|
|
const meta = read('src/Core/ResourceMetaBox.php');
|
|
const fields = [
|
|
'pay_type',
|
|
'pay_limit',
|
|
'pay_modo',
|
|
'order_expired_s',
|
|
'points_price',
|
|
'original_price',
|
|
'promotion_tag',
|
|
'gallery_show',
|
|
'video_episode',
|
|
'video_scale_height',
|
|
'downloads',
|
|
'attributes',
|
|
'pay_doc',
|
|
'pay_details',
|
|
'pay_extra_hide',
|
|
];
|
|
|
|
assert.match(meta, /add_meta_box\('aksrt_pay_meta', __\('付费功能'/);
|
|
fields.forEach((field) => assert.match(meta, new RegExp(field)));
|
|
assert.doesNotMatch(meta, /aksrt_pay_(?:stock|purchase_limit|card_keys|free_preview|require_login|require_captcha)/);
|
|
assert.doesNotMatch(meta, /电商增强|parse_json_array/);
|
|
});
|
|
|
|
test('ordinary article editor chain does not import shop or forum routes', () => {
|
|
const files = [
|
|
'src/Core/PostMetaBox.php',
|
|
'src/Core/FrontSubmit.php',
|
|
'src/Core/FrontSubmitSave.php',
|
|
'src/Core/FrontSubmitPay.php',
|
|
'src/Core/FrontSubmitFeatured.php',
|
|
'templates/pages/page-submit.php',
|
|
'templates/parts/submit/sidebar-pay.php',
|
|
];
|
|
const source = files.map(read).join('\n');
|
|
|
|
assert.doesNotMatch(source, /shop_product|forum_post|bbs_/i);
|
|
assert.doesNotMatch(source, /aksrtpay_s|featured_payload|vip_1_(?:price|points)|vip_2_(?:price|points)/);
|
|
});
|