@odoo/o-spreadsheet
Version:
A spreadsheet component
169 lines (168 loc) • 7.16 kB
TypeScript
import { UuidGenerator } from "./helpers";
import { EventBus } from "./helpers/event_bus";
import { StateUpdateMessage } from "./types/collaborative/transport_service";
import { CommandDispatcher } from "./types/commands";
import { Getters } from "./types/getters";
import { Mode, ModelConfig } from "./types/model";
import { GridRenderingContext, LayerName } from "./types/rendering";
import { SelectionStreamProcessor } from "./types/selection_stream_processor";
import { WorkbookData } from "./types/workbook_data";
import { XLSXExport } from "./types/xlsx";
/**
* Model
*
* The Model class is the owner of the state of the Spreadsheet. However, it
* has more a coordination role: it defers the actual state manipulation work to
* plugins.
*
* At creation, the Model instantiates all necessary plugins. They each have
* a private state (for example, the Selection plugin has the current selection).
*
* State changes are then performed through commands. Commands are dispatched
* to the model, which will then relay them to each plugins (and the history
* handler). Then, the model will trigger an 'update' event to notify whoever
* is concerned that the command was applied (if it was not canceled).
*
* Also, the model has an unconventional responsibility: it actually renders the
* visible viewport on a canvas. This is because each plugins actually manage a
* specific concern about the content of the spreadsheet, and it is more natural
* if they are able to read data from their internal state to represent it on the
* screen.
*
* Note that the Model can be used in a standalone way to manipulate
* programmatically a spreadsheet.
*/
export declare class Model extends EventBus<any> implements CommandDispatcher {
private corePlugins;
private statefulUIPlugins;
private range;
private session;
/**
* In a collaborative context, some commands can be replayed, we have to ensure
* that these commands are not replayed on the UI plugins.
*/
private isReplayingCommand;
/**
* A plugin can draw some contents on the canvas. But even better: it can do
* so multiple times. The order of the render calls will determine a list of
* "layers" (i.e., earlier calls will be obviously drawn below later calls).
* This list simply keeps the renderers+layer information so the drawing code
* can just iterate on it
*/
private renderers;
/**
* Internal status of the model. Important for command handling coordination
*/
private status;
/**
* The config object contains some configuration flag and callbacks
*/
readonly config: ModelConfig;
private corePluginConfig;
private coreViewPluginConfig;
private uiPluginConfig;
private state;
readonly selection: SelectionStreamProcessor;
/**
* Getters are the main way the rest of the UI read data from the model. Also,
* it is shared between all plugins, so they can also communicate with each
* other.
*/
getters: Getters;
/**
* Getters that are accessible from the core plugins. It's a subset of `getters`,
* without the UI getters
*/
private coreGetters;
uuidGenerator: UuidGenerator;
private readonly handlers;
private readonly uiHandlers;
private readonly coreHandlers;
constructor(data?: any, config?: Partial<ModelConfig>, stateUpdateMessages?: StateUpdateMessage[], uuidGenerator?: UuidGenerator, verboseImport?: boolean);
joinSession(): void;
leaveSession(): Promise<void>;
private setupUiPlugin;
private setupCoreViewPlugin;
/**
* Initialize and properly configure a plugin.
*
* This method is private for now, but if the need arise, there is no deep
* reason why the model could not add dynamically a plugin while it is running.
*/
private setupCorePlugin;
private onRemoteRevisionReceived;
private setupSession;
private setupSessionEvents;
private setupConfig;
private setupExternalConfig;
private setupCorePluginConfig;
private setupCoreViewPluginConfig;
private setupUiPluginConfig;
/**
* Check if the given command is allowed by all the plugins and the history.
*/
private checkDispatchAllowed;
private processCommandResults;
private checkDispatchAllowedRemoteCommand;
private checkDispatchAllowedCoreCommand;
private checkDispatchAllowedLocalCommand;
private finalize;
/**
* Check if a command can be dispatched, and returns a DispatchResult object with the possible
* reasons the dispatch failed.
*/
canDispatch: CommandDispatcher["dispatch"];
/**
* The dispatch method is the only entry point to manipulate data in the model.
* This is through this method that commands are dispatched most of the time
* recursively until no plugin want to react anymore.
*
* CoreCommands dispatched from this function are saved in the history.
*
* Small technical detail: it is defined as an arrow function. There are two
* reasons for this:
* 1. this means that the dispatch method can be "detached" from the model,
* which is done when it is put in the environment (see the Spreadsheet
* component)
* 2. This allows us to define its type by using the interface CommandDispatcher
*/
dispatch: CommandDispatcher["dispatch"];
/**
* Dispatch a command from a Core Plugin (or the History).
* A command dispatched from this function is not added to the history.
*/
private dispatchFromCorePlugin;
/**
* Dispatch the given command to the given handlers.
* It will call `beforeHandle` and `handle`
*/
private dispatchToHandlers;
/**
* When the Grid component is ready (= mounted), it has a reference to its
* canvas and need to draw the grid on it. This is then done by calling this
* method, which will dispatch the call to all registered plugins.
*
* Note that nothing prevent multiple grid components from calling this method
* each, or one grid component calling it multiple times with a different
* context. This is probably the way we should do if we want to be able to
* freeze a part of the grid (so, we would need to render different zones)
*/
drawLayer(context: GridRenderingContext, layer: LayerName): void;
/**
* As the name of this method strongly implies, it is useful when we need to
* export data out of the model.
*/
exportData(): WorkbookData;
_exportData(shouldSquish: boolean): WorkbookData;
updateMode(mode: Mode): void;
/**
* Exports the current model data into a list of serialized XML files
* to be zipped together as an *.xlsx file.
*
* We need to trigger a cell revaluation on every sheet and ensure that even
* async functions are evaluated.
* This prove to be necessary if the client did not trigger that evaluation in the first place
* (e.g. open a document with several sheet and click on download before visiting each sheet)
*/
exportXLSX(): Promise<XLSXExport>;
}