diff --git a/lib/apitable.ts b/lib/apitable.ts index 9d7125f..2ee281c 100644 --- a/lib/apitable.ts +++ b/lib/apitable.ts @@ -7,6 +7,7 @@ import { IHttpResponse, IVikaClientConfig } from "./interface"; import { NodeManager } from "./node"; import { SpaceManager } from "./space"; import { mergeConfig, QPSController, isBrowser, subBeforeIfHaving } from "./utils"; +import {IframeManager} from "./iframe"; // axios.defaults.adapter = mpAdapter; export class Vika { @@ -118,7 +119,7 @@ export class Vika { datasheet(datasheetId: string) { if (!datasheetId) { throw new Error( - 'Please pass the datasheet id, which can be retrieved from the datasheet url, ' + + 'Please pass the datasheet id, which can be retrieved from the datasheet url, ' + 'the datasheet id usually starts with dst, for example dstRzy7alM1mkuy1Y3' ); } @@ -145,4 +146,11 @@ export class Vika { space(spaceId: string) { return new SpaceManager(this, spaceId); } + + /** + * 获取 iframe 通信 + */ + getIframe() { + return new IframeManager(); + } } diff --git a/lib/enums.ts b/lib/enums.ts index da8f488..ad15df2 100644 --- a/lib/enums.ts +++ b/lib/enums.ts @@ -70,3 +70,27 @@ export enum APIMetaFieldPropertyFormatEnums { Percent = 'Percent', Currency = 'Currency', } + +export enum IframeMessageName { + Collaborators = "collaborators", + SocketStatus = "socketStatus", + SocketError = "socketError", + ChangeView = "changeView", + ChangeNodeName = 'changeNodeName', + PageLoaded = 'pageLoaded', + EmbedLinkFail = 'embedLinkFail', + PageCrash = 'pageCrash', + ChangeViewName = 'changeViewName', + TriggerEventResult = 'triggerEventResult', +} + +export enum TriggerIframeMessageName { + ExportData = "exportData", +} + +export enum Network { + Online = "online", + Offline = "offline", + Sync = "sync", + Loading = "loading" +} diff --git a/lib/iframe.ts b/lib/iframe.ts new file mode 100644 index 0000000..f916e8a --- /dev/null +++ b/lib/iframe.ts @@ -0,0 +1,76 @@ +import {IframeMessageName} from "./enums"; +import {IEventFunc, ITriggerIframeMessage} from "./interface/iframe"; + +declare let window: any; + +export class IframeManager { + event: Map>; + + private listener = (event: any) => { + const data = event.data; + const message = data.message; + const _data = data.data; + const stack = this.event.get(message); + if (!stack) { + return; + } + stack.forEach(func => { + func(_data); + }); + }; + + constructor() { + console.log('init iframe manager'); + + this.event = new Map(); + + if (typeof window == 'undefined') { + console.log('window is undefined'); + return; + } + + window.addEventListener('message', this.listener); + } + + subscribe(eventName: IframeMessageName, func: IEventFunc) { + if (!this.event.has(eventName)) { + this.event.set(eventName, new Set([func])); + return; + } + + const stack = this.event.get(eventName) || new Set(); + + if (stack.has(func)) { + console.error('has same function'); + return; + } + + stack.add(func); + this.event.set(eventName, stack); + } + + unSubscribe(eventName: IframeMessageName, func: IEventFunc) { + if (!this.event.has(eventName)) { + console.error('there are no subscribe'); + return; + } + + const stack = this.event.get(eventName) || new Set(); + stack.delete(func); + this.event.set(eventName, stack); + } + + unSubscribeAll() { + this.event = new Map(); + } + + triggerEvent({ iframeRef, eventName, data }: ITriggerIframeMessage) { + iframeRef?.contentWindow?.postMessage( + { + msg: eventName, + data + }, + '*', + ); + } +} diff --git a/lib/interface/iframe.ts b/lib/interface/iframe.ts new file mode 100644 index 0000000..c810dad --- /dev/null +++ b/lib/interface/iframe.ts @@ -0,0 +1,101 @@ +import { IframeMessageName, Network, TriggerIframeMessageName } from '../enums'; + +export type IEventFunc = (data: any) => void; + +export interface IIframeMessageForCollaborators { + message: IframeMessageName.Collaborators; + data: { + roomId: string; + collaborators: ICollaborator[]; + }; +} + +interface ICollaborator { + name: string; + avatar: string; +} + +export interface IIframeMessageForSocketStatus { + message: IframeMessageName.SocketStatus; + data: { + roomId: string; + status: Network; + }; +} + +export interface IIframeMessageForSocketError { + message: IframeMessageName.SocketError; + data: IRoomSocketError; +} + +interface IRoomSocketError { + errorCode: number; + message: string; + roomId: string; + messageId: string; +} + +export interface IIframeMessageForChangeView { + message: IframeMessageName.ChangeView; + data: { + roomId: string; + nextViewId: string; + }; +} + +export interface IIframeMessageForChangeNodeName { + message: IframeMessageName.ChangeNodeName; + data: { + roomId: string; + nodeName: string; + }; +} + +export interface IIframeMessageForPageLoaded { + message: IframeMessageName.PageLoaded; +} + +export interface IIframeMessageForEmbedLinkFail { + message: IframeMessageName.EmbedLinkFail; +} + +export interface IIframeMessageForPageCrash { + message: IframeMessageName.PageCrash; +} + +export interface IIframeMessageForChangeViewName { + message: IframeMessageName.ChangeViewName; + data: { + roomId: string; + viewId: string; + viewName: string; + }; +} + +export interface IIframeMessageForTriggerEventResult { + message: IframeMessageName.TriggerEventResult; + data: { + eventName: TriggerIframeMessageName; + success: boolean; + message?: string; + }; +} + +interface ITriggerIframeMessageBase { + iframeRef: any; + eventName: TriggerIframeMessageName; +} + +export interface ITriggerIframeMessageForExportData extends ITriggerIframeMessageBase { + eventName: TriggerIframeMessageName.ExportData; + data: { + nodeId: string; + /** + * @default 'xlsx' + */ + fileType?: 'csv' | 'xlsx' | 'png' + viewId?: string; + }; +} + +export type ITriggerIframeMessage = ITriggerIframeMessageForExportData