User Tools

Site Tools


en:outskirts:mages-peaks:detach-windows

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:outskirts:mages-peaks:detach-windows [2024/04/09 16:41] – [Using the Intercoms to communicate] Philippe Men:outskirts:mages-peaks:detach-windows [2024/10/28 08:00] (current) – external edit 127.0.0.1
Line 1: Line 1:
 +====== Detachable Windows and Intercom ======
 +
 +
 ===== Goals ===== ===== Goals =====
 As demonstrated in the laelith-adventure project, for the Editor, the goal is to enable a (Svelte) component sitting in a page to be //detached// into a popup window, that can be moved around independently, and notably make better use of multi-screen setups.\\  As demonstrated in the laelith-adventure project, for the Editor, the goal is to enable a (Svelte) component sitting in a page to be //detached// into a popup window, that can be moved around independently, and notably make better use of multi-screen setups.\\ 
Line 95: Line 98:
 When the view is mounted, it listens to //Intercom// messages (with ''intercom.on(Intercom.RX_MESSAGE'') and must handle the **wake-up** signal -- this signal notifies the embedded "ghosted" view that the detached window has closed. When the view is mounted, it listens to //Intercom// messages (with ''intercom.on(Intercom.RX_MESSAGE'') and must handle the **wake-up** signal -- this signal notifies the embedded "ghosted" view that the detached window has closed.
  
 +The "container" that mounts the embedded (attached) Svelte component should not destroy it when detached -- only with this implementation, as the code listens for the wake-up signal. Other setups are absolutely possible to manage the re-attachment of a detached component.
 ===== Using the Intercoms to communicate ===== ===== Using the Intercoms to communicate =====
 === Readiness signals === === Readiness signals ===
Line 100: Line 104:
 The //Intercoms// system notifies the application code when the transition is complete, to make sure that the target view can be reached and is ready to process messages. The //Intercoms// system notifies the application code when the transition is complete, to make sure that the target view can be reached and is ready to process messages.
  
-This is signalled using the ''whenReady'' callback+This is signalled using the ''whenReady'' callback
 +When in the embedded view, the returned Promise will immediately resolved.\\  
 +When in the detached view, it will resolve when the handshake with the parent window is complete, and, most importantly, when the internal communication system is ready to deliver messages sent to components living in the parent window.
  
 +Typically, this is where you will have the code to fetch the data of the component, using //Intercom// messages (see below).
  
 +<code>
 +intercom.whenReady().then(() => {
 +      intercom.sendMessage("DataProviderId", "request-my-data");
 +    });
 +</code>
 +
 +=== Communication between components ===
 +The //Intercoms// system provides communication between //intercom// instances ("views"). Each is identified by its **viewId**, that is the parameter given in ''newIntercom''.
 +
 +The key property of this communication system is that a message addressed to a ''viewId'' will reach its destination component //regardless of its attached/detached status//. This enables the application code to communicate with the detacheable view using the same API call, without having to know if it is detached or not.
 +
 +Sending a message to the view identified by **target-view-id** is done using:
 +<code>
 +  intercom.sendMessage("target-view-id", "message-type", payload);
 +</code>
 +
 +The ''message-type'' is fully managed by the application, the //Intercoms// system just reserves a few values for its own operation (''wake-up'', ''me-parent'', ''me-child'' and ''child-up'').
 +
 +For message reception, attach a Listener to the ''intercom'':
 +<code>
 +  intercom.on(Intercom.RX_MESSAGE,
 +      (msg: IntercomMessage) => {
 +        switch (msg.msgType) {
 +          case 'adv-current-adventure: ... // process received Adventure
 +          [...]
 +        }
 +      },"myview",
 +    );
 +    
 +    intercom.whenReady().then(() => {
 +      intercom.sendMessage('adv-store', 'adv-request-current-adventure');
 +    });
 +</code>
 +
 +The code above illustrates a common pattern: the View registers a message listener on the ''intercom'' and requests the data it needs from the ''adv-store'' (when the ''intercom'' is Ready). The response data is received by the Message Listener and can be used by the Component.
 +
 +=== The Network Prefix ===
 +All the ''ViewIds'' should include a dash (-), with the part before the dash termed as the ''networkPrefix''.\\ 
 +The special value **prefix-all** broadcasts a message to all Views with the same Prefix.\\ 
 +
 +//Intercom messages// can only be exchanged between Views of the same ''networkPrefix'', it is thus **required** to use as IDs of the views that need to communicate together only strings sharing the same prefix.  
 +  * This disposition allows to define several independent "communication networks" using //Intercoms//.
 +  * It allows to scope the Broadcasts to the Views of the same //network//.
 +  * Other unrelated applications communicate using also postMessage between windows and //Intercoms// will not forward or deliver these messages.
 +
 +===== Ensuring consistency between definitions =====
 +
 +To prevent misspelling bugs and provide a central place for the common definitions of communicating entities, it is suggested to create a specific ''.d.ts'' definition File with:
 +
 +  * All the ViewIDs (same network prefix) in an //Enum//.
 +  * The ''msgType'' Message Types, possibly segregated between //Requests// and //Indications//
 +  * The type definition of the Payloads.
 +
 +Create one such file for each "network" of communicating entities. As an example, for the Adventure Editor feature, the ''AdvEditIntercom.d.ts'' file plays this role:
 +
 +<code>
 +/**
 + * Participants to the Adventure Editor group. Used as Source and Target of messages, with the NetworkPrefix.
 + */
 +export enum AdvEditViews {
 +  /** For broadcasting messages, to all except the emitter. */
 +  All = "adv-all",
 +
 +  /** The Adventure Editor Store. */
 +  EditStore = "adv-edit-store",
 +
 +  /** The Main Editor View */
 +  MainEditor = "adv-maineditor",
 +[...]
 +}
 +
 +/** Messages of these msgTypes are requests adressed to a View. */
 +export enum AdvEditRequests {
 +  /** 
 +   * The message requests the Adventure currently being edited.
 +   * The Owner of the Adventure Edit Store should respond with a CurrentAdventure indication to the requester.
 +   * Target: AdvEditViews.EditStore
 +   * No Payload.
 +   */
 +  RequestCurrentAdventure = "adv-req-adventure",
 +[...]
 +}
 +
 +/** Messages of these msgTypes are event-like messages that can interest different Views. */
 +export enum AdvEditIndications {
 +
 +  /** The message payload contains the Adventure newly selected. */
 +  CurrentAdventure = "adv-ind-adventure",
 +[...]
 +}
 +
 +/**
 + * Payload of AdventureAssetCount and UpdateAssetCount
 + */
 +export interface AdventureAssetCountUpdate {
 +  assetId: string,
 +  value: number
 +}
 +
 +
 +
 +
 +
 +
 +</code>
  
en/outskirts/mages-peaks/detach-windows.1712680893.txt.gz · Last modified: 2024/10/28 08:00 (external edit)