feat: 添加对 Ace 编辑器的支持和样式优化

This commit is contained in:
2026-04-11 19:43:30 +08:00
parent 7bae6d487d
commit 5a39432029
3 changed files with 198 additions and 116 deletions

View File

@@ -13,6 +13,7 @@
var DEFAULT_CDN = global.HUSTOJ_VDITOR_CDN || getLocalCdnBase();
global.HUSTOJ_VDITOR_CDN = DEFAULT_CDN;
var assetsPromise = null;
var aceAssetsPromise = null;
var styleInjected = false;
function getLocalCdnBase() {
@@ -25,6 +26,16 @@
return scriptSrc.replace(/\/vditor-adapter\.js(?:[?#].*)?$/, '/vditor');
}
function getLocalAceBase() {
var scriptSrc = currentScriptRef && currentScriptRef.src;
if (!scriptSrc) {
return 'ace';
}
return scriptSrc.replace(/\/include\/vditor-adapter\.js(?:[?#].*)?$/, '/ace');
}
function injectAdapterStyle() {
var style;
@@ -39,6 +50,14 @@
'.hustoj-vditor-hidden{display:none !important;}',
'.hustoj-vditor-wrapper{width:100%;margin:0 0 12px;}',
'.hustoj-vditor-code{--hustoj-vditor-font-size:18px;text-align:left;}',
'.hustoj-vditor-code.ace_editor{position:relative;border:1px solid #d4d4d5;border-radius:6px;line-height:1.5;}',
'.hustoj-vditor-code .ace_scroller,',
'.hustoj-vditor-code .ace_gutter,',
'.hustoj-vditor-code .ace_content{font-family:Consolas,Monaco,"Courier New",monospace !important;font-size:var(--hustoj-vditor-font-size) !important;line-height:1.5 !important;}',
'.hustoj-vditor-code .ace_gutter{background:#f8f8f8;color:#8a8a8a;}',
'.hustoj-vditor-dark.ace_editor{background:#272822;border-color:#4a4a4a;}',
'.hustoj-vditor-dark .ace_gutter{background:#2f3129;color:#bcbcbc;}',
'.hustoj-vditor-dark .ace_print-margin{background:#3a3d34;}',
'.hustoj-vditor-preview{--hustoj-diagram-font-family:"Microsoft YaHei","PingFang SC","Hiragino Sans GB","Noto Sans CJK SC","Source Han Sans SC","WenQuanYi Micro Hei",Arial,sans-serif;--hustoj-diagram-font-size:14px;}',
'.hustoj-vditor-code .vditor-toolbar{display:none !important;}',
'.hustoj-vditor-code .vditor-reset,',
@@ -147,6 +166,56 @@
return assetsPromise;
}
function ensureAceAssets(options) {
var aceBase = (options && options.aceBase) || getLocalAceBase();
injectAdapterStyle();
if (global.ace) {
if (global.ace.config && typeof global.ace.config.set === 'function') {
global.ace.config.set('basePath', aceBase);
}
return Promise.resolve(global.ace);
}
if (aceAssetsPromise) {
return aceAssetsPromise;
}
aceAssetsPromise = new Promise(function (resolve, reject) {
var aceScriptSrc = aceBase + '/ace.js';
var existing = documentRef.querySelector('script[data-hustoj-ace-js="' + aceScriptSrc + '"]');
var finish = function () {
if (global.ace && global.ace.config && typeof global.ace.config.set === 'function') {
global.ace.config.set('basePath', aceBase);
}
resolve(global.ace);
};
if (existing) {
if (global.ace) {
finish();
} else {
existing.addEventListener('load', finish, { once: true });
existing.addEventListener('error', reject, { once: true });
}
return;
}
var script = documentRef.createElement('script');
script.src = aceScriptSrc;
script.async = true;
script.setAttribute('data-hustoj-ace-js', aceScriptSrc);
script.onload = finish;
script.onerror = function () {
reject(new Error('Failed to load ' + aceScriptSrc));
};
documentRef.head.appendChild(script);
});
return aceAssetsPromise;
}
function resolveElement(target) {
if (!target) {
return null;
@@ -621,15 +690,16 @@
}
function createCodeEditor(options) {
return ensureAssets(options).then(function () {
return ensureAceAssets(options).then(function () {
var container = resolveElement(options.container);
var hiddenField = resolveElement(options.hiddenField);
var sourceField = resolveElement(options.sourceField);
var initialValue = options.initialValue;
var adapter = null;
var vditor = null;
var aceEditor = null;
var session = null;
var state;
var aceBase = (options && options.aceBase) || getLocalAceBase();
if (!container) {
throw new Error('Vditor code editor container not found');
@@ -649,25 +719,33 @@
container.classList.add('hustoj-vditor-code');
container.style.setProperty('--hustoj-vditor-font-size', state.fontSize + 'px');
container.classList.toggle('hustoj-vditor-dark', aceThemeToVditorTheme(state.theme) === 'dark');
container.style.width = options.width || '100%';
if (typeof options.height === 'string') {
container.style.height = options.height;
} else {
container.style.height = (options.height || computeHeight(container, 420)) + 'px';
}
if (sourceField && sourceField !== container) {
sourceField.classList.add('hustoj-vditor-hidden');
}
container.textContent = '';
container.textContent = initialValue || '';
function applyTheme() {
var editorTheme = aceThemeToVditorTheme(state.theme);
var contentTheme = aceThemeToContentTheme(state.theme);
container.classList.toggle('hustoj-vditor-dark', editorTheme === 'dark');
if (vditor && typeof vditor.setTheme === 'function') {
vditor.setTheme(editorTheme, contentTheme, 'github');
if (aceEditor) {
aceEditor.setTheme(state.theme);
}
}
function applyFontSize() {
container.style.setProperty('--hustoj-vditor-font-size', state.fontSize + 'px');
if (aceEditor) {
aceEditor.setFontSize(state.fontSize);
}
}
function syncSourceValue(value) {
@@ -685,6 +763,9 @@
session = {
setMode: function (modeName) {
state.mode = normalizeMode(modeName);
if (aceEditor) {
aceEditor.session.setMode(modeName || 'text');
}
},
getValue: function () {
return adapter.getValue();
@@ -695,55 +776,51 @@
};
return new Promise(function (resolve) {
vditor = new global.Vditor(container, {
cdn: options.cdn || DEFAULT_CDN,
cache: { enable: false },
mode: options.editorMode || 'sv',
lang: options.lang || 'zh_CN',
value: initialValue || '',
icon: options.icon || 'ant',
theme: aceThemeToVditorTheme(state.theme),
width: options.width || '100%',
minHeight: options.minHeight || computeHeight(container, 420),
height: options.height || computeHeight(container, 420),
toolbar: options.toolbar || [],
toolbarConfig: options.toolbarConfig || { hide: true, pin: false },
resize: options.resize || { enable: false },
outline: options.outline || { enable: false },
counter: options.counter || { enable: false },
preview: options.preview || {
mode: 'editor',
delay: 0,
actions: [],
markdown: {
sanitize: false,
autoSpace: false,
codeBlockPreview: false,
mathBlockPreview: false,
fixTermTypo: false
if (global.ace && global.ace.config && typeof global.ace.config.set === 'function') {
global.ace.config.set('basePath', aceBase);
}
},
input: function (value) {
syncSourceValue(value);
},
blur: function (value) {
syncSourceValue(value);
},
after: function () {
aceEditor = global.ace.edit(container);
aceEditor.$blockScrolling = Infinity;
aceEditor.setValue(initialValue || '', -1);
aceEditor.session.setUseWorker(false);
aceEditor.session.setUseWrapMode(true);
aceEditor.renderer.setShowPrintMargin(false);
aceEditor.setHighlightActiveLine(true);
aceEditor.setOptions({
showFoldWidgets: false,
tabSize: 4,
useSoftTabs: true,
behavioursEnabled: false,
wrapBehavioursEnabled: false,
fontSize: state.fontSize
});
if (state.mode) {
aceEditor.session.setMode('ace/mode/' + state.mode);
}
aceEditor.session.on('change', function () {
syncSourceValue(aceEditor.getValue());
});
aceEditor.on('blur', function () {
syncSourceValue(aceEditor.getValue());
});
adapter = {
getValue: function () {
return vditor.getValue();
return aceEditor.getValue();
},
setValue: function (value) {
var nextValue = typeof value === 'undefined' ? '' : String(value);
vditor.setValue(nextValue, true);
aceEditor.setValue(nextValue, -1);
syncSourceValue(nextValue);
return nextValue;
},
getSession: function () {
return session;
return aceEditor.getSession();
},
session: session,
session: aceEditor.getSession(),
setTheme: function (themeName) {
state.theme = themeName || state.theme;
applyTheme();
@@ -761,13 +838,18 @@
if (typeof editorOptions.readOnly !== 'undefined') {
this.setReadOnly(editorOptions.readOnly);
}
aceEditor.setOptions(editorOptions);
},
setOption: function (name, value) {
if (name === 'wrap') {
state.wrap = value !== 'off';
aceEditor.session.setUseWrapMode(state.wrap);
return;
}
aceEditor.setOption(name, value);
},
resize: function () {
aceEditor.resize();
applyFontSize();
},
getFontSize: function () {
@@ -778,16 +860,12 @@
applyFontSize();
},
setReadOnly: function (readOnly) {
if (readOnly) {
vditor.disabled();
} else {
vditor.enable();
}
aceEditor.setReadOnly(!!readOnly);
},
focus: function () {
vditor.focus();
aceEditor.focus();
},
_vditor: vditor
_ace: aceEditor
};
applyTheme();
@@ -795,10 +873,8 @@
if (options.readOnly) {
adapter.setReadOnly(true);
}
syncSourceValue(vditor.getValue());
syncSourceValue(aceEditor.getValue());
resolve(adapter);
}
});
});
});
}

View File

@@ -2818,13 +2818,6 @@ var plantumlRenderAdapter = {
/* harmony import */ var _util_function__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(446);
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
var FLOWCHART_DIAGRAM_FONT_FAMILY = '"Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Source Han Sans SC", "WenQuanYi Micro Hei", Arial, sans-serif';
var FLOWCHART_DIAGRAM_OPTIONS = {
"font-family": FLOWCHART_DIAGRAM_FONT_FAMILY,
"font-size": 14,
"font-weight": "normal"
};
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
@@ -2994,6 +2987,11 @@ var codeRender = function (element, option) {
var flowchartRender = function (element, cdn) {
if (cdn === void 0) { cdn = _constants__WEBPACK_IMPORTED_MODULE_0__/* .Constants.CDN */ .g.CDN; }
var flowchartDiagramOptions = {
"font-family": '"Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", "Source Han Sans SC", "WenQuanYi Micro Hei", Arial, sans-serif',
"font-size": 14,
"font-weight": "normal"
};
var flowchartElements = _adapterRender__WEBPACK_IMPORTED_MODULE_1__.flowchartRenderAdapter.getElements(element);
if (flowchartElements.length === 0) {
return;
@@ -3005,7 +3003,7 @@ var flowchartRender = function (element, cdn) {
}
var flowchartObj = flowchart.parse(_adapterRender__WEBPACK_IMPORTED_MODULE_1__.flowchartRenderAdapter.getCode(item));
item.innerHTML = "";
flowchartObj.drawSVG(item, FLOWCHART_DIAGRAM_OPTIONS);
flowchartObj.drawSVG(item, flowchartDiagramOptions);
item.setAttribute("data-processed", "true");
});
});
@@ -3548,6 +3546,10 @@ var mermaidRender = function (element, cdn, theme) {
fontFamily: mermaidFontFamily,
fontSize: "14px",
startOnLoad: false,
themeVariables: {
fontFamily: mermaidFontFamily,
fontSize: "14px"
},
flowchart: {
htmlLabels: false,
useMaxWidth: !0

View File

@@ -23,6 +23,10 @@ export const mermaidRender = (element: HTMLElement, cdn = Constants.CDN, theme:
fontFamily: MERMAID_FONT_FAMILY,
fontSize: MERMAID_FONT_SIZE,
startOnLoad: false,
themeVariables: {
fontFamily: MERMAID_FONT_FAMILY,
fontSize: MERMAID_FONT_SIZE,
},
flowchart: {
htmlLabels: false,
useMaxWidth: !0