web-launch-kit 0.0.8 → 0.0.10
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/README.ko.md +37 -3
- package/README.md +37 -2
- package/dist/index.d.ts +3 -1
- package/dist/launch-kit.cjs +177 -59
- package/dist/launch-kit.cjs.map +1 -1
- package/dist/launch-kit.min.cjs +1 -1
- package/dist/launch-kit.min.cjs.map +1 -1
- package/dist/launch-kit.min.mjs +1 -1
- package/dist/launch-kit.min.mjs.map +1 -1
- package/dist/launch-kit.mjs +177 -59
- package/dist/launch-kit.mjs.map +1 -1
- package/dist/launch-kit.umd.js +177 -59
- package/dist/launch-kit.umd.js.map +1 -1
- package/dist/launch-kit.umd.min.js +1 -1
- package/dist/launch-kit.umd.min.js.map +1 -1
- package/dist/utils/get-id.d.ts +2 -2
- package/package.json +2 -2
package/README.ko.md
CHANGED
|
@@ -34,7 +34,7 @@ npm install web-launch-kit
|
|
|
34
34
|
| `LaunchKit.filepicker(options?)` | `Promise<File[]>` | 파일 또는 디렉터리 선택 (File System Access API, input 폴백) |
|
|
35
35
|
| `LaunchKit.setting(type?)` | `Promise<void>` | 지원되는 환경에서 시스템 설정 화면 열기 |
|
|
36
36
|
| `LaunchKit.escapeWebview(options?)` | `Promise<void>` | URL(기본값은 현재 페이지)을 외부 브라우저에서 다시 열어 인앱 웹뷰에서 탈출 |
|
|
37
|
-
| `LaunchKit.utils` | object | `canOpenIntent` / `canOpenUniversal` / `canOpenSetting` / `canEscapeWebview` getter와 비동기 `getTrackId` / `getProductId` |
|
|
37
|
+
| `LaunchKit.utils` | object | `canOpenIntent` / `canOpenUniversal` / `canOpenSetting` / `canEscapeWebview` getter와 비동기 `getTrackId(bundleId)` / `getProductId(packageFamilyName, language?, country?)` |
|
|
38
38
|
|
|
39
39
|
`AppOpenedBy`는 `"scheme"`, `"universal"`, `"intent"`, `"fallback"`, `"store"` 중 하나입니다.
|
|
40
40
|
|
|
@@ -147,6 +147,18 @@ flowchart TD
|
|
|
147
147
|
M2 --> M3["Priority list:<br/>scheme ⭢ fallback<br/>⭢ app store ⭢ web store (by trackId)"]
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
+
subgraph LOC["web store · createWebStoreURL"]
|
|
151
|
+
L1{"country given?"}
|
|
152
|
+
L1 -->|yes| L3["Play · MS Store: hl / gl parameters<br/>App Store: /country/ path + l parameter"]
|
|
153
|
+
L1 -->|no| L2["Derive from language:<br/>region subtag ⭢ Intl.Locale.maximize()<br/>⭢ omit (store geolocation)"]
|
|
154
|
+
L2 --> L3
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
A5 -.->|"web store"| L1
|
|
158
|
+
I3 -.->|"web store"| L1
|
|
159
|
+
W3 -.->|"web store"| L1
|
|
160
|
+
M3 -.->|"web store"| L1
|
|
161
|
+
|
|
150
162
|
AND --> P
|
|
151
163
|
IOS --> P
|
|
152
164
|
WIN --> P
|
|
@@ -191,6 +203,8 @@ const openedBy = await LaunchKit.app({
|
|
|
191
203
|
packageName: 'com.example.myapp',
|
|
192
204
|
allowAppStore: true,
|
|
193
205
|
allowWebStore: true,
|
|
206
|
+
language: 'ko', // 웹스토어 UI 언어
|
|
207
|
+
country: 'KR', // 생략하면 language 에서 유도됩니다 (region 서브태그 → Intl.Locale.maximize())
|
|
194
208
|
},
|
|
195
209
|
ios: {
|
|
196
210
|
universal: 'https://example.com/profile/42',
|
|
@@ -206,7 +220,17 @@ console.log(openedBy) // "universal" | "scheme" | "intent" | "fallback" | "store
|
|
|
206
220
|
플랫폼별 필드: 안드로이드는 `intent` / `scheme` / `packageName` / `fallback` /
|
|
207
221
|
`allowIntent`(scheme ⇄ intent는 서로에게서 유도됩니다), iOS는 `universal` / `scheme` / `bundleId` / `trackId`, Windows는
|
|
208
222
|
`scheme` / `packageFamilyName` / `productId`, macOS는 `scheme` / `bundleId` / `trackId`를
|
|
209
|
-
받습니다. 모두 `fallback`, `timeout`, `allowAppStore`, `allowWebStore
|
|
223
|
+
받습니다. 모두 `fallback`, `timeout`, `allowAppStore`, `allowWebStore`, `language`,
|
|
224
|
+
`country`를 함께 받습니다.
|
|
225
|
+
|
|
226
|
+
`language` / `country`는 **웹스토어** 후보에만 적용됩니다 — Google Play와 Microsoft
|
|
227
|
+
Store에서는 `hl` / `gl` 파라미터, App Store에서는 국가 경로 세그먼트와 `l` 파라미터로
|
|
228
|
+
반영됩니다. `country`를 생략하면 `language`에서 유도합니다. region 서브태그가 우선하고
|
|
229
|
+
(`ko-KR` → `KR`), 없으면 런타임이 지원하는 환경에서 `Intl.Locale.maximize()`를
|
|
230
|
+
사용합니다. 둘 다 실패하면 국가를 붙이지 않고 스토어의 자체 위치 추정에 맡깁니다 —
|
|
231
|
+
잘못된 국가는 "이 지역에서 사용할 수 없음" 페이지로 이어질 수 있어 생략이 안전한
|
|
232
|
+
기본값입니다. 네이티브 앱스토어 스킴(`market://`, `itms-apps://` 등)은 건드리지
|
|
233
|
+
않습니다. OS가 기기 로케일로 알아서 렌더링합니다.
|
|
210
234
|
|
|
211
235
|
`onAttempt`는 각 후보 시도 직전에 동기로 호출됩니다. 대기 UI를 여기서 그리세요 — 그러지
|
|
212
236
|
않으면 타임아웃 동안 화면에 아무 변화가 없습니다.
|
|
@@ -353,7 +377,12 @@ Meta 계열 웹뷰(Facebook, Instagram) 안에서는 차단됩니다. http(s) UR
|
|
|
353
377
|
- **`utils.getTrackId` / `getProductId`는 비동기**이고 1시간 캐시됩니다. 페이지 초기화 때
|
|
354
378
|
한 번 호출해두면 `app()`이 id를 인라인으로 조회하지 않습니다. `app()`은 사용자 제스처 안에서
|
|
355
379
|
실행돼야 하므로, id가 없으면 `await`으로 user activation을 잃는 대신 동기로 조회합니다.
|
|
356
|
-
`trackId` / `productId`를 직접 주면 조회 자체가 생략됩니다.
|
|
380
|
+
`trackId` / `productId`를 직접 주면 조회 자체가 생략됩니다. `getProductId`는 선택적
|
|
381
|
+
`language` / `country`를 추가로 받아 Microsoft 카탈로그의 언어와 마켓을 고정합니다 —
|
|
382
|
+
조회 성공 여부가 마켓에 따라 달라질 수 있으니 `app()`에 넘길 값과 동일하게 주어야
|
|
383
|
+
프리워밍된 캐시가 같은 마켓을 커버합니다. 생략하면 웹스토어 country와 같은 방식으로
|
|
384
|
+
유도됩니다: 명시 region 서브태그 → 런타임이 지원하면 `Intl.Locale.maximize()` →
|
|
385
|
+
`en-US` / `US`. `getTrackId`는 로케일이 필요 없습니다 — iTunes lookup은 마켓과 무관합니다.
|
|
357
386
|
- **스토어 id 조회는 외부 API에 의존합니다**(iTunes Lookup, Microsoft display catalog).
|
|
358
387
|
1시간 캐시되며 실패는 예외가 아니라 `undefined`로 resolve됩니다.
|
|
359
388
|
- **인앱 브라우저는 후보 단위로 걸러집니다.** 실행이 차단된 웹뷰(WeChat, QQ, Qzone, Baidu,
|
|
@@ -371,6 +400,11 @@ Meta 계열 웹뷰(Facebook, Instagram) 안에서는 차단됩니다. http(s) UR
|
|
|
371
400
|
- **웹 폴백은 내비게이션 시점에 resolve합니다.** `fallback`이나 웹스토어 후보는 문서 자체를
|
|
372
401
|
교체하므로 기다릴 앱 전환이 없습니다. 이동을 시작하는 즉시 resolve하며, 이동이 성공한 뒤에
|
|
373
402
|
reject되는 일이 없습니다.
|
|
403
|
+
- **예상 밖의 내비게이션도 결과로 확정됩니다.** 앱이 설치되지 않은 유니버설 링크, 브라우저
|
|
404
|
+
폴백이 실행된 intent처럼 실제 페이지 이동으로 바뀌는 후보는 타임아웃 전에 문서가 내려가
|
|
405
|
+
결과가 유실됐습니다. 이제 `pagehide`가 해당 후보를 resolve합니다. 앱 전환은 `pagehide` 없이
|
|
406
|
+
`hidden`만 발생하므로 두 경우는 구분됩니다. resolve는 언로드 중에 실행되며, 그 시점에도
|
|
407
|
+
`sendBeacon`은 정상 전송됩니다.
|
|
374
408
|
|
|
375
409
|
## 브라우저 지원
|
|
376
410
|
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ The bundle is self-contained (OS/locale detection is inlined) — no peer script
|
|
|
35
35
|
| `LaunchKit.filepicker(options?)` | `Promise<File[]>` | Pick files or a directory (File System Access API, with input fallback) |
|
|
36
36
|
| `LaunchKit.setting(type?)` | `Promise<void>` | Open a system-settings pane where supported |
|
|
37
37
|
| `LaunchKit.escapeWebview(options?)` | `Promise<void>` | Reopen a URL (the current page by default) in the external browser, escaping an in-app webview |
|
|
38
|
-
| `LaunchKit.utils` | object | `canOpenIntent` / `canOpenUniversal` / `canOpenSetting` / `canEscapeWebview` getters, plus async `getTrackId` / `getProductId` |
|
|
38
|
+
| `LaunchKit.utils` | object | `canOpenIntent` / `canOpenUniversal` / `canOpenSetting` / `canEscapeWebview` getters, plus async `getTrackId(bundleId)` / `getProductId(packageFamilyName, language?, country?)` |
|
|
39
39
|
|
|
40
40
|
`AppOpenedBy` is one of: `"scheme"`, `"universal"`, `"intent"`, `"fallback"`, `"store"`.
|
|
41
41
|
|
|
@@ -149,6 +149,18 @@ flowchart TD
|
|
|
149
149
|
M2 --> M3["Priority list:<br/>scheme ⭢ fallback<br/>⭢ app store ⭢ web store (by trackId)"]
|
|
150
150
|
end
|
|
151
151
|
|
|
152
|
+
subgraph LOC["web store · createWebStoreURL"]
|
|
153
|
+
L1{"country given?"}
|
|
154
|
+
L1 -->|yes| L3["Play · MS Store: hl / gl parameters<br/>App Store: /country/ path + l parameter"]
|
|
155
|
+
L1 -->|no| L2["Derive from language:<br/>region subtag ⭢ Intl.Locale.maximize()<br/>⭢ omit (store geolocation)"]
|
|
156
|
+
L2 --> L3
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
A5 -.->|"web store"| L1
|
|
160
|
+
I3 -.->|"web store"| L1
|
|
161
|
+
W3 -.->|"web store"| L1
|
|
162
|
+
M3 -.->|"web store"| L1
|
|
163
|
+
|
|
152
164
|
AND --> P
|
|
153
165
|
IOS --> P
|
|
154
166
|
WIN --> P
|
|
@@ -193,6 +205,8 @@ const openedBy = await LaunchKit.app({
|
|
|
193
205
|
packageName: 'com.example.myapp',
|
|
194
206
|
allowAppStore: true,
|
|
195
207
|
allowWebStore: true,
|
|
208
|
+
language: 'ko', // web-store UI language
|
|
209
|
+
country: 'KR', // omit to derive from language (region subtag → Intl.Locale.maximize())
|
|
196
210
|
},
|
|
197
211
|
ios: {
|
|
198
212
|
universal: 'https://example.com/profile/42',
|
|
@@ -209,7 +223,17 @@ Per-platform fields: Android accepts `intent` / `scheme` / `packageName` / `fall
|
|
|
209
223
|
`allowIntent` (scheme ⇄ intent are derived from each other); iOS accepts `universal` / `scheme` /
|
|
210
224
|
`bundleId` / `trackId`; Windows accepts `scheme` / `packageFamilyName` / `productId`;
|
|
211
225
|
macOS accepts `scheme` / `bundleId` / `trackId`. All accept `fallback`, `timeout`,
|
|
212
|
-
`allowAppStore`, `allowWebStore`.
|
|
226
|
+
`allowAppStore`, `allowWebStore`, `language`, `country`.
|
|
227
|
+
|
|
228
|
+
`language` / `country` localize the **web-store** candidate only — `hl` / `gl` on
|
|
229
|
+
Google Play and the Microsoft Store, a country path segment plus `l` on the App
|
|
230
|
+
Store. When `country` is omitted it is derived from `language`: a region subtag
|
|
231
|
+
wins (`ko-KR` → `KR`), then `Intl.Locale.maximize()` where the runtime supports
|
|
232
|
+
it. When neither yields a region, the country is simply dropped and the store
|
|
233
|
+
falls back to its own geolocation — a wrong country can land on an
|
|
234
|
+
"not available in your region" page, so omission is the safe default. Native
|
|
235
|
+
app-store schemes (`market://`, `itms-apps://`, …) are untouched; the OS renders
|
|
236
|
+
those in the device locale.
|
|
213
237
|
|
|
214
238
|
`onAttempt` fires synchronously before each candidate, which is where you drive the waiting
|
|
215
239
|
UI — there is otherwise nothing on screen for the length of the timeout.
|
|
@@ -360,6 +384,12 @@ the button on `utils.canEscapeWebview`.
|
|
|
360
384
|
during page setup keeps `app()` from resolving the id inline. `app()` must run inside a
|
|
361
385
|
user gesture, so when the id is missing it looks it up synchronously rather than awaiting
|
|
362
386
|
and losing user activation. Passing `trackId` / `productId` directly skips it entirely.
|
|
387
|
+
`getProductId` also takes optional `language` / `country` to pin the Microsoft catalog
|
|
388
|
+
language and market — pass the same values you will give `app()`, since whether a lookup
|
|
389
|
+
succeeds can depend on the market and the pre-warmed cache should cover the same one.
|
|
390
|
+
When omitted, the market is derived the same way as the web-store country: explicit region
|
|
391
|
+
subtag first, then `Intl.Locale.maximize()` where the runtime supports it, then `en-US` / `US`.
|
|
392
|
+
`getTrackId` needs no locale — iTunes lookup is market-independent.
|
|
363
393
|
- **Store-id lookups depend on remote APIs** (iTunes Lookup, Microsoft display catalog)
|
|
364
394
|
and are cached for one hour; failures resolve to `undefined` rather than throwing.
|
|
365
395
|
- **In-app browsers are gated per candidate.** Inside webviews that block launches
|
|
@@ -381,6 +411,11 @@ the button on `utils.canEscapeWebview`.
|
|
|
381
411
|
- **Web fallbacks resolve on navigation.** A `fallback` or web-store candidate replaces the
|
|
382
412
|
document, so there is no app switch to wait for — those resolve as soon as the navigation
|
|
383
413
|
is issued instead of risking a rejection after the move already succeeded.
|
|
414
|
+
- **Unplanned navigations settle too.** A candidate that turns into a real navigation — a
|
|
415
|
+
universal link whose app is not installed, an intent whose browser fallback fires — used to
|
|
416
|
+
unload the document before the timeout, losing the result. `pagehide` now resolves the
|
|
417
|
+
candidate, and since an app switch fires `hidden` without `pagehide`, the two cases stay
|
|
418
|
+
distinguishable. The resolve runs during unload, where `sendBeacon` still delivers.
|
|
384
419
|
|
|
385
420
|
## Browser support
|
|
386
421
|
|
package/dist/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ declare interface AppInfo {
|
|
|
32
32
|
timeout?: number;
|
|
33
33
|
allowAppStore?: boolean;
|
|
34
34
|
allowWebStore?: boolean;
|
|
35
|
+
language?: string;
|
|
36
|
+
country?: string;
|
|
35
37
|
}
|
|
36
38
|
declare interface AndroidAppInfo extends AppInfo {
|
|
37
39
|
intent?: URLCandidate;
|
|
@@ -102,7 +104,7 @@ interface LaunchKitUtils {
|
|
|
102
104
|
get canOpenSetting(): boolean;
|
|
103
105
|
get canEscapeWebview(): boolean;
|
|
104
106
|
getTrackId(bundleId: string): Promise<string | undefined>;
|
|
105
|
-
getProductId(packageFamilyName: string): Promise<string | undefined>;
|
|
107
|
+
getProductId(packageFamilyName: string, language?: string, country?: string): Promise<string | undefined>;
|
|
106
108
|
}
|
|
107
109
|
interface LaunchKitInstance {
|
|
108
110
|
readonly version: string;
|
package/dist/launch-kit.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var version$3 = "0.0.
|
|
5
|
+
var version$3 = "0.0.10";
|
|
6
6
|
var packageJSON$3 = {
|
|
7
7
|
version: version$3};
|
|
8
8
|
|
|
@@ -1284,7 +1284,7 @@ function createHiddenElement(tagName, focusable) {
|
|
|
1284
1284
|
return element;
|
|
1285
1285
|
}
|
|
1286
1286
|
|
|
1287
|
-
var version = "0.0.
|
|
1287
|
+
var version = "0.0.6";
|
|
1288
1288
|
var packageJSON = {
|
|
1289
1289
|
version: version};
|
|
1290
1290
|
|
|
@@ -1413,6 +1413,27 @@ function expandTag(tag) {
|
|
|
1413
1413
|
chain.push(segments.slice(0, i).join('-'));
|
|
1414
1414
|
return freeze(chain);
|
|
1415
1415
|
}
|
|
1416
|
+
function maximizeTag(tag) {
|
|
1417
|
+
var parsed = parseTag(tag);
|
|
1418
|
+
if (parsed === null)
|
|
1419
|
+
return null;
|
|
1420
|
+
if (parsed.script !== null && parsed.region !== null)
|
|
1421
|
+
return parsed;
|
|
1422
|
+
var IntlLocale = getIntlLocaleConstructor();
|
|
1423
|
+
if (typeof IntlLocale === 'undefined')
|
|
1424
|
+
return parsed;
|
|
1425
|
+
try {
|
|
1426
|
+
var intlLocale = new IntlLocale(parsed.baseName);
|
|
1427
|
+
if (typeof intlLocale.maximize === 'function') {
|
|
1428
|
+
var reparsed = parseTag(intlLocale.maximize().toString());
|
|
1429
|
+
if (reparsed !== null)
|
|
1430
|
+
return reparsed;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
catch (_) {
|
|
1434
|
+
}
|
|
1435
|
+
return parsed;
|
|
1436
|
+
}
|
|
1416
1437
|
function toLookupKey(tag) {
|
|
1417
1438
|
var parsed = parseTag(tag);
|
|
1418
1439
|
return (parsed === null ? tag : parsed.baseName).toLowerCase();
|
|
@@ -1455,6 +1476,11 @@ function resolveDirection(primary) {
|
|
|
1455
1476
|
catch (_) {
|
|
1456
1477
|
}
|
|
1457
1478
|
}
|
|
1479
|
+
if (primary.script === null) {
|
|
1480
|
+
var maximized = maximizeTag(primary.baseName);
|
|
1481
|
+
if (maximized !== null && maximized.script !== null)
|
|
1482
|
+
return contains(RTL_SCRIPTS, maximized.script);
|
|
1483
|
+
}
|
|
1458
1484
|
return isRTL(primary);
|
|
1459
1485
|
}
|
|
1460
1486
|
var subtags = null;
|
|
@@ -1554,6 +1580,9 @@ var LocaleKit = {
|
|
|
1554
1580
|
expand: function (tag) {
|
|
1555
1581
|
return expandTag(tag);
|
|
1556
1582
|
},
|
|
1583
|
+
maximize: function (tag) {
|
|
1584
|
+
return maximizeTag(tag);
|
|
1585
|
+
},
|
|
1557
1586
|
lookup: function (supported, fallback) {
|
|
1558
1587
|
return lookupTag(supported, languages, typeof fallback === 'undefined' ? null : fallback);
|
|
1559
1588
|
},
|
|
@@ -1566,6 +1595,7 @@ var CACHE_PREFIX = 'web-launch-kit:';
|
|
|
1566
1595
|
var TRACK_ID = 'track-id';
|
|
1567
1596
|
var PRODUCT_ID = 'product-id';
|
|
1568
1597
|
var TRACK_ID_CACHE_TTL = 1000 * 60 * 60;
|
|
1598
|
+
var ALPHA2_REGION_PATTERN$1 = /^[A-Z]{2}$/;
|
|
1569
1599
|
function toCacheKey(mode, query) {
|
|
1570
1600
|
return CACHE_PREFIX + mode + ':' + query;
|
|
1571
1601
|
}
|
|
@@ -1698,27 +1728,34 @@ function requestGet(url, async) {
|
|
|
1698
1728
|
}
|
|
1699
1729
|
}
|
|
1700
1730
|
}
|
|
1701
|
-
function
|
|
1702
|
-
var
|
|
1703
|
-
var
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
var
|
|
1712
|
-
if (
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1731
|
+
function resolveMarket(language, country) {
|
|
1732
|
+
var locale = language;
|
|
1733
|
+
var market;
|
|
1734
|
+
if (typeof country !== 'undefined' && ALPHA2_REGION_PATTERN$1.test(country.toUpperCase()))
|
|
1735
|
+
market = country.toUpperCase();
|
|
1736
|
+
if (typeof market === 'undefined') {
|
|
1737
|
+
var source = typeof locale !== 'undefined'
|
|
1738
|
+
? locale
|
|
1739
|
+
: (LocaleKit.language === null ? undefined : LocaleKit.language);
|
|
1740
|
+
if (typeof source !== 'undefined') {
|
|
1741
|
+
var maximized = LocaleKit.maximize(source);
|
|
1742
|
+
if (maximized !== null && maximized.region !== null && ALPHA2_REGION_PATTERN$1.test(maximized.region))
|
|
1743
|
+
market = maximized.region;
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
if (typeof locale === 'undefined' && LocaleKit.language !== null)
|
|
1747
|
+
locale = LocaleKit.language;
|
|
1748
|
+
if (typeof locale === 'undefined')
|
|
1749
|
+
locale = 'en-US';
|
|
1750
|
+
if (typeof market === 'undefined')
|
|
1751
|
+
market = 'US';
|
|
1752
|
+
return [locale, market];
|
|
1753
|
+
}
|
|
1754
|
+
function resolveGetProductIdURL(packageFamilyName, language, country) {
|
|
1755
|
+
var resolved = resolveMarket(language, country);
|
|
1756
|
+
var locale = resolved[0];
|
|
1757
|
+
var market = resolved[1];
|
|
1758
|
+
return 'https://displaycatalog.md.mp.microsoft.com/v7.0/products/lookup?value=' + encodeURIComponent(packageFamilyName) + '&market=' + encodeURIComponent(market) + '&languages=' + encodeURIComponent(locale) + '&alternateId=PackageFamilyName';
|
|
1722
1759
|
}
|
|
1723
1760
|
function resolveGetTrackIdURL(bundleId) {
|
|
1724
1761
|
return 'https://itunes.apple.com/lookup?bundleId=' + encodeURIComponent(bundleId);
|
|
@@ -1746,12 +1783,12 @@ function parseGetTrackIdResponse(response) {
|
|
|
1746
1783
|
return undefined;
|
|
1747
1784
|
return '' + result.trackId;
|
|
1748
1785
|
}
|
|
1749
|
-
function getProductId(packageFamilyName) {
|
|
1786
|
+
function getProductId(packageFamilyName, language, country) {
|
|
1750
1787
|
var cache = idCache.get(PRODUCT_ID, packageFamilyName);
|
|
1751
1788
|
if (typeof cache !== 'undefined')
|
|
1752
1789
|
return cache;
|
|
1753
1790
|
try {
|
|
1754
|
-
var productId = parseGetProductIdResponse(requestGet(resolveGetProductIdURL(packageFamilyName)));
|
|
1791
|
+
var productId = parseGetProductIdResponse(requestGet(resolveGetProductIdURL(packageFamilyName, language, country)));
|
|
1755
1792
|
if (typeof productId === 'undefined')
|
|
1756
1793
|
return undefined;
|
|
1757
1794
|
idCache.set(PRODUCT_ID, packageFamilyName, productId);
|
|
@@ -1776,12 +1813,12 @@ function getTrackId(bundleId) {
|
|
|
1776
1813
|
return undefined;
|
|
1777
1814
|
}
|
|
1778
1815
|
}
|
|
1779
|
-
function getProductIdAsync(packageFamilyName) {
|
|
1816
|
+
function getProductIdAsync(packageFamilyName, language, country) {
|
|
1780
1817
|
var cache = idCache.get(PRODUCT_ID, packageFamilyName);
|
|
1781
1818
|
if (typeof cache !== 'undefined')
|
|
1782
1819
|
return Promise.resolve(cache);
|
|
1783
1820
|
try {
|
|
1784
|
-
return requestGet(resolveGetProductIdURL(packageFamilyName), true)
|
|
1821
|
+
return requestGet(resolveGetProductIdURL(packageFamilyName, language, country), true)
|
|
1785
1822
|
.then(parseGetProductIdResponse)
|
|
1786
1823
|
.then(function (productId) {
|
|
1787
1824
|
if (typeof productId === 'undefined')
|
|
@@ -1896,6 +1933,7 @@ var MACOS_DEFAULT_TIMEOUT = 750;
|
|
|
1896
1933
|
var DEFAULT_TIMEOUT = 750;
|
|
1897
1934
|
var GLOBAL = getGlobal$1();
|
|
1898
1935
|
var NAVIGATOR = GLOBAL.navigator;
|
|
1936
|
+
var ALPHA2_REGION_PATTERN = /^[A-Z]{2}$/;
|
|
1899
1937
|
var CLEANUP_INPUT_ELEMENT = null;
|
|
1900
1938
|
var DEBUG = false;
|
|
1901
1939
|
var APP_IN_FLIGHT = null;
|
|
@@ -2115,6 +2153,13 @@ function resolveFocusEventConfig() {
|
|
|
2115
2153
|
};
|
|
2116
2154
|
}
|
|
2117
2155
|
}
|
|
2156
|
+
function resolveEventBinding(config) {
|
|
2157
|
+
return {
|
|
2158
|
+
configured: typeof config.target !== 'undefined' && typeof config.type !== 'undefined',
|
|
2159
|
+
target: config.target,
|
|
2160
|
+
type: config.type,
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2118
2163
|
function openURL(tried, url, timeout, terminal) {
|
|
2119
2164
|
if (terminal === void 0) { terminal = false; }
|
|
2120
2165
|
var config = resolveFocusEventConfig();
|
|
@@ -2188,6 +2233,9 @@ function openURL(tried, url, timeout, terminal) {
|
|
|
2188
2233
|
return new Promise(function (resolve, reject) {
|
|
2189
2234
|
if (DEBUG)
|
|
2190
2235
|
debugger;
|
|
2236
|
+
var blurBinding = resolveEventBinding(config.blur);
|
|
2237
|
+
var focusBinding = resolveEventBinding(config.focus);
|
|
2238
|
+
var visibilityBinding = resolveEventBinding(config.visibilitychange);
|
|
2191
2239
|
var timeoutId;
|
|
2192
2240
|
var resolved = false;
|
|
2193
2241
|
function cleanup() {
|
|
@@ -2196,12 +2244,14 @@ function openURL(tried, url, timeout, terminal) {
|
|
|
2196
2244
|
timeoutId = undefined;
|
|
2197
2245
|
}
|
|
2198
2246
|
try {
|
|
2199
|
-
if (
|
|
2200
|
-
EventKit.remove(
|
|
2201
|
-
if (
|
|
2202
|
-
EventKit.remove(
|
|
2203
|
-
if (
|
|
2204
|
-
EventKit.remove(
|
|
2247
|
+
if (blurBinding.configured)
|
|
2248
|
+
EventKit.remove(blurBinding.target, blurBinding.type, onblur);
|
|
2249
|
+
if (focusBinding.configured)
|
|
2250
|
+
EventKit.remove(focusBinding.target, focusBinding.type, onfocus);
|
|
2251
|
+
if (visibilityBinding.configured)
|
|
2252
|
+
EventKit.remove(visibilityBinding.target, visibilityBinding.type, onvisibilitychange);
|
|
2253
|
+
if (navigationPagehide)
|
|
2254
|
+
EventKit.remove(top, 'pagehide', onpagehide);
|
|
2205
2255
|
}
|
|
2206
2256
|
catch (_) {
|
|
2207
2257
|
}
|
|
@@ -2235,10 +2285,10 @@ function openURL(tried, url, timeout, terminal) {
|
|
|
2235
2285
|
clearTimeout(timeoutId);
|
|
2236
2286
|
timeoutId = undefined;
|
|
2237
2287
|
}
|
|
2238
|
-
if (
|
|
2239
|
-
EventKit.remove(
|
|
2240
|
-
if (
|
|
2241
|
-
EventKit.add(
|
|
2288
|
+
if (blurBinding.configured)
|
|
2289
|
+
EventKit.remove(blurBinding.target, blurBinding.type, onblur);
|
|
2290
|
+
if (focusBinding.configured)
|
|
2291
|
+
EventKit.add(focusBinding.target, focusBinding.type, onfocus);
|
|
2242
2292
|
}
|
|
2243
2293
|
function onfocus() {
|
|
2244
2294
|
done(true);
|
|
@@ -2249,13 +2299,19 @@ function openURL(tried, url, timeout, terminal) {
|
|
|
2249
2299
|
else
|
|
2250
2300
|
onfocus();
|
|
2251
2301
|
}
|
|
2302
|
+
function onpagehide() {
|
|
2303
|
+
done(true);
|
|
2304
|
+
}
|
|
2305
|
+
var navigationPagehide = config.blur.type !== 'pagehide';
|
|
2252
2306
|
timeoutId = setTimeout(function () {
|
|
2253
2307
|
done(false);
|
|
2254
2308
|
}, timeout);
|
|
2255
|
-
if (
|
|
2256
|
-
EventKit.add(
|
|
2257
|
-
if (
|
|
2258
|
-
EventKit.add(
|
|
2309
|
+
if (blurBinding.configured)
|
|
2310
|
+
EventKit.add(blurBinding.target, blurBinding.type, onblur);
|
|
2311
|
+
if (visibilityBinding.configured)
|
|
2312
|
+
EventKit.add(visibilityBinding.target, visibilityBinding.type, onvisibilitychange);
|
|
2313
|
+
if (navigationPagehide)
|
|
2314
|
+
EventKit.add(top, 'pagehide', onpagehide);
|
|
2259
2315
|
if (!hasFocus(topDocument))
|
|
2260
2316
|
restoreFocus();
|
|
2261
2317
|
try {
|
|
@@ -2345,6 +2401,8 @@ function resolveOptions(option) {
|
|
|
2345
2401
|
var allowScheme;
|
|
2346
2402
|
var assumeAllowedInApp;
|
|
2347
2403
|
var timeout;
|
|
2404
|
+
var language;
|
|
2405
|
+
var country;
|
|
2348
2406
|
var intent;
|
|
2349
2407
|
var packageName;
|
|
2350
2408
|
var allowIntent = true;
|
|
@@ -2367,6 +2425,8 @@ function resolveOptions(option) {
|
|
|
2367
2425
|
allowWebStore = option.android.allowWebStore;
|
|
2368
2426
|
allowScheme = canOpenScheme(assumeAllowedInApp);
|
|
2369
2427
|
timeout = option.android.timeout;
|
|
2428
|
+
language = option.android.language;
|
|
2429
|
+
country = option.android.country;
|
|
2370
2430
|
if (typeof intent !== 'undefined' && (typeof scheme === 'undefined' || typeof packageName === 'undefined' || typeof fallback === 'undefined')) {
|
|
2371
2431
|
var parsed = parseIntentURL(intent);
|
|
2372
2432
|
if (typeof parsed.scheme !== 'undefined' && typeof scheme === 'undefined')
|
|
@@ -2390,7 +2450,7 @@ function resolveOptions(option) {
|
|
|
2390
2450
|
if (allowAppStore && allowScheme)
|
|
2391
2451
|
resolved.push(['store', createAppStoreURL(packageName, os)]);
|
|
2392
2452
|
if (allowWebStore)
|
|
2393
|
-
resolved.push(['store', createWebStoreURL(packageName, os)]);
|
|
2453
|
+
resolved.push(['store', createWebStoreURL(packageName, os, language, country)]);
|
|
2394
2454
|
}
|
|
2395
2455
|
return [resolved, timeout];
|
|
2396
2456
|
case 'ios':
|
|
@@ -2406,6 +2466,8 @@ function resolveOptions(option) {
|
|
|
2406
2466
|
allowWebStore = option.ios.allowWebStore;
|
|
2407
2467
|
allowScheme = canOpenScheme(assumeAllowedInApp);
|
|
2408
2468
|
timeout = option.ios.timeout;
|
|
2469
|
+
language = option.ios.language;
|
|
2470
|
+
country = option.ios.country;
|
|
2409
2471
|
if (typeof bundleId !== 'undefined' && typeof trackId === 'undefined')
|
|
2410
2472
|
trackId = getTrackId(bundleId);
|
|
2411
2473
|
if (typeof timeout === 'undefined')
|
|
@@ -2420,7 +2482,7 @@ function resolveOptions(option) {
|
|
|
2420
2482
|
if (allowAppStore && allowScheme)
|
|
2421
2483
|
resolved.push(['store', createAppStoreURL(trackId, os)]);
|
|
2422
2484
|
if (allowWebStore)
|
|
2423
|
-
resolved.push(['store', createWebStoreURL(trackId, os)]);
|
|
2485
|
+
resolved.push(['store', createWebStoreURL(trackId, os, language, country)]);
|
|
2424
2486
|
}
|
|
2425
2487
|
return [resolved, timeout];
|
|
2426
2488
|
case 'windows':
|
|
@@ -2433,8 +2495,10 @@ function resolveOptions(option) {
|
|
|
2433
2495
|
allowAppStore = option.windows.allowAppStore;
|
|
2434
2496
|
allowWebStore = option.windows.allowWebStore;
|
|
2435
2497
|
timeout = option.windows.timeout;
|
|
2498
|
+
language = option.windows.language;
|
|
2499
|
+
country = option.windows.country;
|
|
2436
2500
|
if (typeof packageFamilyName !== 'undefined' && typeof productId === 'undefined')
|
|
2437
|
-
productId = getProductId(packageFamilyName);
|
|
2501
|
+
productId = getProductId(packageFamilyName, language, country);
|
|
2438
2502
|
if (typeof timeout === 'undefined')
|
|
2439
2503
|
timeout = WINDOWS_DEFAULT_TIMEOUT;
|
|
2440
2504
|
if (typeof scheme !== 'undefined')
|
|
@@ -2445,7 +2509,7 @@ function resolveOptions(option) {
|
|
|
2445
2509
|
if (allowAppStore)
|
|
2446
2510
|
resolved.push(['store', createAppStoreURL(productId, os)]);
|
|
2447
2511
|
if (allowWebStore)
|
|
2448
|
-
resolved.push(['store', createWebStoreURL(productId, os)]);
|
|
2512
|
+
resolved.push(['store', createWebStoreURL(productId, os, language, country)]);
|
|
2449
2513
|
}
|
|
2450
2514
|
return [resolved, timeout];
|
|
2451
2515
|
case 'macos':
|
|
@@ -2458,6 +2522,8 @@ function resolveOptions(option) {
|
|
|
2458
2522
|
allowAppStore = option.macos.allowAppStore;
|
|
2459
2523
|
allowWebStore = option.macos.allowWebStore;
|
|
2460
2524
|
timeout = option.macos.timeout;
|
|
2525
|
+
language = option.macos.language;
|
|
2526
|
+
country = option.macos.country;
|
|
2461
2527
|
if (typeof bundleId !== 'undefined' && typeof trackId === 'undefined')
|
|
2462
2528
|
trackId = getTrackId(bundleId);
|
|
2463
2529
|
if (typeof timeout === 'undefined')
|
|
@@ -2470,7 +2536,7 @@ function resolveOptions(option) {
|
|
|
2470
2536
|
if (allowAppStore)
|
|
2471
2537
|
resolved.push(['store', createAppStoreURL(trackId, os)]);
|
|
2472
2538
|
if (allowWebStore)
|
|
2473
|
-
resolved.push(['store', createWebStoreURL(trackId, os)]);
|
|
2539
|
+
resolved.push(['store', createWebStoreURL(trackId, os, language, country)]);
|
|
2474
2540
|
}
|
|
2475
2541
|
return [resolved, timeout];
|
|
2476
2542
|
}
|
|
@@ -2637,19 +2703,69 @@ function createAppStoreURL(id, os) {
|
|
|
2637
2703
|
return os;
|
|
2638
2704
|
}
|
|
2639
2705
|
}
|
|
2640
|
-
function createWebStoreURL(id, os) {
|
|
2706
|
+
function createWebStoreURL(id, os, language, country) {
|
|
2707
|
+
var resolved = resolveCountry(language, country);
|
|
2708
|
+
var countryPath = typeof resolved !== 'undefined' ? resolved.toLowerCase() + '/' : '';
|
|
2709
|
+
var url;
|
|
2641
2710
|
switch (os) {
|
|
2642
2711
|
case 'android':
|
|
2643
|
-
|
|
2712
|
+
url = 'https://play.google.com/store/apps/details?id=' + id;
|
|
2713
|
+
if (typeof language !== 'undefined')
|
|
2714
|
+
url = appendURLParameter(url, 'hl=' + escapeURIComponentString(language));
|
|
2715
|
+
if (typeof resolved !== 'undefined')
|
|
2716
|
+
url = appendURLParameter(url, 'gl=' + resolved);
|
|
2717
|
+
break;
|
|
2644
2718
|
case 'ios':
|
|
2645
|
-
|
|
2719
|
+
url = 'https://itunes.apple.com/' + countryPath + 'app/id' + id + '?mt=8';
|
|
2720
|
+
if (typeof language !== 'undefined')
|
|
2721
|
+
url = appendURLParameter(url, 'l=' + escapeURIComponentString(language));
|
|
2722
|
+
break;
|
|
2646
2723
|
case 'windows':
|
|
2647
|
-
|
|
2724
|
+
url = 'https://apps.microsoft.com/detail/' + id;
|
|
2725
|
+
if (typeof language !== 'undefined')
|
|
2726
|
+
url = appendURLParameter(url, 'hl=' + escapeURIComponentString(language));
|
|
2727
|
+
if (typeof resolved !== 'undefined')
|
|
2728
|
+
url = appendURLParameter(url, 'gl=' + resolved);
|
|
2729
|
+
break;
|
|
2648
2730
|
case 'macos':
|
|
2649
|
-
|
|
2731
|
+
url = 'https://apps.apple.com/' + countryPath + 'app/id' + id + '?mt=12';
|
|
2732
|
+
if (typeof language !== 'undefined')
|
|
2733
|
+
url = appendURLParameter(url, 'l=' + escapeURIComponentString(language));
|
|
2734
|
+
break;
|
|
2650
2735
|
default:
|
|
2651
2736
|
return os;
|
|
2652
2737
|
}
|
|
2738
|
+
return url;
|
|
2739
|
+
}
|
|
2740
|
+
function extractRegion(tag) {
|
|
2741
|
+
var parts = tag.replace(/_/g, '-').split('-');
|
|
2742
|
+
for (var i = 1; i < parts.length; i++) {
|
|
2743
|
+
if (/^[A-Za-z]{2}$/.test(parts[i]))
|
|
2744
|
+
return parts[i].toUpperCase();
|
|
2745
|
+
}
|
|
2746
|
+
return undefined;
|
|
2747
|
+
}
|
|
2748
|
+
function resolveCountry(language, country) {
|
|
2749
|
+
if (typeof country !== 'undefined' && ALPHA2_REGION_PATTERN.test(country.toUpperCase()))
|
|
2750
|
+
return country.toUpperCase();
|
|
2751
|
+
if (typeof language === 'undefined')
|
|
2752
|
+
return undefined;
|
|
2753
|
+
var region = extractRegion(language);
|
|
2754
|
+
if (typeof region !== 'undefined')
|
|
2755
|
+
return region;
|
|
2756
|
+
if (typeof Intl !== 'undefined' && typeof Intl.Locale === 'function') {
|
|
2757
|
+
try {
|
|
2758
|
+
var locale = new Intl.Locale(language);
|
|
2759
|
+
if (typeof locale.maximize === 'function') {
|
|
2760
|
+
var maximized = locale.maximize();
|
|
2761
|
+
if (typeof maximized !== 'undefined' && maximized !== null && typeof maximized.region === 'string' && ALPHA2_REGION_PATTERN.test(maximized.region.toUpperCase()))
|
|
2762
|
+
return maximized.region.toUpperCase();
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
catch (_) {
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
return undefined;
|
|
2653
2769
|
}
|
|
2654
2770
|
function appendURLParameter(url, parameter) {
|
|
2655
2771
|
var index = url.indexOf('#');
|
|
@@ -2799,6 +2915,8 @@ function resolveFile(module) {
|
|
|
2799
2915
|
});
|
|
2800
2916
|
}
|
|
2801
2917
|
function resolveInput(module, resolve) {
|
|
2918
|
+
var focusBinding = resolveEventBinding(config.focus);
|
|
2919
|
+
var visibilityBinding = resolveEventBinding(config.visibilitychange);
|
|
2802
2920
|
var resolved = false;
|
|
2803
2921
|
function done(success) {
|
|
2804
2922
|
if (resolved)
|
|
@@ -2836,10 +2954,10 @@ function resolveFile(module) {
|
|
|
2836
2954
|
}
|
|
2837
2955
|
else {
|
|
2838
2956
|
module.onclick = function () {
|
|
2839
|
-
if (
|
|
2840
|
-
EventKit.add(
|
|
2841
|
-
if (
|
|
2842
|
-
EventKit.add(
|
|
2957
|
+
if (focusBinding.configured)
|
|
2958
|
+
EventKit.add(focusBinding.target, focusBinding.type, onfocus);
|
|
2959
|
+
if (visibilityBinding.configured)
|
|
2960
|
+
EventKit.add(visibilityBinding.target, visibilityBinding.type, onvisibilitychange);
|
|
2843
2961
|
setTimeout(function () {
|
|
2844
2962
|
EventKit.add(topDocument, 'click', onclick);
|
|
2845
2963
|
}, 100);
|
|
@@ -2851,10 +2969,10 @@ function resolveFile(module) {
|
|
|
2851
2969
|
function cleanup() {
|
|
2852
2970
|
CLEANUP_INPUT_ELEMENT = null;
|
|
2853
2971
|
try {
|
|
2854
|
-
if (
|
|
2855
|
-
EventKit.remove(
|
|
2856
|
-
if (
|
|
2857
|
-
EventKit.remove(
|
|
2972
|
+
if (focusBinding.configured)
|
|
2973
|
+
EventKit.remove(focusBinding.target, focusBinding.type, onfocus);
|
|
2974
|
+
if (visibilityBinding.configured)
|
|
2975
|
+
EventKit.remove(visibilityBinding.target, visibilityBinding.type, onvisibilitychange);
|
|
2858
2976
|
EventKit.remove(topDocument, 'click', onclick);
|
|
2859
2977
|
}
|
|
2860
2978
|
catch (_) {
|