mirror of
https://github.com/dream-num/univer.git
synced 2026-08-29 07:13:59 +08:00
feat(facade): add auto-fill api (#6204)
This commit is contained in:
@@ -16,14 +16,15 @@
|
||||
|
||||
import type { IAccessor, ICommand, IRange } from '@univerjs/core';
|
||||
import type { ISetRangeValuesMutationParams, ISetSelectionsOperationParams } from '@univerjs/sheets';
|
||||
import type { APPLY_TYPE } from '../../services/auto-fill/type';
|
||||
import { CommandType, ICommandService, IUndoRedoService, IUniverInstanceService, sequenceExecute } from '@univerjs/core';
|
||||
import { generateNullCellValue, getSheetCommandTarget, SetRangeValuesMutation, SetRangeValuesUndoMutationFactory, SetSelectionsOperation, SheetInterceptorService } from '@univerjs/sheets';
|
||||
|
||||
import { IAutoFillService } from '../../services/auto-fill/auto-fill.service';
|
||||
|
||||
export interface IAutoFillCommandParams {
|
||||
sourceRange: IRange;
|
||||
targetRange: IRange;
|
||||
applyType?: APPLY_TYPE; // manual apply type
|
||||
}
|
||||
|
||||
export const AutoFillCommand: ICommand = {
|
||||
@@ -34,13 +35,13 @@ export const AutoFillCommand: ICommand = {
|
||||
const autoFillService = accessor.get(IAutoFillService);
|
||||
const univerInstanceService = accessor.get(IUniverInstanceService);
|
||||
|
||||
const { sourceRange, targetRange } = params;
|
||||
const { sourceRange, targetRange, applyType } = params;
|
||||
|
||||
const commandTarget = getSheetCommandTarget(univerInstanceService);
|
||||
if (!commandTarget) return false;
|
||||
|
||||
const { subUnitId, unitId } = commandTarget;
|
||||
return autoFillService.triggerAutoFill(unitId, subUnitId, sourceRange, targetRange);
|
||||
return autoFillService.triggerAutoFill(unitId, subUnitId, sourceRange, targetRange, applyType);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
import type { ICellWithCoord, IDisposable, ISelectionCell, Nullable } from '@univerjs/core';
|
||||
import type { ISelectionStyle, ISheetLocation } from '@univerjs/sheets';
|
||||
import type { ICanvasPopup, ICellAlert, IDropdownParam } from '@univerjs/sheets-ui';
|
||||
import type { APPLY_TYPE, ICanvasPopup, ICellAlert, IDropdownParam } from '@univerjs/sheets-ui';
|
||||
import type { ComponentType } from '@univerjs/ui';
|
||||
import { DisposableCollection, generateRandomId, ILogService, toDisposable } from '@univerjs/core';
|
||||
import { DisposableCollection, generateRandomId, ILogService, Rectangle, toDisposable } from '@univerjs/core';
|
||||
import { IRenderManagerService } from '@univerjs/engine-render';
|
||||
import { CellAlertManagerService, IMarkSelectionService, ISheetCellDropdownManagerService, ISheetClipboardService, SheetCanvasPopManagerService, SheetSkeletonManagerService } from '@univerjs/sheets-ui';
|
||||
import { AutoFillCommand, CellAlertManagerService, IMarkSelectionService, ISheetCellDropdownManagerService, ISheetClipboardService, SheetCanvasPopManagerService, SheetSkeletonManagerService } from '@univerjs/sheets-ui';
|
||||
import { FRange } from '@univerjs/sheets/facade';
|
||||
import { ComponentManager } from '@univerjs/ui';
|
||||
|
||||
@@ -225,6 +225,27 @@ interface IFRangeSheetsUIMixin {
|
||||
* ```
|
||||
*/
|
||||
showDropdown(param: IDropdownParam): IDisposable;
|
||||
|
||||
/**
|
||||
* Fills the target range with data based on the data in the current range.
|
||||
* @param {FRange} targetRange - The range to be filled with data.
|
||||
* @param {APPLY_TYPE} [applyType] - The type of data fill to be applied.
|
||||
* @returns {Promise<boolean>} A promise that resolves to true if the fill operation was successful, false otherwise.
|
||||
* @example
|
||||
* ```ts
|
||||
* // Auto-fill the range D1:D10 based on the data in the range C1:C2
|
||||
* const fWorkbook = univerAPI.getActiveWorkbook();
|
||||
* const fWorksheet = fWorkbook.getActiveSheet();
|
||||
* const fRange = fWorksheet.getRange('A1:A4');
|
||||
*
|
||||
* // Auto-fill with 'COPY' type
|
||||
* await fRange.autoFill(fWorksheet.getRange('A1:A20'), 'COPY')
|
||||
*
|
||||
* // Auto-fill with 'SERIES' type
|
||||
* await fRange.autoFill(fWorksheet.getRange('A1:A20'), 'SERIES')
|
||||
* ```
|
||||
*/
|
||||
autoFill(targetRange: FRange, applyType?: APPLY_TYPE): Promise<boolean>;
|
||||
}
|
||||
|
||||
class FRangeSheetsUIMixin extends FRange implements IFRangeSheetsUIMixin {
|
||||
@@ -355,6 +376,47 @@ class FRangeSheetsUIMixin extends FRange implements IFRangeSheetsUIMixin {
|
||||
const cellDropdownManagerService = this._injector.get(ISheetCellDropdownManagerService);
|
||||
return cellDropdownManagerService.showDropdown(param);
|
||||
}
|
||||
|
||||
override async autoFill(targetRange: FRange, applyType?: APPLY_TYPE): Promise<boolean> {
|
||||
const _sourceRange = this.getRange();
|
||||
const _targetRange = targetRange.getRange();
|
||||
|
||||
if (!Rectangle.contains(_targetRange, _sourceRange)) {
|
||||
throw new Error('AutoFill target range must contain source range');
|
||||
}
|
||||
|
||||
const { startRow: sourceStartRow, startColumn: sourceStartColumn, endRow: sourceEndRow, endColumn: sourceEndColumn } = _sourceRange;
|
||||
const { startRow: targetStartRow, startColumn: targetStartColumn, endRow: targetEndRow, endColumn: targetEndColumn } = _targetRange;
|
||||
|
||||
// If both row and column count are different, throw error
|
||||
if ((sourceEndRow - sourceStartRow) !== (targetEndRow - targetStartRow) && (sourceEndColumn - sourceStartColumn) !== (targetEndColumn - targetStartColumn)) {
|
||||
throw new Error('AutoFill can only fill in one direction');
|
||||
}
|
||||
|
||||
// If the direction includes both left and right, throw error
|
||||
if (
|
||||
(sourceEndRow - sourceStartRow) === (targetEndRow - targetStartRow) &&
|
||||
sourceStartColumn !== targetStartColumn &&
|
||||
sourceEndColumn !== targetEndColumn
|
||||
) {
|
||||
throw new Error('AutoFill can only fill in one direction');
|
||||
}
|
||||
|
||||
// If the direction includes both up and down, throw error
|
||||
if (
|
||||
(sourceEndColumn - sourceStartColumn) === (targetEndColumn - targetStartColumn) &&
|
||||
sourceStartRow !== targetStartRow &&
|
||||
sourceEndRow !== targetEndRow
|
||||
) {
|
||||
throw new Error('AutoFill can only fill in one direction');
|
||||
}
|
||||
|
||||
return this._commandService.executeCommand(AutoFillCommand.id, {
|
||||
sourceRange: _sourceRange,
|
||||
targetRange: _targetRange,
|
||||
applyType,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
FRange.extend(FRangeSheetsUIMixin);
|
||||
|
||||
@@ -68,7 +68,7 @@ export interface IAutoFillService {
|
||||
addHook(hook: ISheetAutoFillHook): IDisposable;
|
||||
fillData(applyType: APPLY_TYPE): boolean;
|
||||
|
||||
triggerAutoFill(unitId: string, subUnitId: string, source: IRange, target: IRange): Promise<boolean>;
|
||||
triggerAutoFill(unitId: string, subUnitId: string, source: IRange, target: IRange, manualApplyType?: APPLY_TYPE): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface IApplyMenuItem {
|
||||
@@ -162,8 +162,8 @@ export class AutoFillService extends Disposable implements IAutoFillService {
|
||||
this._prevUndos = [];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
async triggerAutoFill(unitId: string, subUnitId: string, source: IRange, selection: IRange) {
|
||||
// eslint-disable-next-line max-lines-per-function, complexity
|
||||
async triggerAutoFill(unitId: string, subUnitId: string, source: IRange, selection: IRange, manualApplyType?: APPLY_TYPE) {
|
||||
// if source range === dest range, do nothing;
|
||||
if (
|
||||
source.startColumn === selection.startColumn &&
|
||||
@@ -231,6 +231,7 @@ export class AutoFillService extends Disposable implements IAutoFillService {
|
||||
if (!autoFillSource || !autoFillTarget) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.autoFillLocation = {
|
||||
source: autoFillSource,
|
||||
target: autoFillTarget,
|
||||
@@ -248,6 +249,12 @@ export class AutoFillService extends Disposable implements IAutoFillService {
|
||||
});
|
||||
|
||||
this._initPrevUndo();
|
||||
|
||||
// If manual apply type is given, use it
|
||||
if (manualApplyType) {
|
||||
return this.fillData(manualApplyType);
|
||||
}
|
||||
|
||||
// set apply type will trigger fillData
|
||||
for (let i = 0; i < preferTypes.length; i++) {
|
||||
const menuItem = this.menu.find((m) => m.value === preferTypes[i]);
|
||||
@@ -255,6 +262,7 @@ export class AutoFillService extends Disposable implements IAutoFillService {
|
||||
return this.fillData(preferTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// if no hook return apply type, use first available apply type
|
||||
const first = this.menu.find((m) => m.disable === false)?.value;
|
||||
if (first) {
|
||||
|
||||
Reference in New Issue
Block a user