-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
248 lines (211 loc) · 8.06 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
/*!
* pwa-install-prompt
* Copyright (c) 2024 ryxxn
* Released under the MIT License
* https://github.com/ryxxn/pwa-install-prompt
*/
// constants
const MODAL_STYLE = `
.wepp-modal-overlay * { box-sizing: border-box; }
.wepp-modal-overlay { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, .5); justify-content: center; align-items: center; z-index: 99999; }
.wepp-modal-content { min-width: 300px; max-width:340px; background: #fff; border-radius: 10px; position: relative; }
.wepp-modal-content h1 { font-size: 18px; }
.wepp-modal-body { display: flex; flex-direction: column; align-items: center; gap: 10px; }
#wepp-logo { border-radius: 8px; }
#wepp-install-button { width: 100%; background: #007bff; color: #fff; border: none; border-radius: 5px; font-size: 18px; cursor: pointer; font-weight: 700; transition: .3s; }
#wepp-install-button:hover { background: #0056b3; }
#wepp-install-button:active { transform: scale(.98); }
#wepp-install-button:disabled { opacity:0.7; cursor: not-allowed; }
#wepp-skip-button { all: initial; font:inherit; width: 100%; text-align: center; cursor: pointer; color: #a0a0a0; font-size: 14px; text-decoration: underline; }
`;
const IOS_MODAL_CONTENT = `
<div class="wepp-modal-content" style="padding: 20px;">
<div class="wepp-modal-body">
<h1 style="margin-top: 0; margin-bottom: 10px;">IOS 앱 설치 방법</h1>
<img id="wepp-logo" alt="logo" width="64" height="64" />
<h2 id="wepp-name"></h2>
</div>
<p style="margin-block:4px;">
1. 브라우저 주소 표시줄에
<span style="vertical-align:middle;">
<svg
version="1.1"
viewBox="0 0 2048 2048"
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
>
<path
transform="translate(600,655)"
d="m0 0h301l1 2v79l-1 1-284 1-17 2-10 5-6 5-6 10-3 11v751l3 12 7 10 8 6 8 3 12 2h776l54-1 12-4 9-7 6-10 3-14v-744l-2-12-5-10-5-6-14-7-4-1-18-1-278-1-1-1v-81h301l18 3 16 5 16 8 12 8 12 10v2l3 1 9 11 9 14 8 17 4 14 2 12 1 15v744l-2 21-6 21-9 19-10 14-12 13-10 8-11 7-14 7-18 6-17 3-13 1h-824l-20-2-19-5-16-7-12-7-16-13-11-12-10-15-8-16-5-17-3-18-1-42v-658l1-61 3-18 5-16 4-9 7-13 8-11 3-4h2l2-4 13-12 16-10 15-7 18-5z"
/>
<path
transform="translate(1023,229)"
d="m0 0 5 3 269 269 1 4-53 53-2 3-4-1-172-172-1 3v753l-2 3h-81l-1-2v-758l-174 174h-3l-7-8-48-48 1-5 10-9 162-162 5-6 7-6 5-6 7-6 5-6 7-6 5-6 7-6 5-6 7-6 5-6 7-6 5-6 8-7z"
/>
</svg>
</span>
아이콘을 클릭하세요.
</p>
<p style="margin-block:4px;">2. '홈 화면에 추가'를 눌러주세요.</p>
<button id="wepp-skip-button">괜찮아요, 모바일 웹으로 볼게요.</button>
</div>
`;
const DEFAULT_MODAL_CONTENT = `
<div class="wepp-modal-content" style="padding: 20px;">
<div class="wepp-modal-body">
<h1 style="margin-top: 0; margin-bottom: 10px;">앱으로 설치하기</h1>
<img id="wepp-logo" alt="logo" width="64" height="64" />
<h2 id="wepp-name"></h2>
</div>
<button id="wepp-install-button" style="margin-top: 10px;padding: 10px;" disabled>앱 정보 불러오는 중...</button>
<button id="wepp-skip-button" style="margin-top: 20px">
괜찮아요, 모바일 웹으로 볼게요.
</button>
</div>
`
// functions
/**
* Function that identifies the favicon as the default logo
* and gets the address
*/
function getFaviconHref() {
const linkElements = document.getElementsByTagName('link');
for (let i = 0; i < linkElements.length; i++) {
if (linkElements[i].getAttribute('rel') === 'icon') {
return linkElements[i].getAttribute('href');
}
}
return '';
}
function appendStyles() {
const style = document.createElement('style');
style.textContent = MODAL_STYLE;
document.head.appendChild(style);
}
/**
* Create a Proxy object to detect whether PWA is installed
*/
function createProxy() {
// 상태 객체
let state = {
isInstalled: true,
};
// Handlers for detecting state changes
const handler = {
set: function (target, property, value) {
// console.log(
// `${property} changed from ${target[property]} to ${value}.`
// );
target[property] = value;
// Additional actions after status change
if (property === 'isInstalled') {
if (value) {
// console.log('PWA is already installed');
} else {
// console.log('PWA is not installed');
}
}
return true;
},
};
// Proxy
const proxyState = new Proxy(state, handler);
return proxyState;
}
const getModalContent = (isIOS) => {
return isIOS ? IOS_MODAL_CONTENT : DEFAULT_MODAL_CONTENT;
};
function createContainer() {
const container = document.createElement('div');
container.id = 'wepp-install-modal';
container.className = 'wepp-modal-overlay';
document.body.appendChild(container);
return container;
}
const handleHashChange = () => {
const hash = window.location.hash;
const isValidHash = hash.startsWith('#wepp-install-modal');
const modal = document.getElementById('wepp-install-modal');
modal.style.display = isValidHash ? 'flex' : 'none';
};
const initializePWAInfo = () => {
const nameElement = document.getElementById('wepp-name');
const logoElement = document.getElementById('wepp-logo');
const name = document.title;
const logo = getFaviconHref();
nameElement.textContent = name;
logoElement.src = logo;
}
function handleModalClose() {
window.location.hash = '';
const modal = document.getElementById('wepp-install-modal');
modal.style.display = 'none';
}
function preventModalContentClick(event) {
event.stopPropagation();
}
function initializeModalEvents() {
const modal = document.getElementById('wepp-install-modal');
const skipButton = document.getElementById('wepp-skip-button');
const modalContent = modal.querySelector('.wepp-modal-content');
// Close Modal on Background Click
modal.addEventListener('click', handleModalClose);
modalContent.addEventListener('click', preventModalContentClick);
skipButton.addEventListener('click', handleModalClose);
}
const showPrompt = (deferredPrompt) => {
try {
deferredPrompt.prompt(); // Show the install prompt
// Wait for the user to respond to the prompt
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
// User accepted the install prompt
handleModalClose();
} else {
// User dismissed the install prompt
}
// Clear the deferredPrompt variable
deferredPrompt = null;
});
} catch (error) {
console.log('Error: ', error);
}
}
function main() {
const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
appendStyles();
// Create Modal containers and add them to dom
const container = createContainer();
container.innerHTML = getModalContent(isIOS);
// initializeModal
handleHashChange();
initializePWAInfo();
initializeModalEvents();
// initialize hash change event
window.addEventListener('hashchange', handleHashChange);
// ----------------------------------------------------------
const state = createProxy();
if (!isIOS) {
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
const deferredPrompt = e;
const installButton = document.getElementById('wepp-install-button');
installButton.addEventListener('click', () => showPrompt(deferredPrompt), { once: true })
installButton.innerText = '앱으로 설치하기';
installButton.disabled = false;
state.isInstalled = false;
});
}
window.addEventListener('appinstalled', () => {
state.isInstalled = true;
console.log('PWA was installed');
});
}
if (document.readyState === "loading") {
// Loading hasn't finished yet
document.addEventListener("DOMContentLoaded", main);
} else {
// `DOMContentLoaded` has already fired
main();
}