Skip to content

Commit

Permalink
Merge pull request #49 from multiversx/development
Browse files Browse the repository at this point in the history
v0.3.0
  • Loading branch information
CiprianDraghici authored Aug 2, 2024
2 parents 649398b + 47e0b47 commit 3a6cc91
Show file tree
Hide file tree
Showing 18 changed files with 4,888 additions and 68 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [[0.3.0](https://github.com/multiversx/mx-wallet-dapp/pull/48)] - 2024-08-02
- [Fix IFrame Provider issues](https://github.com/multiversx/mx-wallet-dapp/pull/47)
- [Implement IFrameProvider](https://github.com/multiversx/mx-wallet-dapp/pull/46)

## [[0.1.3](https://github.com/multiversx/mx-wallet-dapp/pull/45)] - 2024-05-29
- [Changed lit library to vanilla](https://github.com/multiversx/mx-wallet-dapp/pull/44)

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-web-wallet-cross-window-provider",
"version": "0.2.0",
"version": "0.3.0",
"description": "Signing provider for dApps: Cross Window",
"main": "out/index.js",
"types": "out/index.d.js",
Expand Down
46 changes: 26 additions & 20 deletions src/CrossWindowProvider/CrossWindowProvider.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { SignableMessage, Transaction } from '@multiversx/sdk-core';
import { safeWindow } from '@multiversx/sdk-dapp-utils/out/constants/crossWindowProviderConstants';
import {
CrossWindowProviderRequestEnums,
CrossWindowProviderResponseEnums,
SignMessageStatusEnum
} from '@multiversx/sdk-dapp-utils/out/enums/crossWindowProviderEnums';
import { WindowManager } from '../WindowManager';
import { safeWindow } from '../constants';
import {
ErrAccountNotConnected,
ErrCannotSignSingleTransaction,
ErrCouldNotGuardTransactions,
ErrCouldNotLogin,
ErrCouldNotSignMessage,
ErrCouldNotSignTransactions,
ErrInstantiationFailed,
ErrProviderNotInitialized,
ErrTransactionCancelled
} from '../errors';
import { WindowManager } from '../WindowManager';
import { PopupConsent } from './PopupConsent';
import { confirmationDialogTag } from './PopupConsent/constants';

interface ICrossWindowWalletAccount {
export interface ICrossWindowWalletAccount {
address: string;
signature?: string;
multisig?: string;
Expand All @@ -29,46 +28,55 @@ interface ICrossWindowWalletAccount {

export class CrossWindowProvider {
public account: ICrossWindowWalletAccount = { address: '' };
private initialized = false;
private windowManager: WindowManager;
private static _instance: CrossWindowProvider = new CrossWindowProvider();
protected initialized = false;
protected windowManager: WindowManager;
protected static _instance: CrossWindowProvider | null = null;
private accessToken: string | undefined = undefined;
protected _shouldShowConsentPopup = false;

private constructor() {
if (CrossWindowProvider._instance) {
throw new ErrInstantiationFailed();
}
this.windowManager = WindowManager.getInstance();
CrossWindowProvider._instance = this;
public constructor() {
this.windowManager = new WindowManager();
}

public setShouldShowConsentPopup(shouldShow: boolean) {
this._shouldShowConsentPopup = shouldShow;
}

private ensureConnected() {
protected ensureConnected() {
if (!this.account.address) {
throw new ErrAccountNotConnected();
}
}

private disconnect() {
protected disconnect() {
this.account = { address: '' };
}

public static getInstance(): CrossWindowProvider {
if (!CrossWindowProvider._instance) {
CrossWindowProvider._instance = new CrossWindowProvider();
return CrossWindowProvider._instance;
}

return CrossWindowProvider._instance;
}

public getWindowManager(): WindowManager {
return this.windowManager;
}

public setAddress(address: string): CrossWindowProvider {
this.account.address = address;
return CrossWindowProvider._instance;
return this;
}

public setWalletUrl(url: string): CrossWindowProvider {
this.windowManager.setWalletUrl(url);
return CrossWindowProvider._instance;
return this;
}

public setWalletWindow(): Promise<void> {
return this.windowManager.setWalletWindow();
}

async init(): Promise<boolean> {
Expand Down Expand Up @@ -279,8 +287,6 @@ export class CrossWindowProvider {
CrossWindowProviderRequestEnums.cancelAction
);

console.log(isWalletOpened);

if (!isWalletOpened) {
return;
}
Expand All @@ -291,7 +297,7 @@ export class CrossWindowProvider {
});
}

protected async openPopupConsent(): Promise<boolean> {
public async openPopupConsent(): Promise<boolean> {
await import('./PopupConsent/PopupConsent');
const dialog = safeWindow.document?.createElement('div');
const document = safeWindow.document;
Expand Down
4 changes: 2 additions & 2 deletions src/CrossWindowProvider/PopupConsent/PopupConsent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { safeWindow } from '@multiversx/sdk-dapp-utils/out/constants/crossWindowProviderConstants';
import { safeWindow } from '../../constants';
import { confirmationDialogTag } from './constants';
import { getStyles } from './getStyles';

Expand Down Expand Up @@ -99,7 +99,7 @@ export class PopupConsent extends HTMLElement {
}
}

const customElements = safeWindow?.customElements;
const customElements = safeWindow.customElements;
if (customElements && !customElements.get(confirmationDialogTag)) {
customElements.define(confirmationDialogTag, PopupConsent);
}
5 changes: 2 additions & 3 deletions src/CrossWindowProvider/tests/Cancel.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getWalletWindowMock, WalletWindowMockType } from '../../test-utils';
import { WindowManager } from '../../WindowManager/WindowManager';
import { CrossWindowProvider } from '../CrossWindowProvider';

describe('CrossWindowProvider Login', () => {
Expand All @@ -9,11 +8,11 @@ describe('CrossWindowProvider Login', () => {

beforeEach(() => {
walletWindowMock = getWalletWindowMock();
WindowManager.getInstance().postMessage = jest
CrossWindowProvider.getInstance().getWindowManager().postMessage = jest
.fn()
.mockImplementation(() => undefined);

WindowManager.getInstance().isWalletOpened = jest
CrossWindowProvider.getInstance().getWindowManager().isWalletOpened = jest
.fn()
.mockImplementation(() => true);

Expand Down
3 changes: 1 addition & 2 deletions src/CrossWindowProvider/tests/Login.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getWalletWindowMock, WalletWindowMockType } from '../../test-utils';
import { WindowManager } from '../../WindowManager/WindowManager';
import { CrossWindowProvider } from '../CrossWindowProvider';

describe('CrossWindowProvider Login', () => {
Expand All @@ -9,7 +8,7 @@ describe('CrossWindowProvider Login', () => {

beforeEach(() => {
walletWindowMock = getWalletWindowMock();
WindowManager.getInstance().postMessage = jest
CrossWindowProvider.getInstance().getWindowManager().postMessage = jest
.fn()
.mockImplementation(() => ({
payload: {
Expand Down
5 changes: 2 additions & 3 deletions src/CrossWindowProvider/tests/Logout.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getWalletWindowMock, WalletWindowMockType } from '../../test-utils';
import { WindowManager } from '../../WindowManager/WindowManager';
import { CrossWindowProvider } from '../CrossWindowProvider';

describe('CrossWindowProvider', () => {
Expand All @@ -9,11 +8,11 @@ describe('CrossWindowProvider', () => {

beforeEach(() => {
walletWindowMock = getWalletWindowMock();
WindowManager.getInstance().postMessage = jest
CrossWindowProvider.getInstance().getWindowManager().postMessage = jest
.fn()
.mockImplementation(() => true);

WindowManager.getInstance().closeConnection = jest
CrossWindowProvider.getInstance().getWindowManager().closeConnection = jest
.fn()
.mockImplementation(() => true);

Expand Down
3 changes: 1 addition & 2 deletions src/CrossWindowProvider/tests/SignMessage.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { SignableMessage } from '@multiversx/sdk-core/out';
import { getWalletWindowMock, WalletWindowMockType } from '../../test-utils';
import { WindowManager } from '../../WindowManager/WindowManager';
import { CrossWindowProvider } from '../CrossWindowProvider';

describe('CrossWindowProvider Login', () => {
Expand All @@ -10,7 +9,7 @@ describe('CrossWindowProvider Login', () => {

beforeEach(() => {
walletWindowMock = getWalletWindowMock();
WindowManager.getInstance().postMessage = jest
CrossWindowProvider.getInstance().getWindowManager().postMessage = jest
.fn()
.mockImplementation(() => ({
payload: {
Expand Down
3 changes: 1 addition & 2 deletions src/CrossWindowProvider/tests/SignTransaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
getWalletWindowMock,
WalletWindowMockType
} from '../../test-utils';
import { WindowManager } from '../../WindowManager/WindowManager';
import { CrossWindowProvider } from '../CrossWindowProvider';

describe('CrossWindowProvider Login', () => {
Expand All @@ -22,7 +21,7 @@ describe('CrossWindowProvider Login', () => {
senderUsername: 'sender'
});

WindowManager.getInstance().postMessage = jest
CrossWindowProvider.getInstance().getWindowManager().postMessage = jest
.fn()
.mockImplementation(() => ({
payload: { data: [mockTransaction.toPlainObject()] }
Expand Down
124 changes: 124 additions & 0 deletions src/IFrameManager/IFrameProviderContentWindow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { safeDocument } from '../constants';
import {
bodyStyle,
collapsibleButtonStyle,
containerStyle,
headerStyle,
iframeStyle
} from './iframeManager.styles';

export class IFrameProviderContentWindow {
public iframe: HTMLIFrameElement;
public contentWindow: Window | null;
public walletAddress = '';

private readonly container: HTMLDivElement;
private readonly header: HTMLDivElement;
private readonly body: HTMLDivElement;

public constructor(props: { id: string; url: string; anchor?: HTMLElement }) {
const { id, url, anchor } = props;

this.container = safeDocument.createElement?.('div');
this.header = safeDocument.createElement?.('div');
this.body = safeDocument.createElement?.('div');
this.iframe = safeDocument.createElement?.('iframe');

this.buildWindow(id, url);
this.contentWindow = this.iframe.contentWindow;
this.setupWindow();

if (anchor) {
anchor.appendChild(this.container);
} else {
safeDocument.body?.appendChild?.(this.container);
}
}

private buildWindow(id: string, url: string) {
this.container.id = `window-container-${id}`;
this.iframe.id = id;
this.iframe.src = url;

this.container.style.cssText = containerStyle;
this.header.style.cssText = headerStyle;
this.body.style.cssText = bodyStyle;
this.iframe.style.cssText = iframeStyle;

this.buildContainer();
}

private buildHeader() {
const title = safeDocument.createElement?.('span');
title.innerText = 'Wallet';
this.header.appendChild(title);

const collapsibleButton = safeDocument.createElement?.('span');
collapsibleButton.id = 'iframe-toggle-button';
collapsibleButton.innerText = '-';
collapsibleButton.style.cssText = collapsibleButtonStyle;
collapsibleButton.onclick = () => {
this.body.style.visibility =
this.body.style.visibility === 'hidden' ? 'visible' : 'hidden';
this.container.style.height =
this.body.style.visibility === 'hidden' ? '50px' : '600px';
collapsibleButton.innerText =
this.body.style.visibility === 'hidden' ? '+' : '-';
this.container.style.setProperty(
'resize',
this.body.style.visibility === 'hidden' ? 'none' : 'both'
);
};
this.header.appendChild(collapsibleButton);
}

private buildContainer() {
this.container.appendChild(this.header);
this.container.appendChild(this.body);
this.body.appendChild(this.iframe);
this.buildHeader();
}

private setupWindow() {
this.iframe.onload = () => {
this.contentWindow = this.iframe.contentWindow;

const event = new CustomEvent('iframeWindowReady', {
detail: this.iframe
});

this.iframe.dispatchEvent(event);
};
}

public getContainer(): HTMLDivElement {
return this.container;
}

public getIframe(): HTMLIFrameElement {
return this.iframe;
}

public getContentWindow(): Window | null {
return this.contentWindow;
}

public setUrl(url: string): void {
this.iframe.setAttribute('src', url);
}

public remove(): void {
this.container.remove();
}

public setWalletVisible(visible: boolean): void {
this.container.style.visibility = visible ? 'visible' : 'hidden';
}

public addEventListener(
type: string,
listener: EventListenerOrEventListenerObject
): void {
this.iframe.addEventListener(type, listener);
}
}
Loading

0 comments on commit 3a6cc91

Please sign in to comment.