Skip to content

Commit 4d3a377

Browse files
committed
🎨 #19024
1 parent 01b1ee7 commit 4d3a377

5 files changed

Lines changed: 88 additions & 4 deletions

File tree

app/src/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import {
3232
} from "./dialog/processSystem";
3333
import {initMessage, showMessage} from "./dialog/message";
3434
import {getAllModels, getAllTabs} from "./layout/getAll";
35-
import {getLocalStorage, isChromeBrowser, isInMobileApp} from "./protyle/util/compatibility";
35+
import {getLocalStorage, isChromeBrowser, isInMobileApp, isIOSDevice} from "./protyle/util/compatibility";
3636
import {isBrowser} from "./util/functions";
3737
import {checkPublishServiceClosed} from "./util/processMessage";
3838
import {hideAllElements} from "./protyle/ui/hideElements";
@@ -313,7 +313,8 @@ export class App {
313313
setTitle("", true);
314314
initMessage();
315315
/// #if BROWSER && !MOBILE
316-
if (!isInMobileApp() && !window.siyuan.config.readonly && !window.siyuan.isPublish && !isChromeBrowser()
316+
if (!isInMobileApp() && !isIOSDevice() && !window.siyuan.config.readonly &&
317+
!window.siyuan.isPublish && !isChromeBrowser()
317318
&& window.siyuan.config.appearance.notifications?.browserCompatibility !== false) {
318319
showMessage(window.siyuan.languages.useChrome, 0, "error");
319320
}

app/src/mobile/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
isInAndroid,
3535
isInIOS,
3636
isInMobileApp,
37+
isIOSDevice,
3738
writeText
3839
} from "../protyle/util/compatibility";
3940
import {getCurrentEditor, openMobileFileById} from "./editor";
@@ -195,7 +196,7 @@ class App {
195196
document.querySelector('meta[name="viewport"]').setAttribute("content", "width=device-width, height=device-height, interactive-widget=resizes-content, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover");
196197
} else {
197198
document.querySelector('meta[name="viewport"]').setAttribute("content", "width=device-width, height=device-height, interactive-widget=resizes-visual, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, viewport-fit=cover");
198-
if (!window.siyuan.config.readonly && !window.siyuan.isPublish
199+
if (!isIOSDevice() && !window.siyuan.config.readonly && !window.siyuan.isPublish
199200
&& window.siyuan.config.appearance.notifications?.browserCompatibility !== false) {
200201
showMessage(window.siyuan.languages.useChrome, 0, "error");
201202
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {describe, it} from "node:test";
2+
import * as assert from "node:assert/strict";
3+
import {isIOSPlatform, isIPadOSPlatform, type TBrowserNavigator} from "./browserCompatibility";
4+
5+
const browserNavigator = (
6+
userAgent: string,
7+
platform = "",
8+
maxTouchPoints = 0,
9+
): TBrowserNavigator => ({userAgent, platform, maxTouchPoints});
10+
11+
describe("iOS browser detection", () => {
12+
it("detects iPhone browsers independently of the browser brand", () => {
13+
assert.equal(isIOSPlatform(browserNavigator(
14+
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 " +
15+
"(KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1",
16+
"iPhone",
17+
5,
18+
)), true);
19+
assert.equal(isIOSPlatform(browserNavigator(
20+
"Mozilla/5.0 (iPhone; CPU iPhone OS 17_6 like Mac OS X) AppleWebKit/605.1.15 " +
21+
"(KHTML, like Gecko) CriOS/128.0.6613.69 Mobile/15E148 Safari/604.1",
22+
"iPhone",
23+
5,
24+
)), true);
25+
});
26+
27+
it("detects iPad and iPod user agents", () => {
28+
assert.equal(isIOSPlatform(browserNavigator(
29+
"Mozilla/5.0 (iPad; CPU OS 17_6 like Mac OS X) AppleWebKit/605.1.15 " +
30+
"(KHTML, like Gecko) CriOS/128.0.6613.69 Mobile/15E148 Safari/604.1",
31+
"iPad",
32+
5,
33+
)), true);
34+
assert.equal(isIOSPlatform(browserNavigator(
35+
"Mozilla/5.0 (iPod touch; CPU iPhone OS 15_7 like Mac OS X) AppleWebKit/605.1.15 " +
36+
"(KHTML, like Gecko) Version/15.6 Mobile/15E148 Safari/604.1",
37+
"iPod",
38+
5,
39+
)), true);
40+
});
41+
42+
it("detects iPadOS when it uses a desktop user agent", () => {
43+
const iPadOSNavigator = browserNavigator(
44+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15) AppleWebKit/605.1.15 " +
45+
"(KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1",
46+
"MacIntel",
47+
5,
48+
);
49+
assert.equal(isIPadOSPlatform(iPadOSNavigator), true);
50+
assert.equal(isIOSPlatform(iPadOSNavigator), true);
51+
});
52+
53+
it("does not classify desktop or Android browsers as iOS", () => {
54+
assert.equal(isIOSPlatform(browserNavigator(
55+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 " +
56+
"(KHTML, like Gecko) Version/17.6 Safari/605.1.15",
57+
"MacIntel",
58+
0,
59+
)), false);
60+
assert.equal(isIOSPlatform(browserNavigator(
61+
"Mozilla/5.0 (Linux; Android 15; Pixel 9) AppleWebKit/537.36 " +
62+
"(KHTML, like Gecko) Chrome/128.0.0.0 Mobile Safari/537.36",
63+
"Linux armv8l",
64+
5,
65+
)), false);
66+
});
67+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export type TBrowserNavigator = Pick<Navigator, "maxTouchPoints" | "platform" | "userAgent">;
2+
3+
export const isIPadOSPlatform = (browserNavigator: TBrowserNavigator) => {
4+
return browserNavigator.userAgent.includes("iPad") ||
5+
(browserNavigator.platform === "MacIntel" && browserNavigator.maxTouchPoints > 1);
6+
};
7+
8+
export const isIOSPlatform = (browserNavigator: TBrowserNavigator) => {
9+
return /iPhone|iPod/.test(browserNavigator.userAgent) || isIPadOSPlatform(browserNavigator);
10+
};

app/src/protyle/util/compatibility.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {genUUID} from "../../util/genID";
1313
import {buildBlockDOMClipboardData} from "./blockDOMClipboard";
1414
import {buildWebClipboardHTML, getTextSiyuanFromTextHTML} from "./clipboardData";
1515
import {prepareExternalClipboardHTML} from "./richClipboard";
16+
import {isIOSPlatform, isIPadOSPlatform} from "./browserCompatibility";
1617

1718
export {encodeBase64, getTextSiyuanFromTextHTML} from "./clipboardData";
1819

@@ -524,13 +525,17 @@ export const isIPhone = () => {
524525
return navigator.userAgent.indexOf("iPhone") > -1;
525526
};
526527

528+
export const isIOSDevice = () => {
529+
return isIOSPlatform(navigator);
530+
};
531+
527532
export const isSafari = () => {
528533
const userAgent = navigator.userAgent;
529534
return userAgent.includes("Safari") && !userAgent.includes("Chrome") && !userAgent.includes("Chromium");
530535
};
531536

532537
export const isIPad = () => {
533-
return navigator.userAgent.indexOf("iPad") > -1;
538+
return isIPadOSPlatform(navigator);
534539
};
535540

536541
export const isMac = () => {

0 commit comments

Comments
 (0)