UNPKG

16.7 kBJavaScriptView Raw
1/*
2Copyright 2013-2015 ASIAL CORPORATION
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15
16*/
17
18// Save HTMLElement object before Custom Elements polyfill patch global HTMLElement.
19const NativeHTMLElement = window.HTMLElement;
20
21/**
22 * @object ons.platform
23 * @category util
24 * @description
25 * [en]Utility methods to detect current platform.[/en]
26 * [ja]現在実行されているプラットフォームを検知するためのユーティリティメソッドを収めたオブジェクトです。[/ja]
27 */
28class Platform {
29
30 /**
31 * All elements will be rendered as if the app was running on this platform.
32 * @type {String}
33 */
34 constructor() {
35 this._selectedPlatform = null;
36 this._ignorePlatformSelect = false;
37 }
38
39 /**
40 * @method select
41 * @signature select(platform)
42 * @param {string} platform Name of the platform.
43 * [en]Possible values are: "opera", "firefox", "safari", "chrome", "ie", "android", "blackberry", "ios" or "wp".[/en]
44 * [ja]"opera", "firefox", "safari", "chrome", "ie", "android", "blackberry", "ios", "wp"のいずれかを指定します。[/ja]
45 * @description
46 * [en]Sets the platform used to render the elements. Useful for testing.[/en]
47 * [ja]要素を描画するために利用するプラットフォーム名を設定します。テストに便利です。[/ja]
48 */
49 select(platform) {
50 if (typeof platform === 'string') {
51 this._selectedPlatform = platform.trim().toLowerCase();
52 }
53 }
54
55 _getSelectedPlatform() {
56 return this._ignorePlatformSelect ? null : this._selectedPlatform;
57 }
58
59 _runOnActualPlatform(fn) {
60 this._ignorePlatformSelect = true;
61 const result = fn();
62 this._ignorePlatformSelect = false;
63
64 return result;
65 }
66
67 //----------------
68 // General
69 //----------------
70 /**
71 * @method isWebView
72 * @signature isWebView()
73 * @description
74 * [en]Returns whether app is running in Cordova.[/en]
75 * [ja]Cordova内で実行されているかどうかを返します。[/ja]
76 * @return {Boolean}
77 */
78 isWebView() {
79 if (document.readyState === 'loading' || document.readyState == 'uninitialized') {
80 throw new Error('isWebView() method is available after dom contents loaded.');
81 }
82
83 return !!(window.cordova || window.phonegap || window.PhoneGap);
84 }
85
86 //----------------
87 // iOS devices
88 //----------------
89 /**
90 * @method isIPhone
91 * @signature isIPhone()
92 * @description
93 * [en]Returns whether the device is iPhone.[/en]
94 * [ja]iPhone上で実行されているかどうかを返します。[/ja]
95 * @return {Boolean}
96 */
97 isIPhone() {
98 return /iPhone/i.test(navigator.userAgent);
99 }
100
101 /**
102 * @method isIPhoneX
103 * @signature isIPhoneX()
104 * @description
105 * [en]Returns whether the device is iPhone X, XS, XS Max, XR, 11, 11 Pro, 11 Pro Max, 12 Mini, 12, 12 Pro or 12 Pro Max.[/en]
106 * [ja]iPhone X や XS、XS Max、XR、11、11 Pro、11 Pro Max、12 Mini、12、12 Pro、または12 Pro Max上で実行されているかどうかを返します。[/ja]
107 * @return {Boolean}
108 */
109 isIPhoneX() {
110 // iOS WebViews on the same iOS version have the same user agent.
111 // We cannot avoid using window.screen.
112 // We also cannot use cordova-plugin-device since its behavior is different between simulators and real devices.
113 // This works well both in iOS Safari and (UI|WK)WebView of iPhone X.
114 return this.isIPhone() &&
115 (
116 // X, XS, 11 Pro, 12 Mini
117 window.screen.width === 375 && window.screen.height === 812 || // portrait
118 window.screen.width === 812 && window.screen.height === 375 || // landscape
119
120 // XS Max, XR, 11, 11 Pro Max
121 window.screen.width === 414 && window.screen.height === 896 || // portrait
122 window.screen.width === 896 && window.screen.height === 414 || // landscape
123
124 // 12, 12 Pro
125 window.screen.width === 390 && window.screen.height === 844 || // portrait
126 window.screen.width === 844 && window.screen.height === 390 || // landscape
127
128 // 12 Pro Max
129 window.screen.width === 428 && window.screen.height === 926 || // portrait
130 window.screen.width === 926 && window.screen.height === 428 // landscape
131 );
132 }
133
134 /**
135 * @method isIPad
136 * @signature isIPad()
137 * @description
138 * [en]Returns whether the device is iPad.[/en]
139 * [ja]iPad上で実行されているかどうかを返します。[/ja]
140 * @return {Boolean}
141 */
142 isIPad() {
143 return /iPad/i.test(navigator.userAgent) || this.isIPadOS();
144 }
145
146 /**
147 * @return {Boolean}
148 */
149 isIPod() {
150 return /iPod/i.test(navigator.userAgent);
151 }
152
153 //----------------
154 // iOS versions
155 //----------------
156 /**
157 * @method isIOS
158 * @signature isIOS([forceActualPlatform])
159 * @param {Boolean} forceActualPlatform
160 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
161 * [ja][/ja]
162 * @description
163 * [en]Returns whether the OS is iOS. By default will return manually selected platform if it is set.[/en]
164 * [ja]iOS上で実行されているかどうかを返します。[/ja]
165 * @return {Boolean}
166 */
167 isIOS(forceActualPlatform) {
168 if (!forceActualPlatform && this._getSelectedPlatform()) {
169 return this._getSelectedPlatform() === 'ios';
170 }
171
172 if (typeof device === 'object' && !/browser/i.test(device.platform)) {
173 return /iOS/i.test(device.platform);
174 } else {
175 return /iPhone|iPad|iPod/i.test(navigator.userAgent) || this.isIPadOS();
176 }
177 }
178
179 /**
180 * @method isIOS7above
181 * @signature isIOS7above()
182 * @description
183 * [en]Returns whether the iOS version is 7 or above.[/en]
184 * [ja]iOS7以上で実行されているかどうかを返します。[/ja]
185 * @return {Boolean}
186 */
187 isIOS7above() {
188 if (typeof device === 'object' && !/browser/i.test(device.platform)) {
189 return (/iOS/i.test(device.platform) && (parseInt(device.version.split('.')[0]) >= 7));
190 } else if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
191 const ver = (navigator.userAgent.match(/\b[0-9]+_[0-9]+(?:_[0-9]+)?\b/) || [''])[0].replace(/_/g, '.');
192 return (parseInt(ver.split('.')[0]) >= 7);
193 }
194 return false;
195 }
196
197 /**
198 * @method isIPadOS
199 * @signature isIPadOS()
200 * @description
201 * [en]Returns whether the OS is iPadOS.[/en]
202 * [ja][/ja]
203 * @return {Boolean}
204 */
205 isIPadOS() {
206 // The iPadOS User Agent string is the same as MacOS so as a
207 // workaround we test the max touch points, which is 5 for
208 // iPads and 0 for desktop browsers.
209 return !!(/Macintosh/i.test(navigator.userAgent) && navigator.maxTouchPoints && navigator.maxTouchPoints === 5);
210 }
211
212 //----------------
213 // iOS browsers
214 //----------------
215 /**
216 * @method isIOSSafari
217 * @signature isIOSSafari()
218 * @description
219 * [en]Returns whether app is running in iOS Safari.[/en]
220 * [ja]iOS Safariで実行されているかどうかを返します。[/ja]
221 * @return {Boolean}
222 */
223 isIOSSafari() {
224 const navigator = window.navigator;
225 const ua = navigator.userAgent;
226
227 return !!(this.isIOS() && ua.indexOf('Safari') !== -1 && ua.indexOf('Version') !== -1 && !navigator.standalone);
228 }
229
230 /**
231 * @method isWKWebView
232 * @signature isWKWebView()
233 * @description
234 * [en]Returns whether app is running in WKWebView.[/en]
235 * [ja]WKWebViewで実行されているかどうかを返します。[/ja]
236 * @return {Boolean}
237 */
238 isWKWebView() {
239 const lte9 = /constructor/i.test(NativeHTMLElement);
240 return !!(this.isIOS() && window.webkit && window.webkit.messageHandlers && window.indexedDB && !lte9);
241 }
242
243 //----------------
244 // Android devices
245 //----------------
246 /**
247 * @method isAndroidPhone
248 * @signature isAndroidPhone()
249 * @description
250 * [en]Returns whether the device is Android phone.[/en]
251 * [ja]Android携帯上で実行されているかどうかを返します。[/ja]
252 * @return {Boolean}
253 */
254 isAndroidPhone() {
255 return /Android/i.test(navigator.userAgent) && /Mobile/i.test(navigator.userAgent);
256 }
257
258 /**
259 * @method isAndroidTablet
260 * @signature isAndroidTablet()
261 * @description
262 * [en]Returns whether the device is Android tablet.[/en]
263 * [ja]Androidタブレット上で実行されているかどうかを返します。[/ja]
264 * @return {Boolean}
265 */
266 isAndroidTablet() {
267 return /Android/i.test(navigator.userAgent) && !/Mobile/i.test(navigator.userAgent);
268 }
269
270 //----------------
271 // Android versions
272 //----------------
273 /**
274 * @method isAndroid
275 * @signature isAndroid([forceActualPlatform])
276 * @param {Boolean} forceActualPlatform
277 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
278 * [ja][/ja]
279 * @description
280 * [en]Returns whether the OS is Android. By default will return manually selected platform if it is set.[/en]
281 * [ja]Android上で実行されているかどうかを返します。[/ja]
282 * @return {Boolean}
283 */
284 isAndroid(forceActualPlatform) {
285 if (!forceActualPlatform && this._getSelectedPlatform()) {
286 return this._getSelectedPlatform() === 'android';
287 }
288
289 if (typeof device === 'object' && !/browser/i.test(device.platform)) {
290 return /Android/i.test(device.platform);
291 } else {
292 return /Android/i.test(navigator.userAgent);
293 }
294 }
295
296 //----------------
297 // Other devices
298 //----------------
299 /**
300 * @method isWP
301 * @signature isWP([forceActualPlatform])
302 * @param {Boolean} forceActualPlatform
303 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
304 * [ja][/ja]
305 * @description
306 * [en]Returns whether the OS is Windows phone. By default will return manually selected platform if it is set.[/en]
307 * [ja][/ja]
308 * @return {Boolean}
309 */
310 isWP(forceActualPlatform) {
311 if (!forceActualPlatform && this._getSelectedPlatform()) {
312 return this._getSelectedPlatform() === 'wp';
313 }
314
315 if (typeof device === 'object' && !/browser/i.test(device.platform)) {
316 return /Win32NT|WinCE/i.test(device.platform);
317 } else {
318 return /Windows Phone|IEMobile|WPDesktop/i.test(navigator.userAgent);
319 }
320 }
321
322 /**
323 * @method isBlackBerry
324 * @signature isBlackBerry([forceActualPlatform])
325 * @param {Boolean} forceActualPlatform
326 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
327 * [ja][/ja]
328 * @description
329 * [en]Returns whether the device is BlackBerry. By default will return manually selected platform if it is set.[/en]
330 * [ja]BlackBerry上で実行されているかどうかを返します。[/ja]
331 * @return {Boolean}
332 */
333 isBlackBerry(forceActualPlatform) {
334 if (!forceActualPlatform && this._getSelectedPlatform()) {
335 return this._getSelectedPlatform() === 'blackberry';
336 }
337
338 if (typeof device === 'object' && !/browser/i.test(device.platform)) {
339 return /BlackBerry/i.test(device.platform);
340 } else {
341 return /BlackBerry|RIM Tablet OS|BB10/i.test(navigator.userAgent);
342 }
343 }
344
345 //----------------
346 // Other browsers
347 //----------------
348 /**
349 * @method isOpera
350 * @signature isOpera([forceActualPlatform])
351 * @param {Boolean} forceActualPlatform
352 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
353 * [ja][/ja]
354 * @description
355 * [en]Returns whether the browser is Opera. By default will return manually selected platform if it is set.[/en]
356 * [ja]Opera上で実行されているかどうかを返します。[/ja]
357 * @return {Boolean}
358 */
359 isOpera(forceActualPlatform) {
360 if (!forceActualPlatform && this._getSelectedPlatform()) {
361 return this._getSelectedPlatform() === 'opera';
362 }
363
364 return (!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0);
365 }
366
367 /**
368 * @method isFirefox
369 * @signature isFirefox([forceActualPlatform])
370 * @param {Boolean} forceActualPlatform
371 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
372 * [ja][/ja]
373 * @description
374 * [en]Returns whether the browser is Firefox. By default will return manually selected platform if it is set.[/en]
375 * [ja]Firefox上で実行されているかどうかを返します。[/ja]
376 * @return {Boolean}
377 */
378 isFirefox(forceActualPlatform) {
379 if (!forceActualPlatform && this._getSelectedPlatform()) {
380 return this._getSelectedPlatform() === 'firefox';
381 }
382
383 return (typeof InstallTrigger !== 'undefined');
384 }
385
386 /**
387 * @method isSafari
388 * @signature isSafari([forceActualPlatform])
389 * @param {Boolean} forceActualPlatform
390 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
391 * [ja][/ja]
392 * @description
393 * [en]Returns whether the browser is Safari. By default will return manually selected platform if it is set.[/en]
394 * [ja]Safari上で実行されているかどうかを返します。[/ja]
395 * @return {Boolean}
396 */
397 isSafari(forceActualPlatform) {
398 if (!forceActualPlatform && this._getSelectedPlatform()) {
399 return this._getSelectedPlatform() === 'safari';
400 }
401
402 return (Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0) || (function (p) { return p.toString() === '[object SafariRemoteNotification]'; })(!window['safari'] || safari.pushNotification);
403 }
404
405 /**
406 * @method isChrome
407 * @signature isChrome([forceActualPlatform])
408 * @param {Boolean} forceActualPlatform
409 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
410 * [ja][/ja]
411 * @description
412 * [en]Returns whether the browser is Chrome. By default will return manually selected platform if it is set.[/en]
413 * [ja]Chrome上で実行されているかどうかを返します。[/ja]
414 * @return {Boolean}
415 */
416 isChrome(forceActualPlatform) {
417 if (!forceActualPlatform && this._getSelectedPlatform()) {
418 return this._getSelectedPlatform() === 'chrome';
419 }
420
421 return (!!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0) && !(navigator.userAgent.indexOf(' Edge/') >= 0));
422 }
423
424 /**
425 * @method isIE
426 * @signature isIE([forceActualPlatform])
427 * @param {Boolean} forceActualPlatform
428 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
429 * [ja][/ja]
430 * @description
431 * [en]Returns whether the browser is Internet Explorer. By default will return manually selected platform if it is set.[/en]
432 * [ja]Internet Explorer上で実行されているかどうかを返します。[/ja]
433 * @return {Boolean}
434 */
435 isIE(forceActualPlatform) {
436 if (!forceActualPlatform && this._getSelectedPlatform()) {
437 return this._getSelectedPlatform() === 'ie';
438 }
439
440 return false || !!document.documentMode;
441 }
442
443 /**
444 * @method isEdge
445 * @signature isEdge([forceActualPlatform])
446 * @param {Boolean} forceActualPlatform
447 * [en]If true, selected platform is ignored and the actual platform is returned.[/en]
448 * [ja][/ja]
449 * @description
450 * [en]Returns whether the browser is Edge. By default will return manually selected platform if it is set.[/en]
451 * [ja]Edge上で実行されているかどうかを返します。[/ja]
452 * @return {Boolean}
453 */
454 isEdge(forceActualPlatform) {
455 if (!forceActualPlatform && this._getSelectedPlatform()) {
456 return this._getSelectedPlatform() === 'edge';
457 }
458
459 return navigator.userAgent.indexOf(' Edge/') >= 0;
460 }
461
462 //----------------
463 // Utility functions
464 //----------------
465 /**
466 * @return {String}
467 */
468 getMobileOS() {
469 if (this.isAndroid()) {
470 return 'android';
471 }
472 else if (this.isIOS()) {
473 return 'ios';
474 }
475 else if (this.isWP()) {
476 return 'wp';
477 }
478 else {
479 return 'other';
480 }
481 }
482
483 /**
484 * @return {String}
485 */
486 getIOSDevice() {
487 if (this.isIPhone()) {
488 return 'iphone';
489 }
490 else if (this.isIPad()) {
491 return 'ipad';
492 }
493 else if (this.isIPod()) {
494 return 'ipod';
495 }
496 else {
497 return 'na';
498 }
499 }
500}
501
502
503export default new Platform();