refactor(editor): merge implementation of createTemplateJob (#11474)

This commit is contained in:
Saul-Mirone
2025-04-05 12:59:48 +00:00
parent aed7f40568
commit 41499c1cd6
8 changed files with 77 additions and 98 deletions

View File

@@ -23,6 +23,7 @@ import { styleMap } from 'lit/directives/style-map.js';
import { unsafeSVG } from 'lit/directives/unsafe-svg.js'; import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
import { EdgelessRootService } from '../../../edgeless-root-service.js'; import { EdgelessRootService } from '../../../edgeless-root-service.js';
import { createTemplateJob } from '../../../services/template.js';
import { builtInTemplates } from './builtin-templates.js'; import { builtInTemplates } from './builtin-templates.js';
import { defaultPreview, Triangle } from './cards.js'; import { defaultPreview, Triangle } from './cards.js';
import type { Template } from './template-type.js'; import type { Template } from './template-type.js';
@@ -287,7 +288,11 @@ export class EdgelessTemplatePanel extends WithDisposable(LitElement) {
x: bound.x + bound.w / 2, x: bound.x + bound.w / 2,
y: bound.y + bound.h / 2, y: bound.y + bound.h / 2,
}; };
const templateJob = this.service.createTemplateJob(template.type, center); const templateJob = createTemplateJob(
this.edgeless.std,
template.type,
center
);
try { try {
const { assets } = template; const { assets } = template;

View File

@@ -11,7 +11,6 @@ import {
RootBlockSchema, RootBlockSchema,
} from '@blocksuite/affine-model'; } from '@blocksuite/affine-model';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions'; import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { Bound, getCommonBound } from '@blocksuite/global/gfx';
import type { BlockStdScope } from '@blocksuite/std'; import type { BlockStdScope } from '@blocksuite/std';
import type { import type {
GfxController, GfxController,
@@ -33,12 +32,6 @@ import clamp from 'lodash-es/clamp';
import { RootService } from '../root-service.js'; import { RootService } from '../root-service.js';
import { TemplateJob } from './services/template.js'; import { TemplateJob } from './services/template.js';
import {
createInsertPlaceMiddleware,
createRegenerateIndexMiddleware,
createStickerMiddleware,
replaceIdMiddleware,
} from './services/template-middlewares.js';
import { getCursorMode } from './utils/query.js'; import { getCursorMode } from './utils/query.js';
export class EdgelessRootService extends RootService implements SurfaceContext { export class EdgelessRootService extends RootService implements SurfaceContext {
@@ -160,46 +153,6 @@ export class EdgelessRootService extends RootService implements SurfaceContext {
); );
} }
createTemplateJob(
type: 'template' | 'sticker',
center?: { x: number; y: number }
) {
const middlewares: ((job: TemplateJob) => void)[] = [];
if (type === 'template') {
const bounds = [...this.blocks, ...this.elements].map(i =>
Bound.deserialize(i.xywh)
);
const currentContentBound = getCommonBound(bounds);
if (currentContentBound) {
currentContentBound.x +=
currentContentBound.w + 20 / this.viewport.zoom;
middlewares.push(createInsertPlaceMiddleware(currentContentBound));
}
const idxGenerator = this.layer.createIndexGenerator();
middlewares.push(createRegenerateIndexMiddleware(() => idxGenerator()));
}
if (type === 'sticker') {
middlewares.push(
createStickerMiddleware(center || this.viewport.center, () =>
this.layer.generateIndex()
)
);
}
middlewares.push(replaceIdMiddleware);
return TemplateJob.create({
model: this.surface,
type,
middlewares,
});
}
generateIndex() { generateIndex() {
return this.layer.generateIndex(); return this.layer.generateIndex();
} }

View File

@@ -6,6 +6,7 @@ export * from './edgeless-root-block.js';
export { EdgelessRootPreviewBlockComponent } from './edgeless-root-preview-block.js'; export { EdgelessRootPreviewBlockComponent } from './edgeless-root-preview-block.js';
export { EdgelessRootService } from './edgeless-root-service.js'; export { EdgelessRootService } from './edgeless-root-service.js';
export * from './gfx-tool'; export * from './gfx-tool';
export * from './services/template.js';
export * from './utils/clipboard-utils.js'; export * from './utils/clipboard-utils.js';
export { sortEdgelessElements } from './utils/clone-utils.js'; export { sortEdgelessElements } from './utils/clone-utils.js';
export { isCanvasElement } from './utils/query.js'; export { isCanvasElement } from './utils/query.js';

View File

@@ -1,10 +1,14 @@
import type { import {
SurfaceBlockModel, getSurfaceBlock,
SurfaceBlockTransformer, type SurfaceBlockModel,
type SurfaceBlockTransformer,
} from '@blocksuite/affine-block-surface'; } from '@blocksuite/affine-block-surface';
import type { ConnectorElementModel } from '@blocksuite/affine-model'; import type { ConnectorElementModel } from '@blocksuite/affine-model';
import { BlockSuiteError } from '@blocksuite/global/exceptions';
import { Bound, getCommonBound } from '@blocksuite/global/gfx'; import { Bound, getCommonBound } from '@blocksuite/global/gfx';
import { assertType } from '@blocksuite/global/utils'; import { assertType } from '@blocksuite/global/utils';
import type { BlockStdScope } from '@blocksuite/std';
import { GfxControllerIdentifier } from '@blocksuite/std/gfx';
import { import {
type BlockModel, type BlockModel,
type BlockSnapshot, type BlockSnapshot,
@@ -15,6 +19,13 @@ import {
} from '@blocksuite/store'; } from '@blocksuite/store';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import type * as Y from 'yjs'; import type * as Y from 'yjs';
import {
createInsertPlaceMiddleware,
createRegenerateIndexMiddleware,
createStickerMiddleware,
replaceIdMiddleware,
} from './template-middlewares';
/** /**
* Those block contains other block's id * Those block contains other block's id
* should defer the loading * should defer the loading
@@ -369,3 +380,53 @@ export class TemplateJob {
iterate(this._template.blocks, this._template); iterate(this._template.blocks, this._template);
} }
} }
export function createTemplateJob(
std: BlockStdScope,
type: 'template' | 'sticker',
center?: { x: number; y: number }
) {
const surface = getSurfaceBlock(std.store);
if (!surface) {
throw new BlockSuiteError(
BlockSuiteError.ErrorCode.NoSurfaceModelError,
'This doc is missing surface block in edgeless.'
);
}
const gfx = std.get(GfxControllerIdentifier);
const middlewares: ((job: TemplateJob) => void)[] = [];
const { layer, viewport } = gfx;
const blocks = layer.blocks;
const elements = layer.canvasElements;
if (type === 'template') {
const bounds = [...blocks, ...elements].map(i => Bound.deserialize(i.xywh));
const currentContentBound = getCommonBound(bounds);
if (currentContentBound) {
currentContentBound.x += currentContentBound.w + 20 / viewport.zoom;
middlewares.push(createInsertPlaceMiddleware(currentContentBound));
}
const idxGenerator = layer.createIndexGenerator();
middlewares.push(createRegenerateIndexMiddleware(() => idxGenerator()));
}
if (type === 'sticker') {
middlewares.push(
createStickerMiddleware(center || viewport.center, () =>
layer.generateIndex()
)
);
}
middlewares.push(replaceIdMiddleware);
return TemplateJob.create({
model: surface,
type,
middlewares,
});
}

View File

@@ -1,4 +1,5 @@
import { addImages } from '@blocksuite/affine/blocks/image'; import { addImages } from '@blocksuite/affine/blocks/image';
import { createTemplateJob } from '@blocksuite/affine/blocks/root';
import { getSurfaceBlock } from '@blocksuite/affine/blocks/surface'; import { getSurfaceBlock } from '@blocksuite/affine/blocks/surface';
import { LightLoadingIcon } from '@blocksuite/affine/components/icons'; import { LightLoadingIcon } from '@blocksuite/affine/components/icons';
import { addTree } from '@blocksuite/affine/gfx/mindmap'; import { addTree } from '@blocksuite/affine/gfx/mindmap';
@@ -46,7 +47,6 @@ import {
getEdgelessRootFromEditor, getEdgelessRootFromEditor,
getSurfaceElementFromEditor, getSurfaceElementFromEditor,
} from '../utils/selection-utils'; } from '../utils/selection-utils';
import { createTemplateJob } from '../utils/template-job';
import type { AffineAIPanelWidget } from '../widgets/ai-panel/ai-panel'; import type { AffineAIPanelWidget } from '../widgets/ai-panel/ai-panel';
import type { EdgelessCopilotWidget } from '../widgets/edgeless-copilot'; import type { EdgelessCopilotWidget } from '../widgets/edgeless-copilot';
import { EXCLUDING_INSERT_ACTIONS, generatingStages } from './consts'; import { EXCLUDING_INSERT_ACTIONS, generatingStages } from './consts';
@@ -514,7 +514,7 @@ async function responseToCreateSlides(host: EditorHost, ctx: AIContext) {
for (let i = 0; i < contents.length; i++) { for (let i = 0; i < contents.length; i++) {
const image = images[i] || []; const image = images[i] || [];
const content = contents[i]; const content = contents[i];
const job = createTemplateJob(host); const job = createTemplateJob(host.std, 'template');
const imagePromises = image.map(async ({ id, url }) => { const imagePromises = image.map(async ({ id, url }) => {
const response = await fetch(url); const response = await fetch(url);

View File

@@ -1,4 +1,5 @@
import { uploadBlobForImage } from '@blocksuite/affine/blocks/image'; import { uploadBlobForImage } from '@blocksuite/affine/blocks/image';
import { createTemplateJob } from '@blocksuite/affine/blocks/root';
import { import {
getSurfaceBlock, getSurfaceBlock,
SurfaceBlockModel, SurfaceBlockModel,
@@ -25,7 +26,6 @@ import { insertAbove, insertBelow, replace } from '../utils/editor-actions';
import { preprocessHtml } from '../utils/html'; import { preprocessHtml } from '../utils/html';
import { fetchImageToFile } from '../utils/image'; import { fetchImageToFile } from '../utils/image';
import { getSelections } from '../utils/selection-utils'; import { getSelections } from '../utils/selection-utils';
import { createTemplateJob } from '../utils/template-job';
const PADDING = 100; const PADDING = 100;
@@ -138,7 +138,7 @@ async function responseToCreateSlides(
for (let i = 0; i < contents.length; i++) { for (let i = 0; i < contents.length; i++) {
const image = images[i]; const image = images[i];
const content = contents[i]; const content = contents[i];
const job = createTemplateJob(host); const job = createTemplateJob(host.std, 'template');
await Promise.all( await Promise.all(
image.map(({ id, url }) => image.map(({ id, url }) =>
fetch(url) fetch(url)

View File

@@ -1,10 +1,10 @@
import { createTemplateJob } from '@blocksuite/affine/blocks/root';
import type { EditorHost } from '@blocksuite/affine/std'; import type { EditorHost } from '@blocksuite/affine/std';
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx'; import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
import type { BlockSnapshot } from '@blocksuite/affine/store'; import type { BlockSnapshot } from '@blocksuite/affine/store';
import { markdownToSnapshot } from '../../utils'; import { markdownToSnapshot } from '../../utils';
import { getSurfaceElementFromEditor } from '../utils/selection-utils'; import { getSurfaceElementFromEditor } from '../utils/selection-utils';
import { createTemplateJob } from '../utils/template-job';
import { import {
basicTheme, basicTheme,
type PPTDoc, type PPTDoc,
@@ -36,7 +36,7 @@ export const PPTBuilder = (host: EditorHost) => {
}; };
docs.push(doc); docs.push(doc);
const job = createTemplateJob(host); const job = createTemplateJob(host.std, 'template');
const { images, content } = await basicTheme(doc); const { images, content } = await basicTheme(doc);
contents.push(content); contents.push(content);
allImages.push(images); allImages.push(images);

View File

@@ -1,41 +0,0 @@
import {
TemplateJob,
TemplateMiddlewares,
} from '@blocksuite/affine/blocks/root';
import { getSurfaceBlock } from '@blocksuite/affine/blocks/surface';
import { Bound, getCommonBound } from '@blocksuite/affine/global/gfx';
import type { EditorHost } from '@blocksuite/affine/std';
import { GfxController, LayerManager } from '@blocksuite/affine/std/gfx';
export function createTemplateJob(host: EditorHost) {
const surface = getSurfaceBlock(host.doc);
if (!surface) {
throw new Error('surface is not found');
}
const middlewares: ((job: TemplateJob) => void)[] = [];
const layer = new LayerManager(host.std.get(GfxController));
const bounds = [...layer.blocks, ...layer.canvasElements].map(i =>
Bound.deserialize(i.xywh)
);
const currentContentBound = getCommonBound(bounds);
if (currentContentBound) {
currentContentBound.x += currentContentBound.w + 100;
middlewares.push(
TemplateMiddlewares.createInsertPlaceMiddleware(currentContentBound)
);
}
const idxGenerator = layer.createIndexGenerator();
middlewares.push(
TemplateMiddlewares.createRegenerateIndexMiddleware(() => idxGenerator())
);
middlewares.push(TemplateMiddlewares.replaceIdMiddleware);
return TemplateJob.create({
model: surface,
type: 'template',
middlewares,
});
}