Files
kate522andClaude Opus 5 35bb96e82f refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.

Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
  cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
  window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)

Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
  so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
  (dropped 3 stale entries, added the 17 missing ones)

Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
  get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
  when it is empty

Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.

Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-01 20:05:04 +08:00

203 lines
5.4 KiB
JavaScript

/**
* Jio Page Edit — 前台编辑增强
*
* 提供前台编辑页面的增强功能:
* - 自动保存草稿
* - 标签建议
* - 快捷键支持
*
* @package Jio
*/
(function () {
'use strict';
var DRAFT_KEY_PREFIX = 'jio_draft_';
/**
* 初始化页面编辑增强
*
* @param {Object} options 配置项
*/
function PageEdit(options) {
this.options = Object.assign({
formSelector: 'form[data-jio-edit]',
titleSelector: 'input[name="title"], input[name="topic_title"]',
contentSelector: 'textarea[name="content"], textarea[name="topic_content"]',
tagsSelector: 'input[name="tags"], input[name="topic_tags"]',
autoSaveInterval: 30000, // 30秒
draftKey: '',
}, options || {});
this.form = document.querySelector(this.options.formSelector);
if (!this.form) return;
this.autoSaveTimer = null;
this.lastSavedContent = '';
this.init();
}
PageEdit.prototype.init = function () {
var self = this;
this.titleInput = this.form.querySelector(this.options.titleSelector);
this.contentTextarea = this.form.querySelector(this.options.contentSelector);
this.tagsInput = this.form.querySelector(this.options.tagsSelector);
// 自动保存草稿
this.initAutoSave();
// 快捷键
this.initShortcuts();
// 标签输入增强
this.initTagInput();
// 表单提交时清除草稿
this.form.addEventListener('submit', function () {
self.clearDraft();
});
// 页面离开提醒
window.addEventListener('beforeunload', function (e) {
if (self.hasUnsavedChanges()) {
e.preventDefault();
e.returnValue = '您有未保存的修改,确定要离开吗?';
}
});
};
PageEdit.prototype.initAutoSave = function () {
var self = this;
if (!this.options.draftKey) {
// 从页面 URL 生成 draft key
this.options.draftKey = DRAFT_KEY_PREFIX + (window.location.pathname.replace(/\//g, '_') || 'page');
}
// 恢复草稿
this.restoreDraft();
// 定时自动保存
if (this.options.autoSaveInterval > 0) {
this.autoSaveTimer = setInterval(function () {
self.saveDraft();
}, this.options.autoSaveInterval);
}
};
PageEdit.prototype.saveDraft = function () {
if (!this.form) return;
var data = {};
if (this.titleInput) data.title = this.titleInput.value;
if (this.contentTextarea) data.content = this.contentTextarea.value;
if (this.tagsInput) data.tags = this.tagsInput.value;
var content = JSON.stringify(data);
if (content === this.lastSavedContent) return;
try {
localStorage.setItem(this.options.draftKey, content);
this.lastSavedContent = content;
// 显示保存提示
var toast = document.getElementById('jio-draft-toast');
if (!toast) {
toast = document.createElement('div');
toast.id = 'jio-draft-toast';
toast.className = 'jio-page-edit__toast';
document.body.appendChild(toast);
}
toast.textContent = '草稿已自动保存';
toast.classList.add('jio-page-edit__toast--visible');
setTimeout(function () {
toast.classList.remove('jio-page-edit__toast--visible');
}, 2000);
} catch (e) {
console.error('[Jio PageEdit] 保存草稿失败:', e);
}
};
PageEdit.prototype.restoreDraft = function () {
try {
var saved = localStorage.getItem(this.options.draftKey);
if (!saved) return;
var data = JSON.parse(saved);
var hasContent = false;
if (this.titleInput && data.title && !this.titleInput.value) {
this.titleInput.value = data.title;
hasContent = true;
}
if (this.contentTextarea && data.content && !this.contentTextarea.value) {
this.contentTextarea.value = data.content;
hasContent = true;
}
if (this.tagsInput && data.tags && !this.tagsInput.value) {
this.tagsInput.value = data.tags;
hasContent = true;
}
if (hasContent) {
this.lastSavedContent = saved;
}
} catch (e) {
console.error('[Jio PageEdit] 恢复草稿失败:', e);
}
};
PageEdit.prototype.clearDraft = function () {
try {
localStorage.removeItem(this.options.draftKey);
} catch (e) {}
};
PageEdit.prototype.hasUnsavedChanges = function () {
if (!this.form) return false;
var data = {};
if (this.titleInput) data.title = this.titleInput.value;
if (this.contentTextarea) data.content = this.contentTextarea.value;
if (this.tagsInput) data.tags = this.tagsInput.value;
return JSON.stringify(data) !== this.lastSavedContent;
};
PageEdit.prototype.initShortcuts = function () {
var self = this;
this.form.addEventListener('keydown', function (e) {
// Ctrl+S / Cmd+S 保存草稿
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
e.preventDefault();
self.saveDraft();
}
});
};
PageEdit.prototype.initTagInput = function () {
if (!this.tagsInput) return;
// 回车键添加标签
this.tagsInput.addEventListener('keydown', function (e) {
if (e.key === 'Enter') {
e.preventDefault();
}
});
};
// 自动初始化
function autoInit() {
var form = document.querySelector('form[data-jio-edit]');
if (form) {
new PageEdit();
}
}
jQuery(document).off('auto_fun.jio-page-edit').on('auto_fun.jio-page-edit', autoInit);
window.JioPageEdit = PageEdit;
})();