@eluvio/elv-client-js 3.2.4 → 3.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ElvClient-min.js +15 -11
- package/dist/ElvClient-node-min.js +17 -13
- package/dist/ElvFrameClient-min.js +12 -8
- package/dist/ElvPermissionsClient-min.js +13 -9
- package/dist/ElvWalletClient-min.js +58 -0
- package/dist/ElvWalletClient-node-min.js +78 -0
- package/dist/src/AuthorizationClient.js +2248 -1990
- package/dist/src/ContentObjectVerification.js +164 -173
- package/dist/src/Crypto.js +376 -324
- package/dist/src/ElvClient.js +1185 -1019
- package/dist/src/ElvWallet.js +119 -95
- package/dist/src/EthClient.js +1040 -896
- package/dist/src/FrameClient.js +331 -300
- package/dist/src/HttpClient.js +153 -147
- package/dist/src/Id.js +1 -3
- package/dist/src/PermissionsClient.js +1294 -1168
- package/dist/src/RemoteSigner.js +263 -211
- package/dist/src/UserProfileClient.js +1164 -1023
- package/dist/src/Utils.js +229 -184
- package/dist/src/client/ABRPublishing.js +895 -858
- package/dist/src/client/AccessGroups.js +1102 -959
- package/dist/src/client/ContentAccess.js +3724 -3431
- package/dist/src/client/ContentManagement.js +2252 -2068
- package/dist/src/client/Contracts.js +647 -563
- package/dist/src/client/Files.js +1886 -1757
- package/dist/src/client/NFT.js +126 -112
- package/dist/src/client/NTP.js +478 -422
- package/dist/src/index.js +11 -0
- package/dist/src/marketplaceClient/ClientMethods.js +1918 -0
- package/dist/src/marketplaceClient/Configuration.js +29 -0
- package/dist/src/marketplaceClient/Utils.js +304 -0
- package/dist/src/marketplaceClient/index.js +1553 -0
- package/dist/src/walletClient/ClientMethods.js +1978 -0
- package/dist/src/walletClient/Configuration.js +29 -0
- package/dist/src/walletClient/Utils.js +304 -0
- package/dist/src/walletClient/index.js +1571 -0
- package/package.json +8 -4
- package/src/ElvClient.js +4 -1
- package/src/Utils.js +22 -4
- package/src/index.js +7 -0
- package/src/walletClient/ClientMethods.js +1048 -0
- package/src/walletClient/Configuration.js +40 -0
- package/src/walletClient/README.md +185 -0
- package/src/walletClient/Utils.js +234 -0
- package/src/walletClient/index.js +884 -0
- package/testScripts/TestMarketplaceClient.js +25 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
let WalletConfiguration = {
|
|
2
|
+
demo: {
|
|
3
|
+
configUrl: "https://demov3.net955210.contentfabric.io/config",
|
|
4
|
+
staging: {
|
|
5
|
+
siteId: "iq__2gkNh8CCZqFFnoRpEUmz7P3PaBQG",
|
|
6
|
+
purchaseMode: "develop",
|
|
7
|
+
appUrl: "https://core.test.contentfabric.io/wallet-demo"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
main: {
|
|
11
|
+
configUrl: "https://main.net955305.contentfabric.io/config",
|
|
12
|
+
staging: {
|
|
13
|
+
siteId: "iq__inauxD1KLyKWPHargCWjdCh2ayr",
|
|
14
|
+
purchaseMode: "production",
|
|
15
|
+
appUrl: "https://core.test.contentfabric.io/wallet"
|
|
16
|
+
},
|
|
17
|
+
production: {
|
|
18
|
+
siteId: "iq__suqRJUt2vmXsyiWS5ZaSGwtFU9R",
|
|
19
|
+
purchaseMode: "production",
|
|
20
|
+
appUrl: "https://wallet.contentfabric.io"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
__MARKETPLACE_ORDER: [
|
|
24
|
+
"dolly-marketplace",
|
|
25
|
+
"oc-marketplace",
|
|
26
|
+
"maskverse-marketplace",
|
|
27
|
+
"emp-marketplace",
|
|
28
|
+
"microsoft",
|
|
29
|
+
"indieflix-marketplace",
|
|
30
|
+
"angels-airwaves-marketplace"
|
|
31
|
+
]
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// No production environment on demo
|
|
35
|
+
WalletConfiguration.demo.production = WalletConfiguration.demo.staging;
|
|
36
|
+
|
|
37
|
+
// Allow demo to be referred to as demov3
|
|
38
|
+
WalletConfiguration.demov3 = WalletConfiguration.demo;
|
|
39
|
+
|
|
40
|
+
module.exports = WalletConfiguration;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Eluvio Wallet Client
|
|
2
|
+
|
|
3
|
+
This is a standalone client for using Eluvio Media Wallet functionality
|
|
4
|
+
|
|
5
|
+
For information about the embedded wallet app frame client, see [here](https://eluv-io.github.io/elv-media-wallet/ElvWalletFrameClient.html)
|
|
6
|
+
|
|
7
|
+
## Initializing the Client
|
|
8
|
+
|
|
9
|
+
Initializing the client is as simple as calling the static Initialize method with the network (main or demo) and the mode (production or staging) the client should operate upon, as well as (optionally) the marketplace to associate the client with.
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
await ElvWalletClient.Initialize({
|
|
13
|
+
network: "main | demo",
|
|
14
|
+
mode: "production | staging",
|
|
15
|
+
marketplaceParams: {
|
|
16
|
+
tenantSlug,
|
|
17
|
+
marketplaceSlug
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Referencing Marketplaces
|
|
23
|
+
|
|
24
|
+
Many methods, including the Initialize method, take a parameter called `marketplaceParams`. This parameter should be specified in one of the following formats:
|
|
25
|
+
|
|
26
|
+
Specify the tenant slug and marketplace slug corresponding to your marketplace.
|
|
27
|
+
```javascript
|
|
28
|
+
{
|
|
29
|
+
tenantSlug: "<tenant-slug>",
|
|
30
|
+
marketplaceSlug: "<marketplace-slug>"
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Specify the object ID of the marketplace
|
|
35
|
+
```javascript
|
|
36
|
+
{ marketplaceId: "iq__abc123" }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Specify a version hash of the marketplace
|
|
40
|
+
```javascript
|
|
41
|
+
{ marketplaceHash: "hq__abc123" }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Handling Login
|
|
45
|
+
|
|
46
|
+
The wallet client make it simple to log in with the Eluvio Media Wallet. However, if you are also using the frame client to embed the wallet application, extra care must be taken to ensure the login flow is handled correctly and the wallet client and frame have parity in their authorization states.
|
|
47
|
+
|
|
48
|
+
<div id="wallet-client" />
|
|
49
|
+
|
|
50
|
+
### Wallet Client
|
|
51
|
+
|
|
52
|
+
##### Redirect Flow
|
|
53
|
+
```javascript
|
|
54
|
+
walletClient.LogIn({
|
|
55
|
+
method: "redirect",
|
|
56
|
+
callbackUrl: <https://your-domain.com/callback>
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Upon login, the browser will return to the callbackUrl with the authorization token as a url parameter (`elvToken`). **Initializing the client will automatically pull the token out of the URL parameters and log in.**
|
|
61
|
+
|
|
62
|
+
If you don't want to initialize the client in the callback URL, you can save this token and later set it in the client using the `Authenticate` method.
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
66
|
+
const clientAuthToken = searchParams.get("elvToken");
|
|
67
|
+
|
|
68
|
+
...
|
|
69
|
+
|
|
70
|
+
walletClient.Authorize({token: clientAuthToken});
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
##### Popup Flow
|
|
75
|
+
```javascript
|
|
76
|
+
try {
|
|
77
|
+
await walletClient.LogIn({
|
|
78
|
+
method: "popup"
|
|
79
|
+
})
|
|
80
|
+
} catch(error) {
|
|
81
|
+
// User closed popup
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
##### Additional Options
|
|
86
|
+
|
|
87
|
+
The `clear` parameter in the LogIn method will ensure that the user does the full log in flow, even if they are already logged in to the Eluvio Media Wallet application. This is important to specify if the user has logged out from your application, as they will otherwise still be logged in to the Media Wallet and the login flow will simply authorize them as the same user.
|
|
88
|
+
|
|
89
|
+
The `provider` parameter will automatically proceed to log in with the specified provider instead of presenting the usual login screen and waiting for the user to choose. For example, you can specify that the login flow should automatically prompt for Metamask login or proceed to the OAuth login flow. For the OAuth flow, the `mode` parameter can be used to proceed to the `login` flow or the `create` account flow.
|
|
90
|
+
|
|
91
|
+
##### Saving Authorization
|
|
92
|
+
|
|
93
|
+
By default, the client will save the authorization token in localstorage, if available. If you prefer to handle storing the authorization token differently, you can specify that the client should not save the token when initializing the client:
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
const walletClient = ElvWalletClient.Initialize({
|
|
97
|
+
...,
|
|
98
|
+
storeAuthToken: false
|
|
99
|
+
})
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The authorization token can be retrieved using `walletClient.ClientAuthToken()`, which can then be used later in the `Authenticate` method.
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
### Frame Client
|
|
106
|
+
|
|
107
|
+
If you only want to embed the Eluvio Media Wallet application without using the Wallet Client and you don't want to implement a custom login screen, no special effort is needed. The wallet app UI will handle login natively.
|
|
108
|
+
|
|
109
|
+
You can use event listeners with the frame client to detect when the user logs in or out:
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
frameClient.AddEventListener(frameClient.EVENTS.LOG_IN, ({address}) => { ... });
|
|
113
|
+
|
|
114
|
+
frameClient.AddEventListener(frameClient.EVENTS.LOG_OUT, () => { ... });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Custom Login UI For Embedded Wallet App / Using Both Wallet Client and Frame Client
|
|
119
|
+
|
|
120
|
+
If you want to implement a custom login screen for the embedded wallet application, or if you want to use both the wallet and frame clients in the same application, some care must be taken to ensure the login flow is handled correctly and the wallet client and frame have parity in their authorization states.
|
|
121
|
+
|
|
122
|
+
First, **login should be handled by the Wallet Client only**. The wallet client does not have to deal with the limitations of iframes, and the wallet client is allowed access to the user's authorization token, which can be passed to the frame client to authorize the embedded application.
|
|
123
|
+
|
|
124
|
+
Authorization can be passed to the embedded frame, but **cannot be retrieved** from it. Because of this, logging in via the embedded application would mean the user is logged in in the frame, but the wallet client in the containing application has no access to that user's authorization.
|
|
125
|
+
|
|
126
|
+
Here's how to handle this case:
|
|
127
|
+
|
|
128
|
+
##### Perform Login Using the Wallet Client
|
|
129
|
+
|
|
130
|
+
See the [Wallet Client](#wallet-client) login section for details about how to handle the login flow with the wallet client.
|
|
131
|
+
|
|
132
|
+
##### Capture Login from the Frame
|
|
133
|
+
|
|
134
|
+
When initializing the frame client, specify the `captureLogin` option. This will cause login prompts (e.g. user clicks log in, user tries to perform/access something that requires login, etc.) to emit an event instead of presenting the login form in the frame.
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
const frameClient = await ElvWalletFrameClient.InitializeFrame({
|
|
138
|
+
...,
|
|
139
|
+
captureLogin: true
|
|
140
|
+
})
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
You can then listen for that event to present your own login screen, or simply trigger the login flow with the Wallet Client.
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
frameClient.AddEventListener(
|
|
147
|
+
frameClient.EVENTS.LOG_IN_REQUESTED,
|
|
148
|
+
() => {
|
|
149
|
+
// Show your login screen or log in with wallet client
|
|
150
|
+
// ShowLogin()
|
|
151
|
+
// walletClient.LogIn({...});
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
##### Pass Authorization Token to Frame Client
|
|
157
|
+
|
|
158
|
+
When the login flow has completed with the wallet client, pass the authorization token to the embedded application:
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
if(walletClient.ClientAuthToken()) {
|
|
162
|
+
await frameClient.LogIn({clientAuthToken: walletClient.ClientAuthToken()})
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
##### Handle Log Out in Both Clients
|
|
167
|
+
|
|
168
|
+
After the user is logged in with the frame client, you can present an option to log out. Be sure this logs out both the wallet client and the frame client:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
function LogOutFromMyApp() {
|
|
172
|
+
walletClient.LogOut();
|
|
173
|
+
frameClient.LogOut();
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Additionally, the user may log out from the embedded application. Use an event listener in the frame client to handle this and log out from the wallet client:
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
frameClient.AddEventListener(
|
|
181
|
+
frameClient.EVENTS.LOG_OUT,
|
|
182
|
+
() => LogOutFromMyApp()
|
|
183
|
+
);
|
|
184
|
+
```
|
|
185
|
+
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
const Utils = require("../Utils");
|
|
2
|
+
|
|
3
|
+
const RarityToPercentage = (rarity) => {
|
|
4
|
+
if(!rarity) {
|
|
5
|
+
return "";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
rarity = rarity.toString();
|
|
9
|
+
|
|
10
|
+
if(!rarity.includes("/")) {
|
|
11
|
+
return rarity;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const [ numerator, denominator ] = rarity.split("/");
|
|
15
|
+
let percentage = 100 * parseInt(numerator) / parseInt(denominator);
|
|
16
|
+
|
|
17
|
+
if(percentage < 1) {
|
|
18
|
+
percentage = percentage.toFixed(2);
|
|
19
|
+
} else {
|
|
20
|
+
percentage = percentage.toFixed(1).toString().replace(".0", "");
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return percentage;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Format NFT or listing result into consistent format
|
|
27
|
+
const FormatNFTDetails = function(entry) {
|
|
28
|
+
const isListing = !!entry.id;
|
|
29
|
+
|
|
30
|
+
const metadata = (isListing ? entry.nft : entry.meta) || {};
|
|
31
|
+
const info = (isListing ? entry.info : entry);
|
|
32
|
+
|
|
33
|
+
let details = {
|
|
34
|
+
USDCAccepted: !!(entry.accepts || []).find(entry => entry.type === "sol"),
|
|
35
|
+
USDCOnly: ((entry.accepts || []).find(entry => entry.type === "sol") || {}).preferred,
|
|
36
|
+
TenantId: entry.tenant || entry.tenant_id,
|
|
37
|
+
ContractAddr: info.contract_addr,
|
|
38
|
+
ContractId: `ictr${Utils.AddressToHash(info.contract_addr)}`,
|
|
39
|
+
ContractName: info.contract_name,
|
|
40
|
+
Cap: info.cap,
|
|
41
|
+
TokenIdStr: info.token_id_str,
|
|
42
|
+
TokenUri: info.token_uri,
|
|
43
|
+
TokenOrdinal: info.ordinal,
|
|
44
|
+
TokenHold: info.hold,
|
|
45
|
+
TokenHoldDate: info.hold ? new Date(parseInt(info.hold) * 1000) : undefined,
|
|
46
|
+
TokenOwner: info.token_owner ? Utils.FormatAddress(info.token_owner) : "",
|
|
47
|
+
VersionHash: (info.token_uri || "").split("/").find(s => (s || "").startsWith("hq__")),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if(isListing) {
|
|
51
|
+
details = {
|
|
52
|
+
...details,
|
|
53
|
+
// Listing specific fields
|
|
54
|
+
ListingId: entry.id,
|
|
55
|
+
CreatedAt: entry.created * 1000,
|
|
56
|
+
UpdatedAt: entry.updated * 1000,
|
|
57
|
+
CheckoutLockedUntil: entry.checkout ? entry.checkout * 1000 : undefined,
|
|
58
|
+
SellerAddress: Utils.FormatAddress(entry.seller),
|
|
59
|
+
Price: entry.price,
|
|
60
|
+
Fee: entry.fee
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
metadata,
|
|
66
|
+
details
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
exports.FormatNFTDetails = FormatNFTDetails;
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
const FormatNFTMetadata = function(nft) {
|
|
74
|
+
nft.formatted = true;
|
|
75
|
+
|
|
76
|
+
// Surface relevant details to top level
|
|
77
|
+
nft.contractAddress = nft.details.ContractAddr;
|
|
78
|
+
nft.contractId = nft.details.ContractId;
|
|
79
|
+
nft.tokenId = nft.details.TokenIdStr;
|
|
80
|
+
nft.name = nft.metadata.display_name;
|
|
81
|
+
|
|
82
|
+
if(nft.details.ListingId) {
|
|
83
|
+
nft.listingId = nft.details.ListingId;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Format traits
|
|
87
|
+
const FILTERED_ATTRIBUTES = ["Content Fabric Hash", "Creator", "Total Minted Supply"];
|
|
88
|
+
nft.metadata.attributes = (nft.metadata.attributes || [])
|
|
89
|
+
.filter(attribute => attribute && !FILTERED_ATTRIBUTES.includes(attribute.trait_type))
|
|
90
|
+
.map(trait => ({...trait, name: trait.trait_type, rarity_percent: RarityToPercentage(trait.rarity)}));
|
|
91
|
+
|
|
92
|
+
// Generate embed URLs for additional media
|
|
93
|
+
if(nft.metadata.additional_media) {
|
|
94
|
+
nft.metadata.additional_media = nft.metadata.additional_media.map(media => {
|
|
95
|
+
try {
|
|
96
|
+
// Generate embed URLs for additional media
|
|
97
|
+
const mediaType = (media.media_type || "").toLowerCase();
|
|
98
|
+
|
|
99
|
+
if(mediaType === "image") {
|
|
100
|
+
return {
|
|
101
|
+
...media,
|
|
102
|
+
embed_url: media.media_file.url
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let embedUrl = new URL("https://embed.v3.contentfabric.io");
|
|
107
|
+
embedUrl.searchParams.set("p", "");
|
|
108
|
+
embedUrl.searchParams.set("net", rootStore.network === "demo" ? "demo" : "main");
|
|
109
|
+
embedUrl.searchParams.set("ath", rootStore.authToken);
|
|
110
|
+
|
|
111
|
+
if(mediaType === "video") {
|
|
112
|
+
embedUrl.searchParams.set("vid", LinkTargetHash(media.media_link));
|
|
113
|
+
embedUrl.searchParams.set("ct", "h");
|
|
114
|
+
embedUrl.searchParams.set("ap", "");
|
|
115
|
+
} else if(mediaType === "ebook") {
|
|
116
|
+
embedUrl.searchParams.set("type", "ebook");
|
|
117
|
+
embedUrl.searchParams.set("vid", media.media_file["."].container);
|
|
118
|
+
embedUrl.searchParams.set("murl", btoa(media.media_file.url));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
...media,
|
|
123
|
+
embed_url: embedUrl.toString()
|
|
124
|
+
};
|
|
125
|
+
} catch(error) {
|
|
126
|
+
return media;
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Generate embed URLs for pack opening animations
|
|
132
|
+
["open_animation", "open_animation__mobile", "reveal_animation", "reveal_animation_mobile"].forEach(key => {
|
|
133
|
+
try {
|
|
134
|
+
if(nft.metadata.pack_options && nft.metadata.pack_options[key]) {
|
|
135
|
+
let embedUrl = new URL("https://embed.v3.contentfabric.io");
|
|
136
|
+
embedUrl.searchParams.set("p", "");
|
|
137
|
+
embedUrl.searchParams.set("net", rootStore.network === "demo" ? "demo" : "main");
|
|
138
|
+
embedUrl.searchParams.set("ath", rootStore.authToken || rootStore.staticToken);
|
|
139
|
+
embedUrl.searchParams.set("vid", LinkTargetHash(nft.metadata.pack_options[key]));
|
|
140
|
+
embedUrl.searchParams.set("ap", "");
|
|
141
|
+
|
|
142
|
+
if(!key.startsWith("reveal")) {
|
|
143
|
+
embedUrl.searchParams.set("m", "");
|
|
144
|
+
embedUrl.searchParams.set("lp", "");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
nft.metadata.pack_options[`${key}_embed_url`] = embedUrl.toString();
|
|
148
|
+
}
|
|
149
|
+
// eslint-disable-next-line no-empty
|
|
150
|
+
} catch(error) {}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
return nft;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
exports.FormatNFTMetadata = FormatNFTMetadata;
|
|
157
|
+
|
|
158
|
+
exports.FormatNFT = function (item) {
|
|
159
|
+
return FormatNFTMetadata(FormatNFTDetails(item));
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
exports.LinkTargetHash = function(link) {
|
|
164
|
+
if(!link) { return; }
|
|
165
|
+
|
|
166
|
+
if(link["."] && link["."].source) {
|
|
167
|
+
return link["."].source;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if(link["/"] && link["/"].startsWith("/qfab/")) {
|
|
171
|
+
return link["/"].split("/").find(segment => segment.startsWith("hq__"));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if(link["."] && link["."].container) {
|
|
175
|
+
return link["."].container;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
// https://stackoverflow.com/questions/4068373/center-a-popup-window-on-screen
|
|
180
|
+
const Popup = ({url, title, w, h}) => {
|
|
181
|
+
// Fixes dual-screen position
|
|
182
|
+
const dualScreenLeft = window.screenLeft || window.screenX;
|
|
183
|
+
const dualScreenTop = window.screenTop || window.screenY;
|
|
184
|
+
|
|
185
|
+
const width = window.innerWidth || document.documentElement.clientWidth || screen.width;
|
|
186
|
+
const height = window.innerHeight || document.documentElement.clientHeight || screen.height;
|
|
187
|
+
|
|
188
|
+
const systemZoom = width / window.screen.availWidth;
|
|
189
|
+
const left = (width - w) / 2 / systemZoom + dualScreenLeft;
|
|
190
|
+
const top = (height - h) / 2 / systemZoom + dualScreenTop;
|
|
191
|
+
const newWindow = window.open(url, title,
|
|
192
|
+
`
|
|
193
|
+
width=${w / systemZoom},
|
|
194
|
+
height=${h / systemZoom},
|
|
195
|
+
top=${top},
|
|
196
|
+
left=${left}
|
|
197
|
+
`
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
if(window.focus) newWindow.focus();
|
|
201
|
+
|
|
202
|
+
return newWindow;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
exports.ActionPopup = async ({mode="tab", url, onMessage, onCancel}) => {
|
|
206
|
+
await new Promise(resolve => {
|
|
207
|
+
const newWindow = mode === "popup" ?
|
|
208
|
+
Popup({url, title: "Eluvio Media Wallet", w: 500, h: 850}) :
|
|
209
|
+
window.open(url);
|
|
210
|
+
|
|
211
|
+
const closeCheck = setInterval(async () => {
|
|
212
|
+
if(newWindow.closed) {
|
|
213
|
+
clearInterval(closeCheck);
|
|
214
|
+
|
|
215
|
+
if(onCancel) {
|
|
216
|
+
await onCancel();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
resolve();
|
|
220
|
+
}
|
|
221
|
+
}, 1000);
|
|
222
|
+
|
|
223
|
+
window.addEventListener("message", async event => {
|
|
224
|
+
await onMessage(
|
|
225
|
+
event,
|
|
226
|
+
() => {
|
|
227
|
+
clearInterval(closeCheck);
|
|
228
|
+
newWindow.close();
|
|
229
|
+
resolve();
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
};
|