snapshot of https://github.com/dream-num/univer.git (dev, 2026-09-16; blobs > 131072B omitted)
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
Some checks failed
📦 Build / build (push) Has been cancelled
🧪 CI Test / test shard (1/4) (push) Has been cancelled
🧪 CI Test / test shard (2/4) (push) Has been cancelled
🧪 CI Test / test shard (3/4) (push) Has been cancelled
🧪 CI Test / test shard (4/4) (push) Has been cancelled
🧪 CI Test / test (push) Has been cancelled
🧪 CI Test / eslint (push) Has been cancelled
🧪 CI Test / typecheck (push) Has been cancelled
🔫 Sync to Pro / dispatch-sync (push) Has been cancelled
🔮 Sync Mirror / sync (push) Has been cancelled
This commit is contained in:
237
packages/docs-ui/src/controllers/doc-auto-format.controller.ts
Normal file
237
packages/docs-ui/src/controllers/doc-auto-format.controller.ts
Normal file
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* Copyright 2023-present DreamNum Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { Nullable } from '@univerjs/core';
|
||||
import type { ITabCommandParams } from '../commands/commands/auto-format.command';
|
||||
import { Disposable, Inject, QuickListTypeMap } from '@univerjs/core';
|
||||
import { DocSkeletonManagerService } from '@univerjs/docs';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { AfterSpaceCommand, EnterCommand, TabCommand } from '../commands/commands/auto-format.command';
|
||||
import { BreakLineCommand } from '../commands/commands/break-line.command';
|
||||
import {
|
||||
ChangeListNestingLevelCommand,
|
||||
ChangeListNestingLevelType,
|
||||
ListOperationCommand,
|
||||
QuickListCommand,
|
||||
} from '../commands/commands/list.command';
|
||||
import { QUICK_HEADING_MAP, QuickHeadingCommand } from '../commands/commands/set-heading.command';
|
||||
import { DocTableTabCommand } from '../commands/commands/table/doc-table-tab.command';
|
||||
import { DocAutoFormatService } from '../services/doc-auto-format.service';
|
||||
import { isInSameTableCellData } from '../services/selection/convert-rect-range';
|
||||
|
||||
function hasQuickListType(text: string): text is keyof typeof QuickListTypeMap {
|
||||
return Object.prototype.hasOwnProperty.call(QuickListTypeMap, text);
|
||||
}
|
||||
|
||||
function hasQuickHeading(text: string): text is keyof typeof QUICK_HEADING_MAP {
|
||||
return Object.prototype.hasOwnProperty.call(QUICK_HEADING_MAP, text);
|
||||
}
|
||||
|
||||
export class DocAutoFormatController extends Disposable {
|
||||
constructor(
|
||||
@Inject(DocAutoFormatService) private readonly _docAutoFormatService: DocAutoFormatService,
|
||||
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService
|
||||
) {
|
||||
super();
|
||||
|
||||
this._initListTabAutoFormat();
|
||||
this._initSpaceAutoFormat();
|
||||
this._initDefaultEnterFormat();
|
||||
this._initExitListAutoFormat();
|
||||
}
|
||||
|
||||
private _initListTabAutoFormat() {
|
||||
this.disposeWithMe(
|
||||
this._docAutoFormatService.registerAutoFormat({
|
||||
id: TabCommand.id,
|
||||
match: (context) => {
|
||||
const { selection, paragraphs, unit } = context;
|
||||
|
||||
// 1. match 1 bullet paragraph, range.start == paragraph.start
|
||||
if (paragraphs.length === 1 && selection.startOffset === paragraphs[0].paragraphStart && paragraphs[0].bullet) {
|
||||
// 2. cross paragraphs, some paragraph is bullet
|
||||
const allParagraphs = unit.getBody()?.paragraphs;
|
||||
// 3. disable first bullet indent
|
||||
const bulletParagraphs = allParagraphs?.filter((p) => p.bullet?.listId === paragraphs[0].bullet!.listId);
|
||||
if (bulletParagraphs?.findIndex((p) => p.startIndex === paragraphs[0].startIndex) === 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else if (paragraphs.length > 1 && paragraphs.some((p) => p.bullet)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
// traverse all paragraphs, set paragraph
|
||||
getMutations(context) {
|
||||
const params = context.commandParams as Nullable<ITabCommandParams>;
|
||||
return [{
|
||||
id: ChangeListNestingLevelCommand.id,
|
||||
params: {
|
||||
type: params?.shift ? ChangeListNestingLevelType.decrease : ChangeListNestingLevelType.increase,
|
||||
},
|
||||
}];
|
||||
},
|
||||
priority: 100,
|
||||
})
|
||||
);
|
||||
|
||||
this.disposeWithMe(
|
||||
this._docAutoFormatService.registerAutoFormat({
|
||||
id: TabCommand.id,
|
||||
match: (context) => {
|
||||
const { selection, unit } = context;
|
||||
|
||||
const { startNodePosition, endNodePosition } = selection;
|
||||
|
||||
const renderObject = this._renderManagerService.getRenderUnitById(unit.getUnitId());
|
||||
const skeleton = renderObject?.with(DocSkeletonManagerService).getSkeleton();
|
||||
|
||||
if (skeleton == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (startNodePosition && endNodePosition && isInSameTableCellData(skeleton, startNodePosition, endNodePosition)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (startNodePosition && !endNodePosition && startNodePosition.path.indexOf('cells') > -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
getMutations(context) {
|
||||
const params = context.commandParams as Nullable<ITabCommandParams>;
|
||||
return [{
|
||||
id: DocTableTabCommand.id,
|
||||
params: {
|
||||
shift: !!params?.shift,
|
||||
},
|
||||
}];
|
||||
},
|
||||
priority: 99,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private _initSpaceAutoFormat() {
|
||||
this.disposeWithMe(
|
||||
this._docAutoFormatService.registerAutoFormat({
|
||||
id: AfterSpaceCommand.id,
|
||||
match: (context) => {
|
||||
const { selection, paragraphs, unit } = context;
|
||||
if (!selection.collapsed) {
|
||||
return false;
|
||||
}
|
||||
if (paragraphs.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
if (!selection.collapsed) {
|
||||
return false;
|
||||
}
|
||||
const text = unit.getBody()?.dataStream.slice(paragraphs[0].paragraphStart, selection.startOffset - 1);
|
||||
if (text && (hasQuickListType(text) || hasQuickHeading(text))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getMutations(context) {
|
||||
const { paragraphs, unit, selection } = context;
|
||||
const text = unit.getBody()?.dataStream.slice(paragraphs[0].paragraphStart, selection.startOffset - 1);
|
||||
if (text && hasQuickListType(text)) {
|
||||
const type = QuickListTypeMap[text];
|
||||
return [{
|
||||
id: QuickListCommand.id,
|
||||
params: {
|
||||
listType: type,
|
||||
paragraph: paragraphs[0],
|
||||
},
|
||||
}];
|
||||
}
|
||||
|
||||
if (text && hasQuickHeading(text)) {
|
||||
const type = QUICK_HEADING_MAP[text];
|
||||
return [{
|
||||
id: QuickHeadingCommand.id,
|
||||
params: {
|
||||
value: type,
|
||||
},
|
||||
}];
|
||||
}
|
||||
return [];
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private _initExitListAutoFormat() {
|
||||
this.disposeWithMe(
|
||||
this._docAutoFormatService.registerAutoFormat({
|
||||
id: EnterCommand.id,
|
||||
match: (context) => {
|
||||
const { paragraphs } = context;
|
||||
// selection at empty bullet paragraph
|
||||
if (paragraphs.length === 1 && paragraphs[0].bullet && paragraphs[0].paragraphStart === paragraphs[0].paragraphEnd) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
getMutations: (context) => {
|
||||
const bullet = context.paragraphs[0].bullet;
|
||||
if (!bullet) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (bullet.nestingLevel > 0) {
|
||||
return [{
|
||||
id: ChangeListNestingLevelCommand.id,
|
||||
params: {
|
||||
type: ChangeListNestingLevelType.decrease,
|
||||
},
|
||||
}];
|
||||
}
|
||||
|
||||
return [{
|
||||
id: ListOperationCommand.id,
|
||||
params: {
|
||||
listType: context.paragraphs[0].bullet!.listType,
|
||||
},
|
||||
}];
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private _initDefaultEnterFormat() {
|
||||
// enter default
|
||||
this.disposeWithMe(
|
||||
this._docAutoFormatService.registerAutoFormat({
|
||||
id: EnterCommand.id,
|
||||
match: () => {
|
||||
return true;
|
||||
},
|
||||
getMutations() {
|
||||
return [{
|
||||
id: BreakLineCommand.id,
|
||||
}];
|
||||
},
|
||||
priority: -9999,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user