初始化模版工程

This commit is contained in:
Cloud Bot
2026-03-20 07:33:46 +00:00
commit 23717e0ecd
386 changed files with 51675 additions and 0 deletions

View File

@@ -0,0 +1,281 @@
/**
* Style Manager
* 样式管理器,处理元素样式的应用和获取
*/
import { type HTMLEditor } from '../editor';
import type { ElementStyles } from '../../types';
import { createStyleChangeCommand, createElementTagChangeCommand, createContentChangeCommand } from '../historyManager/commands';
export class StyleManager {
private editor: HTMLEditor;
constructor(editor: HTMLEditor) {
this.editor = editor;
}
/**
* 应用样式并记录历史
*/
private applyStyleWithHistory(element: HTMLElement, property: string, value: string): void {
const oldValue = element.style.getPropertyValue(property) || window.getComputedStyle(element).getPropertyValue(property);
// 创建命令并执行
if (this.editor.historyManager) {
const command = createStyleChangeCommand(element, property, oldValue, value);
command.execute();
this.editor.historyManager.push(command);
} else {
// 如果没有历史管理器,直接应用样式
element.style.setProperty(property, value);
}
}
// 字体相关方法
changeFont(element: HTMLElement | null, fontFamily: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'font-family', fontFamily);
this.editor.emit('styleChange', element, { fontFamily });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changeFontSize(element: HTMLElement | null, fontSize: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'font-size', fontSize);
this.editor.emit('styleChange', element, { fontSize });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changeFontWeight(element: HTMLElement | null, fontWeight: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'font-weight', fontWeight);
this.editor.emit('styleChange', element, { fontWeight });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changeFontStyle(element: HTMLElement | null, fontStyle: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'font-style', fontStyle);
this.editor.emit('styleChange', element, { fontStyle });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changeTextDecoration(element: HTMLElement | null, textDecoration: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'text-decoration', textDecoration);
this.editor.emit('styleChange', element, { textDecoration });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changeTextAlign(element: HTMLElement | null, textAlign: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'text-align', textAlign);
this.editor.emit('styleChange', element, { textAlign });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
// 边距相关方法
changeMargin(element: HTMLElement | null, margin: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'margin', margin);
this.editor.emit('styleChange', element, { margin });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changePadding(element: HTMLElement | null, padding: string,triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'padding', padding);
this.editor.emit('styleChange', element, { padding });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
// 颜色相关方法
changeColor(element: HTMLElement | null, color: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'color', color);
this.editor.emit('styleChange', element, { color });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changeBackground(element: HTMLElement | null, backgroundColor: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
// 使用批量操作记录 background 和 backgroundColor
// this.editor.beginBatch();
this.applyStyleWithHistory(element, 'background', backgroundColor);
// this.editor.endBatch();
this.editor.emit('styleChange', element, { backgroundColor, background: backgroundColor });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
// 边框相关方法
changeBorder(element: HTMLElement | null, border: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'border', border);
this.editor.emit('styleChange', element, { border });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
changeBorderRadius(element: HTMLElement | null, borderRadius: string, triggerContentChange = true): boolean {
if (!element) element = this.editor.selectedElement;
if (!element) return false;
this.applyStyleWithHistory(element, 'border-radius', borderRadius);
this.editor.emit('styleChange', element, { borderRadius });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
applyTextStyle(property: string, value: string, triggerContentChange = true): boolean {
if (!this.editor.selectedElement) return false;
this.applyStyleWithHistory(this.editor.selectedElement, property, value);
this.editor.emit('styleChange', this.editor.selectedElement, { [property]: value });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
applyBlockStyle(property: string, value: string, triggerContentChange = true): boolean {
if (!this.editor.selectedElement) return false;
const el = this.editor.selectedElement;
// 兼容传入 'background-color' 字符串
const prop = property === 'background-color' ? 'background-color' : property;
// 当设置背景相关属性时,同时更新 background 与 backgroundColor
if (prop === 'background' || prop === 'background-color') {
this.editor.beginBatch();
this.applyStyleWithHistory(el, 'background-color', value);
this.applyStyleWithHistory(el, 'background', value);
this.editor.endBatch();
this.editor.emit('styleChange', el, { backgroundColor: value, background: value });
return true;
}
this.applyStyleWithHistory(el, prop, value);
this.editor.emit('styleChange', el, { [prop]: value });
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return true;
}
getComputedStyle(element: HTMLElement, property: string): string {
return window.getComputedStyle(element)[property as any];
}
getElementStyles(element: HTMLElement): ElementStyles {
const computedStyle = window.getComputedStyle(element);
return {
fontSize: computedStyle.fontSize,
color: computedStyle.color,
fontWeight: computedStyle.fontWeight,
backgroundColor: computedStyle.backgroundColor,
borderWidth: computedStyle.borderWidth,
padding: computedStyle.padding,
margin: computedStyle.margin,
borderRadius: computedStyle.borderRadius
};
}
changeElementTag(element: HTMLElement, newTag: string, triggerContentChange = true): HTMLElement | null {
if (!element || !element.parentNode || !newTag) {
return null;
}
const command = createElementTagChangeCommand(element, newTag);
command.execute();
const newElement = (command as any).newElement as HTMLElement;
if (!newElement) return null;
if (this.editor.historyManager) {
this.editor.historyManager.push(command);
}
this.editor.selectElement(newElement);
this.editor.emit('contentChange');
if (triggerContentChange) {
this.editor.emit('contentChange');
}
return newElement;
}
rgbToHex(rgb: string): string {
if (!rgb || rgb === 'rgba(0, 0, 0, 0)' || rgb === 'transparent') {
return '#ffffff';
}
const result = rgb.match(/\d+/g);
if (!result) return '#000000';
const r = parseInt(result[0]);
const g = parseInt(result[1]);
const b = parseInt(result[2]);
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
// =============================
// 选区样式操作全局contenteditable模式
// =============================
applySelectionBold(): boolean { return this.editor.globalEditable?.applySelectionBold() ?? false; }
applySelectionItalic(): boolean { return this.editor.globalEditable?.applySelectionItalic() ?? false; }
applySelectionUnderline(): boolean { return this.editor.globalEditable?.applySelectionUnderline() ?? false; }
applySelectionStrikeThrough(): boolean { return this.editor.globalEditable?.applySelectionStrikeThrough() ?? false; }
applySelectionFontSize(px: string): boolean { return this.editor.globalEditable?.applySelectionFontSize(px) ?? false; }
applySelectionFontFamily(name: string): boolean { return this.editor.globalEditable?.applySelectionFontFamily(name) ?? false; }
applySelectionColor(color: string): boolean { return this.editor.globalEditable?.applySelectionColor(color) ?? false; }
applySelectionBackground(color: string): boolean { return this.editor.globalEditable?.applySelectionBackground(color) ?? false; }
applySelectionAlign(align: 'left' | 'center' | 'right'): boolean { return this.editor.globalEditable?.applySelectionAlign(align as any) ?? false; }
}
export default StyleManager;