@kangsicj/dcinsideenhancer 1.2.2 → 1.3.1
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.en.md +2 -1
- package/README.md +2 -1
- package/dist/DCInsideEnhancer.meta.js +1 -1
- package/dist/DCInsideEnhancer.user.js +594 -40
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -64,7 +64,8 @@ One userscript for DCInside on mobile and PC: smart blocking, endless lists, ima
|
|
|
64
64
|
- Come back from a post and you're **right where you left off**
|
|
65
65
|
- Cleaner read-post colors and a back-to-top button
|
|
66
66
|
- Keyboard shortcuts on PC: **J/K** next/previous post, Enter to open, P to preview, S to scrap, / to search
|
|
67
|
-
- On PC,
|
|
67
|
+
- On PC, **press and hold** a title to preview the whole post, iPhone-style — blocked images and words stay hidden there too
|
|
68
|
+
- **Pin the order** of recently visited galleries — it stays put wherever you go
|
|
68
69
|
|
|
69
70
|
</td>
|
|
70
71
|
</tr>
|
package/README.md
CHANGED
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
- 글을 보고 돌아오면 **보던 위치 그대로**
|
|
65
65
|
- 읽은 글 색 정리, 맨 위로 버튼
|
|
66
66
|
- PC 키보드 단축키: **J/K** 다음·이전 글, Enter 열기, P 미리보기, S 스크랩, / 검색
|
|
67
|
-
- PC는
|
|
67
|
+
- PC는 아이폰처럼 제목을 **길게 누르면 글 전체 미리보기** — 차단 이미지·단어는 미리보기에서도 가림
|
|
68
|
+
- 최근 방문 갤러리 **순서 고정** — 어디를 가도 정한 순서 그대로
|
|
68
69
|
|
|
69
70
|
</td>
|
|
70
71
|
</tr>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @name DCInside Enhancer
|
|
3
3
|
// @name:ko 디시 인핸서
|
|
4
4
|
// @namespace https://github.com/kangsicj/DCInsideEnhancer
|
|
5
|
-
// @version 1.
|
|
5
|
+
// @version 1.3.1
|
|
6
6
|
// @description DCInside filter & enhancer — mobile & PC. Block users/words/heads/notices/images & GIFs across posts, infinite list, zoom viewer, theme sync, encrypted multi-device sync.
|
|
7
7
|
// @description:ko 디시인사이드 차단·편의 기능 (모바일·PC) - 유저·단어(제목/본문)·말머리·공지 차단, 같은/비슷한 이미지·움짤 모든 글 차단, 디시콘 제거, 차단 미디어 데이터 절약, 목록 자동 보충·무한 스크롤·뒤로 가기 위치 복원, 스크랩, 이미지 확대뷰 개선, 야간모드 자동 연동, 암호화 기기 간 동기화
|
|
8
8
|
// @author kangsicj
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// @name DCInside Enhancer
|
|
3
3
|
// @name:ko 디시 인핸서
|
|
4
4
|
// @namespace https://github.com/kangsicj/DCInsideEnhancer
|
|
5
|
-
// @version 1.
|
|
5
|
+
// @version 1.3.1
|
|
6
6
|
// @description DCInside filter & enhancer — mobile & PC. Block users/words/heads/notices/images & GIFs across posts, infinite list, zoom viewer, theme sync, encrypted multi-device sync.
|
|
7
7
|
// @description:ko 디시인사이드 차단·편의 기능 (모바일·PC) - 유저·단어(제목/본문)·말머리·공지 차단, 같은/비슷한 이미지·움짤 모든 글 차단, 디시콘 제거, 차단 미디어 데이터 절약, 목록 자동 보충·무한 스크롤·뒤로 가기 위치 복원, 스크랩, 이미지 확대뷰 개선, 야간모드 자동 연동, 암호화 기기 간 동기화
|
|
8
8
|
// @author kangsicj
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
// 0. 설정·상수
|
|
76
76
|
// =========================================================
|
|
77
77
|
|
|
78
|
-
const SCRIPT_VERSION = '1.
|
|
78
|
+
const SCRIPT_VERSION = '1.3.1';
|
|
79
79
|
const PROJECT_URL = 'https://github.com/kangsicj/DCInsideEnhancer';
|
|
80
80
|
const DONATE_URL = 'https://fairy.hada.io/@jinny#support';
|
|
81
81
|
|
|
@@ -106,6 +106,7 @@
|
|
|
106
106
|
syncLock: 'dc_sync_lock',
|
|
107
107
|
syncRt: 'dc_sync_rt',
|
|
108
108
|
recent: 'dc_recent_galls',
|
|
109
|
+
recentOrder: 'dc_recent_order',
|
|
109
110
|
recentNative: 'dc_recent_native',
|
|
110
111
|
searchHistory: 'dc_search_history',
|
|
111
112
|
blockHits: 'dc_block_hits',
|
|
@@ -221,11 +222,14 @@
|
|
|
221
222
|
hideAdSlots: true,
|
|
222
223
|
hideNewsRows: true,
|
|
223
224
|
hideCommentAds: true,
|
|
225
|
+
hideCommentFab: true,
|
|
226
|
+
mobileRecentStrip: true,
|
|
224
227
|
hideSilbeAlarm: true,
|
|
225
228
|
alarmBubble: true,
|
|
226
229
|
alarmKeepPolling: true,
|
|
227
230
|
keyboardShortcuts: true,
|
|
228
231
|
hoverPreview: true,
|
|
232
|
+
previewHover: false,
|
|
229
233
|
alarmSystemNotify: false,
|
|
230
234
|
pcFitWidth: true,
|
|
231
235
|
autoHideScrollbar: true,
|
|
@@ -474,7 +478,17 @@
|
|
|
474
478
|
html.dc-pc-fit .dcwrap :is(.cmt_info, .reply_info) > .fr { flex: 0 0 auto; float: none !important; margin-left: 10px; }
|
|
475
479
|
|
|
476
480
|
html.dc-pc-fit .dcwrap .writing_view_box { float: none !important; width: auto !important; }
|
|
477
|
-
html.dc-pc-fit .dcwrap .writing_view_box .write_div {
|
|
481
|
+
html.dc-pc-fit .dcwrap .writing_view_box .write_div {
|
|
482
|
+
width: auto !important;
|
|
483
|
+
max-width: min(100%, 900px) !important;
|
|
484
|
+
margin-left: auto !important;
|
|
485
|
+
margin-right: auto !important;
|
|
486
|
+
}
|
|
487
|
+
html.dc-pc-fit .dcwrap .writing_view_box .write_div :is(img, video, iframe) { margin-left: auto; margin-right: auto; }
|
|
488
|
+
html.dc-pc-fit .dcwrap .writing_view_box .write_div img { display: block; height: auto; }
|
|
489
|
+
|
|
490
|
+
html.dc-pc-fit .dcwrap .comment_count { display: flow-root; }
|
|
491
|
+
html.dc-pc-fit .dcwrap :is(.cmt_list, .comment_box) { clear: both; }
|
|
478
492
|
|
|
479
493
|
html.dc-pc-fit .dcwrap .bottom_paging_wrap {
|
|
480
494
|
display: flex !important;
|
|
@@ -507,6 +521,7 @@
|
|
|
507
521
|
html.dc-ad-slots-off .dcwrap :is(.stickyunit, .rightbanner, .rightbanner1, .banner_box, .ad_bottom_list, #ad_floating, .kakao_ad_area, .ad_top, .view_ad_wrap, .power_link, .con_banner.writing_banbox, #ad_nv_slot, ins.adsbygoogle),
|
|
508
522
|
html.dc-ad-slots-off :is(.adv-group, li.adv-inner, section.grid.clkhigh, #home-ad, .kakao_ad_area) { display: none !important; }
|
|
509
523
|
html.dc-news-rows-off :is(table.gall_list tr.ub-content[data-type="icon_fnews"], .gall-detail-lst > li:has(.sp-lst-fnews)) { display: none !important; }
|
|
524
|
+
html.dc-comment-fab-off :is(#cmt_fab, .fab-wrap:has(> #cmt_fab)) { display: none !important; }
|
|
510
525
|
html.dc-comment-ads-off :is(.comment_box li.ub-content.dory, .comment_box li.cmt_pw_ad, .all-comment-lst > li.dc-comment-boy) { display: none !important; }
|
|
511
526
|
html.dc-silbe-alarm-off :is(.alarm-popup.silbe-alarm, .rtbAlarmPopup) { display: none !important; }
|
|
512
527
|
html.dc-alarm-bubble :is(.alarm-popup.alarm-default, .alarmPopup) { display: none !important; }
|
|
@@ -1223,6 +1238,9 @@
|
|
|
1223
1238
|
#dc-custom-modal .dc-btn.mini.id-type { color: var(--dc-type-id); }
|
|
1224
1239
|
#dc-custom-modal .dc-btn.mini.nick-type { color: var(--dc-text-dim); }
|
|
1225
1240
|
|
|
1241
|
+
#dc-custom-modal .dc-btn:disabled { opacity: .35; cursor: default; }
|
|
1242
|
+
#dc-custom-modal .dc-btn.on-state { background: var(--dc-success); }
|
|
1243
|
+
|
|
1226
1244
|
#dc-custom-modal .dc-btn.mini.on {
|
|
1227
1245
|
border-color: var(--dc-danger);
|
|
1228
1246
|
background: var(--dc-danger);
|
|
@@ -2030,8 +2048,79 @@
|
|
|
2030
2048
|
font-weight: 700;
|
|
2031
2049
|
}
|
|
2032
2050
|
|
|
2051
|
+
#dc-preview-backdrop {
|
|
2052
|
+
position: fixed;
|
|
2053
|
+
inset: 0;
|
|
2054
|
+
z-index: 99996;
|
|
2055
|
+
background: rgba(0,0,0,.18);
|
|
2056
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.1);
|
|
2057
|
+
backdrop-filter: blur(14px) saturate(1.1);
|
|
2058
|
+
opacity: 0;
|
|
2059
|
+
visibility: hidden;
|
|
2060
|
+
transition: opacity .2s ease, visibility 0s linear .2s;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
html.dc-dark #dc-preview-backdrop { background: rgba(0,0,0,.4); }
|
|
2064
|
+
#dc-preview-backdrop.show { opacity: 1; visibility: visible; transition: opacity .2s ease, visibility 0s; }
|
|
2065
|
+
|
|
2066
|
+
#dc-preview.dc-pv-peek { transform: var(--dc-pv-from, translate(-50%, -50%) scale(.9)); transition: opacity .18s ease, transform .32s cubic-bezier(.2,.9,.3,1.15), visibility 0s linear .32s; }
|
|
2067
|
+
#dc-preview.dc-pv-peek.show { transform: translate(-50%, -50%); transition: opacity .18s ease, transform .32s cubic-bezier(.2,.9,.3,1.15), visibility 0s; }
|
|
2068
|
+
#dc-preview.dc-pv-peek { box-shadow: 0 24px 80px rgba(0,0,0,.35); }
|
|
2069
|
+
|
|
2033
2070
|
.dc-pv-anchor { text-decoration: underline !important; text-decoration-color: var(--dc-accent-ink) !important; }
|
|
2034
2071
|
|
|
2072
|
+
html.dc-recent-strip-on #lately_pop.dc-strip-lately #swiper-lately,
|
|
2073
|
+
html.dc-recent-strip-on #lately_pop.dc-strip-lately #lately_paging1 { display: none !important; }
|
|
2074
|
+
.dc-recent-strip {
|
|
2075
|
+
display: flex;
|
|
2076
|
+
gap: 8px;
|
|
2077
|
+
padding: 12px 12px 14px;
|
|
2078
|
+
overflow-x: auto;
|
|
2079
|
+
overflow-y: hidden;
|
|
2080
|
+
-webkit-overflow-scrolling: touch;
|
|
2081
|
+
scroll-snap-type: x proximity;
|
|
2082
|
+
scrollbar-width: none;
|
|
2083
|
+
overscroll-behavior-x: contain;
|
|
2084
|
+
}
|
|
2085
|
+
.dc-recent-strip::-webkit-scrollbar { display: none; }
|
|
2086
|
+
.dc-recent-strip[hidden] { display: none !important; }
|
|
2087
|
+
.dc-recent-strip .dc-rs-chip {
|
|
2088
|
+
flex: 0 0 auto;
|
|
2089
|
+
display: inline-flex;
|
|
2090
|
+
align-items: center;
|
|
2091
|
+
gap: 4px;
|
|
2092
|
+
max-width: 60vw;
|
|
2093
|
+
height: 36px;
|
|
2094
|
+
padding: 0 4px 0 14px;
|
|
2095
|
+
border: 1px solid var(--dc-border);
|
|
2096
|
+
border-radius: 999px;
|
|
2097
|
+
background: var(--dc-surface-2);
|
|
2098
|
+
color: var(--dc-text);
|
|
2099
|
+
font-size: 14px;
|
|
2100
|
+
font-weight: 600;
|
|
2101
|
+
text-decoration: none;
|
|
2102
|
+
white-space: nowrap;
|
|
2103
|
+
scroll-snap-align: start;
|
|
2104
|
+
}
|
|
2105
|
+
.dc-recent-strip .dc-rs-chip.here { border-color: var(--dc-accent-ink); color: var(--dc-accent-ink); background: var(--dc-accent-soft); }
|
|
2106
|
+
.dc-recent-strip .dc-rs-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
|
2107
|
+
.dc-recent-strip .dc-rs-kind { color: var(--dc-text-dim); font-size: 13px; }
|
|
2108
|
+
.dc-recent-strip .dc-rs-del {
|
|
2109
|
+
flex: 0 0 auto;
|
|
2110
|
+
width: 28px;
|
|
2111
|
+
height: 28px;
|
|
2112
|
+
margin: 0;
|
|
2113
|
+
padding: 0;
|
|
2114
|
+
border: none;
|
|
2115
|
+
border-radius: 50%;
|
|
2116
|
+
background: transparent;
|
|
2117
|
+
color: var(--dc-text-dim);
|
|
2118
|
+
font-size: 18px;
|
|
2119
|
+
line-height: 28px;
|
|
2120
|
+
}
|
|
2121
|
+
.dc-recent-strip .dc-rs-pin,
|
|
2122
|
+
.dc-recent-strip .dc-rs-empty { flex: 0 0 auto; align-self: center; padding: 0 6px; color: var(--dc-text-dim); font-size: 12px; white-space: nowrap; }
|
|
2123
|
+
|
|
2035
2124
|
.dc-key-cursor { outline: 2px solid var(--dc-accent-ink) !important; outline-offset: -2px; background: var(--dc-accent-soft) !important; }
|
|
2036
2125
|
|
|
2037
2126
|
#dc-custom-modal .dc-about {
|
|
@@ -3158,6 +3247,7 @@
|
|
|
3158
3247
|
root.classList.toggle('dc-ad-slots-off', settings.hideAdSlots !== false);
|
|
3159
3248
|
root.classList.toggle('dc-news-rows-off', settings.hideNewsRows !== false);
|
|
3160
3249
|
root.classList.toggle('dc-comment-ads-off', settings.hideCommentAds !== false);
|
|
3250
|
+
root.classList.toggle('dc-comment-fab-off', settings.hideCommentFab !== false);
|
|
3161
3251
|
root.classList.toggle('dc-silbe-alarm-off', settings.hideSilbeAlarm !== false);
|
|
3162
3252
|
root.classList.toggle('dc-alarm-bubble', settings.alarmBubble !== false);
|
|
3163
3253
|
root.classList.toggle('dc-hide-scrollbar', settings.autoHideScrollbar !== false && root.classList.contains('dc-classic-scrollbar'));
|
|
@@ -9507,7 +9597,10 @@
|
|
|
9507
9597
|
link.addEventListener('click', () => closeBlockModal());
|
|
9508
9598
|
actionsEl.appendChild(link);
|
|
9509
9599
|
} else {
|
|
9510
|
-
|
|
9600
|
+
const btn = makeButton(action.label, `mini ${action.className || ''}`, action.onClick);
|
|
9601
|
+
|
|
9602
|
+
btn.disabled = !!action.disabled;
|
|
9603
|
+
actionsEl.appendChild(btn);
|
|
9511
9604
|
}
|
|
9512
9605
|
});
|
|
9513
9606
|
|
|
@@ -10405,6 +10498,22 @@
|
|
|
10405
10498
|
off: '댓글돌이를 그대로 보여 줍니다.',
|
|
10406
10499
|
refresh: 'root'
|
|
10407
10500
|
},
|
|
10501
|
+
{
|
|
10502
|
+
group: 'clean',
|
|
10503
|
+
key: 'hideCommentFab',
|
|
10504
|
+
name: "떠 있는 '댓글로 이동' 버튼 숨기기 (모바일)",
|
|
10505
|
+
on: '글 화면 오른쪽 아래에 떠 있는 댓글 버튼을 숨깁니다. 본문 아래 [댓글] 링크와 차단 관리 버튼은 그대로입니다.',
|
|
10506
|
+
off: '댓글로 이동 버튼을 보여 줍니다.',
|
|
10507
|
+
refresh: 'root'
|
|
10508
|
+
},
|
|
10509
|
+
{
|
|
10510
|
+
group: 'clean',
|
|
10511
|
+
key: 'mobileRecentStrip',
|
|
10512
|
+
name: "'최근 방문'을 한 줄로 밀어 보기 (모바일)",
|
|
10513
|
+
on: '위쪽 [최근 방문]을 누르면 넓은 표 대신 갤러리가 순서대로 한 줄에 나오고, 옆으로 밀어 봅니다. 고정한 순서를 그대로 따릅니다.',
|
|
10514
|
+
off: '사이트 기본 표(2줄 × 4칸, 넘겨 보기)로 보여 줍니다.',
|
|
10515
|
+
refresh: 'root'
|
|
10516
|
+
},
|
|
10408
10517
|
{
|
|
10409
10518
|
group: 'clean',
|
|
10410
10519
|
key: 'hideAdSlots',
|
|
@@ -10490,9 +10599,18 @@
|
|
|
10490
10599
|
{
|
|
10491
10600
|
group: 'list',
|
|
10492
10601
|
key: 'hoverPreview',
|
|
10493
|
-
name: '
|
|
10494
|
-
on: '목록
|
|
10495
|
-
off: '
|
|
10602
|
+
name: '제목을 길게 누르면 글 미리보기 (PC)',
|
|
10603
|
+
on: '아이폰처럼 목록 제목을 길게 누르면 화면이 흐려지며 글 전체가 가운데에 떠오릅니다. 짧게 누르면 평소처럼 글로 갑니다. 창에서 본문을 누르면 글로 이동, 바깥을 누르거나 Esc 로 닫습니다. 스크랩·작성자 차단도 바로 할 수 있고, 차단한 이미지·단어는 미리보기에서도 가립니다. 키보드로 고른 글은 P 로 엽니다.',
|
|
10604
|
+
off: '미리보기를 쓰지 않습니다.',
|
|
10605
|
+
refresh: 'root'
|
|
10606
|
+
},
|
|
10607
|
+
{
|
|
10608
|
+
group: 'list',
|
|
10609
|
+
key: 'previewHover',
|
|
10610
|
+
parent: 'hoverPreview',
|
|
10611
|
+
name: '마우스를 올려 멈춰도 미리보기 (PC)',
|
|
10612
|
+
on: '제목 위에 마우스를 잠시 멈추면 누르지 않아도 미리보기가 뜹니다. 창 밖으로 마우스가 나가면 닫힙니다.',
|
|
10613
|
+
off: '길게 눌렀을 때만 미리보기가 뜹니다.',
|
|
10496
10614
|
refresh: 'root'
|
|
10497
10615
|
},
|
|
10498
10616
|
{
|
|
@@ -10688,6 +10806,10 @@
|
|
|
10688
10806
|
repinReadColors();
|
|
10689
10807
|
}
|
|
10690
10808
|
|
|
10809
|
+
if (item.key === 'mobileRecentStrip') {
|
|
10810
|
+
renderRecentStrip();
|
|
10811
|
+
}
|
|
10812
|
+
|
|
10691
10813
|
if (item.key === 'alarmBubble') {
|
|
10692
10814
|
paintAlarmBadge();
|
|
10693
10815
|
}
|
|
@@ -11759,7 +11881,7 @@
|
|
|
11759
11881
|
{ key: 'words', label: '단어', fields: ['keywords', 'titles'] },
|
|
11760
11882
|
{ key: 'heads', label: '말머리', fields: ['heads'] },
|
|
11761
11883
|
{ key: 'scraps', label: '스크랩', fields: ['scraps'] },
|
|
11762
|
-
{ key: 'recent', label: '최근 갤러리', fields: ['recent'] },
|
|
11884
|
+
{ key: 'recent', label: '최근 갤러리', fields: ['recent', 'recentOrder'] },
|
|
11763
11885
|
{ key: 'search', label: '검색 기록', fields: ['search'] },
|
|
11764
11886
|
{ key: 'settings', label: '설정', fields: ['settings'] }
|
|
11765
11887
|
];
|
|
@@ -11929,6 +12051,7 @@
|
|
|
11929
12051
|
scraps: scraps.map(item => ({ ...item })),
|
|
11930
12052
|
settings: syncedSettings(),
|
|
11931
12053
|
recent: collectRecentForSync(),
|
|
12054
|
+
recentOrder: collectRecentOrderForSync(),
|
|
11932
12055
|
search: collectSearchForSync(),
|
|
11933
12056
|
hits: collectHitsForSync()
|
|
11934
12057
|
});
|
|
@@ -12038,6 +12161,7 @@
|
|
|
12038
12161
|
scraps: mergeScraps(local.scraps, base && base.scraps, remote && remote.scraps),
|
|
12039
12162
|
settings: mergeSettings(local.settings, base && base.settings, remote && remote.settings),
|
|
12040
12163
|
recent: mergeRecent(local.recent, base && base.recent, remote && remote.recent),
|
|
12164
|
+
recentOrder: mergeRecentOrder(local.recentOrder, remote && remote.recentOrder),
|
|
12041
12165
|
search: mergeSearchHistory(local.search, base && base.search, remote && remote.search),
|
|
12042
12166
|
hits: mergeBlockHits(local.hits, remote && remote.hits)
|
|
12043
12167
|
};
|
|
@@ -12093,6 +12217,7 @@
|
|
|
12093
12217
|
const data = collectSyncData();
|
|
12094
12218
|
|
|
12095
12219
|
delete data.recent;
|
|
12220
|
+
delete data.recentOrder;
|
|
12096
12221
|
delete data.search;
|
|
12097
12222
|
delete data.hits;
|
|
12098
12223
|
|
|
@@ -12100,6 +12225,7 @@
|
|
|
12100
12225
|
};
|
|
12101
12226
|
|
|
12102
12227
|
const applySyncData = data => {
|
|
12228
|
+
const orderChanged = data && 'recentOrder' in data ? applyRecentOrderFromSync(data.recentOrder) : false;
|
|
12103
12229
|
const recentChanged = data && 'recent' in data ? applyRecentFromSync(data.recent) : false;
|
|
12104
12230
|
const searchChanged = data && 'search' in data ? applySearchFromSync(data.search) : false;
|
|
12105
12231
|
const hitsChanged = data && 'hits' in data ? applyHitsFromSync(data.hits) : false;
|
|
@@ -12157,7 +12283,7 @@
|
|
|
12157
12283
|
refreshAfterBlockChange();
|
|
12158
12284
|
}
|
|
12159
12285
|
|
|
12160
|
-
return changed || recentChanged || searchChanged || hitsChanged;
|
|
12286
|
+
return changed || recentChanged || orderChanged || searchChanged || hitsChanged;
|
|
12161
12287
|
};
|
|
12162
12288
|
|
|
12163
12289
|
const saveSyncUndo = (before, incoming, summary, from) => {
|
|
@@ -13401,6 +13527,38 @@
|
|
|
13401
13527
|
};
|
|
13402
13528
|
};
|
|
13403
13529
|
|
|
13530
|
+
const readRecentOrder = () => {
|
|
13531
|
+
const stored = readObject(STORAGE.recentOrder);
|
|
13532
|
+
|
|
13533
|
+
return {
|
|
13534
|
+
fixed: stored.fixed === true,
|
|
13535
|
+
keys: Array.isArray(stored.keys) ? stored.keys.filter(key => typeof key === 'string').slice(0, 200) : [],
|
|
13536
|
+
at: Number(stored.at) || 0
|
|
13537
|
+
};
|
|
13538
|
+
};
|
|
13539
|
+
|
|
13540
|
+
let recentOrder = readRecentOrder();
|
|
13541
|
+
|
|
13542
|
+
const saveRecentOrder = patch => {
|
|
13543
|
+
recentOrder = { ...recentOrder, ...patch, at: Date.now() };
|
|
13544
|
+
writeJson(STORAGE.recentOrder, recentOrder);
|
|
13545
|
+
};
|
|
13546
|
+
|
|
13547
|
+
const orderRecent = list => {
|
|
13548
|
+
const byTime = [...list].sort((a, b) => b.at - a.at);
|
|
13549
|
+
|
|
13550
|
+
if (!recentOrder.fixed) {
|
|
13551
|
+
return byTime;
|
|
13552
|
+
}
|
|
13553
|
+
|
|
13554
|
+
const index = new Map(recentOrder.keys.map((key, i) => [key, i]));
|
|
13555
|
+
const known = byTime.filter(item => index.has(recentKeyOf(item))).sort((a, b) => index.get(recentKeyOf(a)) - index.get(recentKeyOf(b)));
|
|
13556
|
+
|
|
13557
|
+
const fresh = byTime.filter(item => !index.has(recentKeyOf(item))).reverse();
|
|
13558
|
+
|
|
13559
|
+
return [...known, ...fresh];
|
|
13560
|
+
};
|
|
13561
|
+
|
|
13404
13562
|
const tidyRecent = list => {
|
|
13405
13563
|
const best = new Map();
|
|
13406
13564
|
|
|
@@ -13413,7 +13571,62 @@
|
|
|
13413
13571
|
}
|
|
13414
13572
|
});
|
|
13415
13573
|
|
|
13416
|
-
|
|
13574
|
+
const kept = [...best.values()].sort((a, b) => b.at - a.at).slice(0, RECENT_LIMIT);
|
|
13575
|
+
const ordered = orderRecent(kept);
|
|
13576
|
+
|
|
13577
|
+
if (recentOrder.fixed) {
|
|
13578
|
+
const keys = ordered.map(recentKeyOf);
|
|
13579
|
+
|
|
13580
|
+
if (JSON.stringify(keys) !== JSON.stringify(recentOrder.keys.filter(key => keys.includes(key)))) {
|
|
13581
|
+
recentOrder = { ...recentOrder, keys };
|
|
13582
|
+
writeJson(STORAGE.recentOrder, recentOrder);
|
|
13583
|
+
}
|
|
13584
|
+
}
|
|
13585
|
+
|
|
13586
|
+
return ordered;
|
|
13587
|
+
};
|
|
13588
|
+
|
|
13589
|
+
const setRecentFixed = fixed => {
|
|
13590
|
+
saveRecentOrder({ fixed, keys: recentGalls.map(recentKeyOf) });
|
|
13591
|
+
recentGalls = tidyRecent(recentGalls);
|
|
13592
|
+
writeJson(STORAGE.recent, recentGalls);
|
|
13593
|
+
exportNativeRecent();
|
|
13594
|
+
reorderNativeRecentDom();
|
|
13595
|
+
};
|
|
13596
|
+
|
|
13597
|
+
const moveRecent = (item, step) => {
|
|
13598
|
+
const list = [...recentGalls];
|
|
13599
|
+
const from = list.indexOf(item);
|
|
13600
|
+
const to = Math.max(0, Math.min(list.length - 1, from + step));
|
|
13601
|
+
|
|
13602
|
+
if (from < 0 || from === to) {
|
|
13603
|
+
return;
|
|
13604
|
+
}
|
|
13605
|
+
|
|
13606
|
+
list.splice(to, 0, ...list.splice(from, 1));
|
|
13607
|
+
saveRecentOrder({ fixed: true, keys: list.map(recentKeyOf) });
|
|
13608
|
+
recentGalls = tidyRecent(list);
|
|
13609
|
+
writeJson(STORAGE.recent, recentGalls);
|
|
13610
|
+
exportNativeRecent();
|
|
13611
|
+
reorderNativeRecentDom();
|
|
13612
|
+
};
|
|
13613
|
+
|
|
13614
|
+
const reorderNativeRecentDom = () => {
|
|
13615
|
+
if (!IS_PC_SITE || !recentOrder.fixed) {
|
|
13616
|
+
return;
|
|
13617
|
+
}
|
|
13618
|
+
|
|
13619
|
+
const index = new Map(recentGalls.map((item, i) => [item.id, i]));
|
|
13620
|
+
|
|
13621
|
+
document.querySelectorAll('#visit_history .vst_listbox, .visit_tablist .under_listbox, #visit_history_lyr .vst_list').forEach(box => {
|
|
13622
|
+
const items = [...box.children].filter(li => li.tagName === 'LI');
|
|
13623
|
+
const idOf = li => li.querySelector('[data-id]')?.getAttribute('data-id') || (/lately_gall_(\S+)/.exec(li.className) || [])[1] || '';
|
|
13624
|
+
const sorted = [...items].sort((a, b) => (index.has(idOf(a)) ? index.get(idOf(a)) : 999) - (index.has(idOf(b)) ? index.get(idOf(b)) : 999));
|
|
13625
|
+
|
|
13626
|
+
if (sorted.some((li, i) => li !== items[i])) {
|
|
13627
|
+
sorted.forEach(li => box.appendChild(li));
|
|
13628
|
+
}
|
|
13629
|
+
});
|
|
13417
13630
|
};
|
|
13418
13631
|
|
|
13419
13632
|
let recentGalls = tidyRecent(readArray(STORAGE.recent));
|
|
@@ -13636,19 +13849,201 @@
|
|
|
13636
13849
|
saveRecent();
|
|
13637
13850
|
};
|
|
13638
13851
|
|
|
13852
|
+
const watchNativeRecentDom = () => {
|
|
13853
|
+
if (!IS_PC_SITE) {
|
|
13854
|
+
return;
|
|
13855
|
+
}
|
|
13856
|
+
|
|
13857
|
+
const target = document.getElementById('visit_history');
|
|
13858
|
+
|
|
13859
|
+
if (!target) {
|
|
13860
|
+
return;
|
|
13861
|
+
}
|
|
13862
|
+
|
|
13863
|
+
let timer = null;
|
|
13864
|
+
|
|
13865
|
+
new MutationObserver(() => {
|
|
13866
|
+
if (!recentOrder.fixed) {
|
|
13867
|
+
return;
|
|
13868
|
+
}
|
|
13869
|
+
|
|
13870
|
+
clearTimeout(timer);
|
|
13871
|
+
timer = setTimeout(reorderNativeRecentDom, 60);
|
|
13872
|
+
}).observe(target, { childList: true, subtree: true });
|
|
13873
|
+
|
|
13874
|
+
reorderNativeRecentDom();
|
|
13875
|
+
};
|
|
13876
|
+
|
|
13639
13877
|
const initRecentEarly = () => {
|
|
13640
13878
|
importNativeRecent();
|
|
13641
13879
|
exportNativeRecent();
|
|
13642
13880
|
};
|
|
13643
13881
|
|
|
13882
|
+
const fixNativeLatelyValue = value => {
|
|
13883
|
+
if (!recentOrder.fixed) {
|
|
13884
|
+
return value;
|
|
13885
|
+
}
|
|
13886
|
+
|
|
13887
|
+
try {
|
|
13888
|
+
const parts = unescape(String(value)).split(',').filter(Boolean);
|
|
13889
|
+
const index = new Map(recentGalls.map((item, i) => [item.id, i]));
|
|
13890
|
+
const seen = new Set();
|
|
13891
|
+
const unique = parts.filter(part => {
|
|
13892
|
+
const id = part.split('|')[0];
|
|
13893
|
+
|
|
13894
|
+
if (!id || seen.has(id)) {
|
|
13895
|
+
return false;
|
|
13896
|
+
}
|
|
13897
|
+
|
|
13898
|
+
seen.add(id);
|
|
13899
|
+
return true;
|
|
13900
|
+
});
|
|
13901
|
+
const known = unique.filter(part => index.has(part.split('|')[0])).sort((a, b) => index.get(a.split('|')[0]) - index.get(b.split('|')[0]));
|
|
13902
|
+
const fresh = unique.filter(part => !index.has(part.split('|')[0]));
|
|
13903
|
+
|
|
13904
|
+
return escape([...known, ...fresh].map(part => `${part},`).join(''));
|
|
13905
|
+
} catch {
|
|
13906
|
+
return value;
|
|
13907
|
+
}
|
|
13908
|
+
};
|
|
13909
|
+
|
|
13910
|
+
if (IS_MOBILE_SITE) {
|
|
13911
|
+
try {
|
|
13912
|
+
const proto = window.Storage && window.Storage.prototype;
|
|
13913
|
+
const original = proto && proto.setItem;
|
|
13914
|
+
|
|
13915
|
+
if (original && !original.__dcLately) {
|
|
13916
|
+
const patched = function (key, value) {
|
|
13917
|
+
if (this === window.localStorage && key === 'm_dcinside_lately') {
|
|
13918
|
+
return original.call(this, key, fixNativeLatelyValue(value));
|
|
13919
|
+
}
|
|
13920
|
+
|
|
13921
|
+
return original.call(this, key, value);
|
|
13922
|
+
};
|
|
13923
|
+
|
|
13924
|
+
patched.__dcLately = true;
|
|
13925
|
+
proto.setItem = patched;
|
|
13926
|
+
}
|
|
13927
|
+
} catch {
|
|
13928
|
+
}
|
|
13929
|
+
}
|
|
13930
|
+
|
|
13931
|
+
const renderRecentStrip = () => {
|
|
13932
|
+
const pop = document.getElementById('lately_pop');
|
|
13933
|
+
|
|
13934
|
+
if (!IS_MOBILE_SITE || !pop || settings.mobileRecentStrip === false) {
|
|
13935
|
+
document.documentElement.classList.remove('dc-recent-strip-on');
|
|
13936
|
+
pop?.querySelector('.dc-recent-strip')?.remove();
|
|
13937
|
+
return;
|
|
13938
|
+
}
|
|
13939
|
+
|
|
13940
|
+
const latelyTab = document.getElementById('lately_gall');
|
|
13941
|
+
const showing = !latelyTab || latelyTab.classList.contains('on');
|
|
13942
|
+
let strip = pop.querySelector('.dc-recent-strip');
|
|
13943
|
+
|
|
13944
|
+
if (!strip) {
|
|
13945
|
+
strip = h('div', 'dc-ui dc-recent-strip');
|
|
13946
|
+
strip.setAttribute('role', 'list');
|
|
13947
|
+
const slider = pop.querySelector('#swiper-lately') || pop.querySelector('.vst-slider');
|
|
13948
|
+
|
|
13949
|
+
(slider ? slider.parentNode : pop).insertBefore(strip, slider || null);
|
|
13950
|
+
}
|
|
13951
|
+
|
|
13952
|
+
document.documentElement.classList.add('dc-recent-strip-on');
|
|
13953
|
+
strip.hidden = !showing;
|
|
13954
|
+
pop.classList.toggle('dc-strip-lately', showing);
|
|
13955
|
+
|
|
13956
|
+
if (!showing) {
|
|
13957
|
+
return;
|
|
13958
|
+
}
|
|
13959
|
+
|
|
13960
|
+
const keepScroll = strip.scrollLeft;
|
|
13961
|
+
|
|
13962
|
+
strip.textContent = '';
|
|
13963
|
+
|
|
13964
|
+
if (!recentGalls.length) {
|
|
13965
|
+
strip.appendChild(h('span', 'dc-rs-empty', '최근 방문한 갤러리가 없습니다'));
|
|
13966
|
+
return;
|
|
13967
|
+
}
|
|
13968
|
+
|
|
13969
|
+
const here = (currentGalleryVisit() || {}).id;
|
|
13970
|
+
|
|
13971
|
+
recentGalls.forEach(item => {
|
|
13972
|
+
const chip = h('a', `dc-rs-chip${item.id === here ? ' here' : ''}`);
|
|
13973
|
+
|
|
13974
|
+
chip.href = recentUrl(item);
|
|
13975
|
+
chip.setAttribute('role', 'listitem');
|
|
13976
|
+
chip.appendChild(h('span', 'dc-rs-name', item.n || item.id));
|
|
13977
|
+
|
|
13978
|
+
if (RECENT_KIND_LABEL[item.k]) {
|
|
13979
|
+
chip.appendChild(h('span', 'dc-rs-kind', item.k === 'M' ? 'ⓜ' : item.k === 'N' ? 'ⓝ' : 'ⓟ'));
|
|
13980
|
+
}
|
|
13981
|
+
|
|
13982
|
+
const del = h('button', 'dc-rs-del', '×');
|
|
13983
|
+
|
|
13984
|
+
del.type = 'button';
|
|
13985
|
+
del.setAttribute('aria-label', `${item.n || item.id} 지우기`);
|
|
13986
|
+
del.addEventListener('click', event => {
|
|
13987
|
+
event.preventDefault();
|
|
13988
|
+
event.stopPropagation();
|
|
13989
|
+
recentGalls = recentGalls.filter(other => other !== item);
|
|
13990
|
+
saveRecent();
|
|
13991
|
+
exportNativeRecent();
|
|
13992
|
+
renderRecentStrip();
|
|
13993
|
+
});
|
|
13994
|
+
chip.appendChild(del);
|
|
13995
|
+
strip.appendChild(chip);
|
|
13996
|
+
});
|
|
13997
|
+
|
|
13998
|
+
if (recentOrder.fixed) {
|
|
13999
|
+
strip.appendChild(h('span', 'dc-rs-pin', '📌 순서 고정'));
|
|
14000
|
+
}
|
|
14001
|
+
|
|
14002
|
+
strip.scrollLeft = keepScroll;
|
|
14003
|
+
|
|
14004
|
+
strip.querySelector('.dc-rs-chip.here')?.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });
|
|
14005
|
+
};
|
|
14006
|
+
|
|
14007
|
+
const watchRecentStrip = () => {
|
|
14008
|
+
const pop = document.getElementById('lately_pop');
|
|
14009
|
+
|
|
14010
|
+
if (!IS_MOBILE_SITE || !pop) {
|
|
14011
|
+
return;
|
|
14012
|
+
}
|
|
14013
|
+
|
|
14014
|
+
let timer = null;
|
|
14015
|
+
const refresh = () => {
|
|
14016
|
+
clearTimeout(timer);
|
|
14017
|
+
timer = setTimeout(() => {
|
|
14018
|
+
if (pop.style.display !== 'none') {
|
|
14019
|
+
importNativeRecent();
|
|
14020
|
+
renderRecentStrip();
|
|
14021
|
+
}
|
|
14022
|
+
}, 30);
|
|
14023
|
+
};
|
|
14024
|
+
|
|
14025
|
+
new MutationObserver(refresh).observe(pop, { attributes: true, attributeFilter: ['style'] });
|
|
14026
|
+
|
|
14027
|
+
const tabs = pop.querySelector('.tab-lst');
|
|
14028
|
+
|
|
14029
|
+
if (tabs) {
|
|
14030
|
+
new MutationObserver(refresh).observe(tabs, { attributes: true, subtree: true, attributeFilter: ['class'] });
|
|
14031
|
+
}
|
|
14032
|
+
|
|
14033
|
+
renderRecentStrip();
|
|
14034
|
+
};
|
|
14035
|
+
|
|
13644
14036
|
const initRecent = () => {
|
|
13645
14037
|
importNativeRecent();
|
|
13646
14038
|
recordGalleryVisit();
|
|
13647
14039
|
exportNativeRecent();
|
|
14040
|
+
watchNativeRecentDom();
|
|
14041
|
+
watchRecentStrip();
|
|
13648
14042
|
|
|
13649
14043
|
const follow = () => {
|
|
13650
|
-
if (document.visibilityState === 'visible' && importNativeRecent()) {
|
|
14044
|
+
if (document.visibilityState === 'visible' && (importNativeRecent() || recentOrder.fixed)) {
|
|
13651
14045
|
exportNativeRecent();
|
|
14046
|
+
reorderNativeRecentDom();
|
|
13652
14047
|
}
|
|
13653
14048
|
};
|
|
13654
14049
|
|
|
@@ -13658,6 +14053,31 @@
|
|
|
13658
14053
|
|
|
13659
14054
|
const collectRecentForSync = () => recentGalls.map(item => ({ ...item }));
|
|
13660
14055
|
|
|
14056
|
+
const collectRecentOrderForSync = () => ({ ...recentOrder, keys: [...recentOrder.keys] });
|
|
14057
|
+
|
|
14058
|
+
const mergeRecentOrder = (local, remote) => {
|
|
14059
|
+
if (!remote || typeof remote !== 'object' || !Array.isArray(remote.keys)) {
|
|
14060
|
+
return local;
|
|
14061
|
+
}
|
|
14062
|
+
|
|
14063
|
+
return (Number(remote.at) || 0) > (Number(local && local.at) || 0) ? remote : local;
|
|
14064
|
+
};
|
|
14065
|
+
|
|
14066
|
+
const applyRecentOrderFromSync = data => {
|
|
14067
|
+
if (!data || typeof data !== 'object' || !Array.isArray(data.keys) || (Number(data.at) || 0) <= recentOrder.at) {
|
|
14068
|
+
return false;
|
|
14069
|
+
}
|
|
14070
|
+
|
|
14071
|
+
recentOrder = { fixed: data.fixed === true, keys: data.keys.filter(key => typeof key === 'string').slice(0, 200), at: Number(data.at) };
|
|
14072
|
+
writeJson(STORAGE.recentOrder, recentOrder);
|
|
14073
|
+
recentGalls = tidyRecent(recentGalls);
|
|
14074
|
+
writeJson(STORAGE.recent, recentGalls);
|
|
14075
|
+
exportNativeRecent();
|
|
14076
|
+
reorderNativeRecentDom();
|
|
14077
|
+
|
|
14078
|
+
return true;
|
|
14079
|
+
};
|
|
14080
|
+
|
|
13661
14081
|
const mergeRecent = (local = [], base, remote) => {
|
|
13662
14082
|
if (!Array.isArray(remote)) {
|
|
13663
14083
|
return tidyRecent(local || []);
|
|
@@ -14246,18 +14666,35 @@
|
|
|
14246
14666
|
return;
|
|
14247
14667
|
}
|
|
14248
14668
|
|
|
14669
|
+
const orderRow = h('div', 'dc-btn-row');
|
|
14670
|
+
|
|
14671
|
+
orderRow.appendChild(makeButton(recentOrder.fixed ? '📌 순서 고정 중 · 끄기' : '📌 지금 순서로 고정', recentOrder.fixed ? 'wide on-state' : 'wide', () => {
|
|
14672
|
+
setRecentFixed(!recentOrder.fixed);
|
|
14673
|
+
showToast(recentOrder.fixed ? '📌 최근 방문 순서를 고정했습니다 · ↑↓ 로 바꿀 수 있어요' : '최근 방문 순서 고정을 풀었습니다 (방문한 순서로)');
|
|
14674
|
+
rerenderModal();
|
|
14675
|
+
}));
|
|
14676
|
+
area.appendChild(orderRow);
|
|
14677
|
+
|
|
14678
|
+
if (recentOrder.fixed) {
|
|
14679
|
+
area.appendChild(makeNote('고정한 순서는 디시 화면의 최근 방문 목록에도 그대로 보이고, 어느 갤러리를 가도 바뀌지 않습니다. 처음 가는 갤러리는 맨 뒤에 붙습니다.'));
|
|
14680
|
+
}
|
|
14681
|
+
|
|
14249
14682
|
const filterRow = makeFilterRow(recentGalls.length);
|
|
14250
14683
|
|
|
14251
14684
|
if (filterRow) {
|
|
14252
14685
|
area.appendChild(filterRow);
|
|
14253
14686
|
}
|
|
14254
14687
|
|
|
14255
|
-
recentGalls.forEach(item => {
|
|
14688
|
+
recentGalls.forEach((item, i) => {
|
|
14256
14689
|
area.appendChild(makeRow({
|
|
14257
14690
|
title: item.n || item.id,
|
|
14258
14691
|
chip: RECENT_KIND_LABEL[item.k] || '',
|
|
14259
14692
|
meta: [item.id, item.at ? timeAgo(item.at) : ''].filter(Boolean).join(' · '),
|
|
14260
14693
|
actions: [
|
|
14694
|
+
...(recentOrder.fixed ? [
|
|
14695
|
+
{ label: '↑', className: 'dc-icon-btn', onClick: () => { moveRecent(item, -1); rerenderModal(); }, disabled: i === 0 },
|
|
14696
|
+
{ label: '↓', className: 'dc-icon-btn', onClick: () => { moveRecent(item, 1); rerenderModal(); }, disabled: i === recentGalls.length - 1 }
|
|
14697
|
+
] : []),
|
|
14261
14698
|
{ label: '열기', href: recentUrl(item) },
|
|
14262
14699
|
{
|
|
14263
14700
|
label: '지우기',
|
|
@@ -14525,7 +14962,7 @@
|
|
|
14525
14962
|
|
|
14526
14963
|
// =========================================================
|
|
14527
14964
|
|
|
14528
|
-
const CLEANUP_IDLE_DAYS =
|
|
14965
|
+
const CLEANUP_IDLE_DAYS = 7;
|
|
14529
14966
|
|
|
14530
14967
|
const cleanupSuggestions = () => {
|
|
14531
14968
|
flushBlockHits();
|
|
@@ -14762,7 +15199,11 @@
|
|
|
14762
15199
|
'</div>' +
|
|
14763
15200
|
'<div class="dc-pv-body"></div>';
|
|
14764
15201
|
previewEl.addEventListener('mouseenter', () => clearTimeout(previewCloseTimer));
|
|
14765
|
-
previewEl.addEventListener('mouseleave', () =>
|
|
15202
|
+
previewEl.addEventListener('mouseleave', () => {
|
|
15203
|
+
if (previewMode === 'hover') {
|
|
15204
|
+
schedulePreviewClose();
|
|
15205
|
+
}
|
|
15206
|
+
});
|
|
14766
15207
|
document.body.appendChild(previewEl);
|
|
14767
15208
|
|
|
14768
15209
|
return previewEl;
|
|
@@ -14780,6 +15221,7 @@
|
|
|
14780
15221
|
|
|
14781
15222
|
clearTimeout(previewCloseTimer);
|
|
14782
15223
|
stopPreviewTheme();
|
|
15224
|
+
previewBackdrop?.classList.remove('show');
|
|
14783
15225
|
|
|
14784
15226
|
if (previewEl) {
|
|
14785
15227
|
previewEl.classList.remove('show');
|
|
@@ -14957,6 +15399,20 @@
|
|
|
14957
15399
|
doc.getElementById('dc-pv-css').textContent = previewFrameCss();
|
|
14958
15400
|
doc.body.appendChild(doc.importNode(body, true));
|
|
14959
15401
|
|
|
15402
|
+
doc.querySelectorAll('img').forEach(img => {
|
|
15403
|
+
let tries = 0;
|
|
15404
|
+
const original = img.getAttribute('src') || '';
|
|
15405
|
+
|
|
15406
|
+
img.addEventListener('error', () => {
|
|
15407
|
+
if (tries >= 4 || !/dcinside\.(com|co\.kr)\//.test(original)) {
|
|
15408
|
+
return;
|
|
15409
|
+
}
|
|
15410
|
+
|
|
15411
|
+
tries += 1;
|
|
15412
|
+
setTimeout(() => img.setAttribute('src', `${original}&${tries + 1}`), 250 * tries);
|
|
15413
|
+
});
|
|
15414
|
+
});
|
|
15415
|
+
|
|
14960
15416
|
doc.querySelectorAll('video[data-src]').forEach(video => {
|
|
14961
15417
|
const gif = video.getAttribute('data-src');
|
|
14962
15418
|
let swapped = false;
|
|
@@ -15220,18 +15676,135 @@
|
|
|
15220
15676
|
}
|
|
15221
15677
|
};
|
|
15222
15678
|
|
|
15679
|
+
const PREVIEW_HOLD_MS = 350;
|
|
15680
|
+
let previewMode = 'peek';
|
|
15681
|
+
let previewBackdrop = null;
|
|
15682
|
+
|
|
15683
|
+
const ensurePreviewBackdrop = () => {
|
|
15684
|
+
if (previewBackdrop && previewBackdrop.isConnected) {
|
|
15685
|
+
return previewBackdrop;
|
|
15686
|
+
}
|
|
15687
|
+
|
|
15688
|
+
previewBackdrop = h('div', 'dc-ui');
|
|
15689
|
+
previewBackdrop.id = 'dc-preview-backdrop';
|
|
15690
|
+
previewBackdrop.addEventListener('mousedown', event => {
|
|
15691
|
+
event.preventDefault();
|
|
15692
|
+
event.stopPropagation();
|
|
15693
|
+
closePreview();
|
|
15694
|
+
});
|
|
15695
|
+
document.body.appendChild(previewBackdrop);
|
|
15696
|
+
|
|
15697
|
+
return previewBackdrop;
|
|
15698
|
+
};
|
|
15699
|
+
|
|
15700
|
+
const openPreview = (anchor, mode) => {
|
|
15701
|
+
previewMode = mode;
|
|
15702
|
+
|
|
15703
|
+
const el = ensurePreviewEl();
|
|
15704
|
+
|
|
15705
|
+
el.classList.toggle('dc-pv-peek', mode === 'peek');
|
|
15706
|
+
|
|
15707
|
+
try {
|
|
15708
|
+
const r = anchor.getBoundingClientRect();
|
|
15709
|
+
const ox = Math.round(r.left + Math.min(r.width, 240) / 2 - window.innerWidth / 2);
|
|
15710
|
+
const oy = Math.round(r.top + r.height / 2 - window.innerHeight / 2);
|
|
15711
|
+
|
|
15712
|
+
el.style.setProperty('--dc-pv-from', `translate(calc(-50% + ${ox}px), calc(-50% + ${oy}px)) scale(.35)`);
|
|
15713
|
+
} catch {
|
|
15714
|
+
el.style.removeProperty('--dc-pv-from');
|
|
15715
|
+
}
|
|
15716
|
+
|
|
15717
|
+
if (mode === 'peek') {
|
|
15718
|
+
ensurePreviewBackdrop().classList.add('show');
|
|
15719
|
+
} else {
|
|
15720
|
+
previewBackdrop?.classList.remove('show');
|
|
15721
|
+
}
|
|
15722
|
+
|
|
15723
|
+
showPreviewFor(anchor);
|
|
15724
|
+
};
|
|
15725
|
+
|
|
15223
15726
|
const initHoverPreview = () => {
|
|
15224
15727
|
if (!IS_PC_SITE) {
|
|
15225
15728
|
return;
|
|
15226
15729
|
}
|
|
15227
15730
|
|
|
15731
|
+
const hoverOn = () => previewEnabled() && settings.previewHover === true;
|
|
15732
|
+
|
|
15228
15733
|
let hoverAnchor = null;
|
|
15229
15734
|
let pressedAnchor = null;
|
|
15735
|
+
let holdTimer = null;
|
|
15736
|
+
let holdStart = null;
|
|
15737
|
+
let swallowClick = null;
|
|
15738
|
+
|
|
15739
|
+
document.addEventListener('mousedown', event => {
|
|
15740
|
+
const anchor = event.target instanceof Element ? event.target.closest(PREVIEW_TITLE_SELECTOR) : null;
|
|
15741
|
+
|
|
15742
|
+
if (!anchor || anchor.closest('.dc-ui')) {
|
|
15743
|
+
if (previewOpen() && !(event.target instanceof Node && previewEl.contains(event.target))) {
|
|
15744
|
+
closePreview();
|
|
15745
|
+
}
|
|
15746
|
+
|
|
15747
|
+
return;
|
|
15748
|
+
}
|
|
15749
|
+
|
|
15750
|
+
pressedAnchor = anchor;
|
|
15751
|
+
clearTimeout(previewHoverTimer);
|
|
15752
|
+
|
|
15753
|
+
if (!previewEnabled() || event.button !== 0 || event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) {
|
|
15754
|
+
return;
|
|
15755
|
+
}
|
|
15756
|
+
|
|
15757
|
+
holdStart = { x: event.clientX, y: event.clientY };
|
|
15758
|
+
clearTimeout(holdTimer);
|
|
15759
|
+
holdTimer = setTimeout(() => {
|
|
15760
|
+
holdTimer = null;
|
|
15761
|
+
swallowClick = anchor;
|
|
15762
|
+
|
|
15763
|
+
window.getSelection?.()?.removeAllRanges?.();
|
|
15764
|
+
openPreview(anchor, 'peek');
|
|
15765
|
+
}, PREVIEW_HOLD_MS);
|
|
15766
|
+
}, true);
|
|
15767
|
+
|
|
15768
|
+
document.addEventListener('mousemove', event => {
|
|
15769
|
+
if (holdTimer && holdStart && Math.hypot(event.clientX - holdStart.x, event.clientY - holdStart.y) > 8) {
|
|
15770
|
+
clearTimeout(holdTimer);
|
|
15771
|
+
holdTimer = null;
|
|
15772
|
+
}
|
|
15773
|
+
}, { passive: true, capture: true });
|
|
15774
|
+
|
|
15775
|
+
const cancelHold = () => {
|
|
15776
|
+
clearTimeout(holdTimer);
|
|
15777
|
+
holdTimer = null;
|
|
15778
|
+
};
|
|
15779
|
+
|
|
15780
|
+
document.addEventListener('mouseup', cancelHold, true);
|
|
15781
|
+
document.addEventListener('dragstart', event => {
|
|
15782
|
+
if (swallowClick || holdTimer) {
|
|
15783
|
+
event.preventDefault();
|
|
15784
|
+
}
|
|
15785
|
+
|
|
15786
|
+
cancelHold();
|
|
15787
|
+
}, true);
|
|
15788
|
+
|
|
15789
|
+
document.addEventListener('click', event => {
|
|
15790
|
+
if (!swallowClick) {
|
|
15791
|
+
return;
|
|
15792
|
+
}
|
|
15793
|
+
|
|
15794
|
+
const anchor = event.target instanceof Element ? event.target.closest(PREVIEW_TITLE_SELECTOR) : null;
|
|
15795
|
+
|
|
15796
|
+
if (anchor === swallowClick) {
|
|
15797
|
+
event.preventDefault();
|
|
15798
|
+
event.stopImmediatePropagation();
|
|
15799
|
+
}
|
|
15800
|
+
|
|
15801
|
+
swallowClick = null;
|
|
15802
|
+
}, true);
|
|
15230
15803
|
|
|
15231
15804
|
const armHover = anchor => {
|
|
15232
15805
|
clearTimeout(previewHoverTimer);
|
|
15233
15806
|
|
|
15234
|
-
if (!
|
|
15807
|
+
if (!hoverOn() || anchor === pressedAnchor || (previewOpen() && previewMode === 'peek')) {
|
|
15235
15808
|
return;
|
|
15236
15809
|
}
|
|
15237
15810
|
|
|
@@ -15243,18 +15816,14 @@
|
|
|
15243
15816
|
}
|
|
15244
15817
|
|
|
15245
15818
|
clearTimeout(previewCloseTimer);
|
|
15246
|
-
|
|
15819
|
+
openPreview(anchor, 'hover');
|
|
15247
15820
|
}, switching ? PREVIEW_SWITCH_DELAY : PREVIEW_DELAY);
|
|
15248
15821
|
};
|
|
15249
15822
|
|
|
15250
15823
|
document.addEventListener('mouseover', event => {
|
|
15251
15824
|
const anchor = event.target instanceof Element ? event.target.closest(PREVIEW_TITLE_SELECTOR) : null;
|
|
15252
15825
|
|
|
15253
|
-
if (!anchor || anchor.closest('.dc-ui')) {
|
|
15254
|
-
return;
|
|
15255
|
-
}
|
|
15256
|
-
|
|
15257
|
-
if (anchor === hoverAnchor) {
|
|
15826
|
+
if (!anchor || anchor.closest('.dc-ui') || anchor === hoverAnchor) {
|
|
15258
15827
|
return;
|
|
15259
15828
|
}
|
|
15260
15829
|
|
|
@@ -15265,7 +15834,7 @@
|
|
|
15265
15834
|
return;
|
|
15266
15835
|
}
|
|
15267
15836
|
|
|
15268
|
-
if (previewOpen()) {
|
|
15837
|
+
if (previewOpen() && previewMode === 'hover') {
|
|
15269
15838
|
clearTimeout(previewCloseTimer);
|
|
15270
15839
|
}
|
|
15271
15840
|
|
|
@@ -15282,15 +15851,6 @@
|
|
|
15282
15851
|
}
|
|
15283
15852
|
}, { passive: true });
|
|
15284
15853
|
|
|
15285
|
-
document.addEventListener('mousedown', event => {
|
|
15286
|
-
const anchor = event.target instanceof Element ? event.target.closest(PREVIEW_TITLE_SELECTOR) : null;
|
|
15287
|
-
|
|
15288
|
-
if (anchor) {
|
|
15289
|
-
pressedAnchor = anchor;
|
|
15290
|
-
clearTimeout(previewHoverTimer);
|
|
15291
|
-
}
|
|
15292
|
-
}, true);
|
|
15293
|
-
|
|
15294
15854
|
document.addEventListener('mouseout', event => {
|
|
15295
15855
|
const anchor = event.target instanceof Element ? event.target.closest(PREVIEW_TITLE_SELECTOR) : null;
|
|
15296
15856
|
|
|
@@ -15308,19 +15868,13 @@
|
|
|
15308
15868
|
|
|
15309
15869
|
clearTimeout(previewHoverTimer);
|
|
15310
15870
|
|
|
15311
|
-
if (previewOpen() && !(event.relatedTarget instanceof Node && previewEl.contains(event.relatedTarget))) {
|
|
15871
|
+
if (previewOpen() && previewMode === 'hover' && !(event.relatedTarget instanceof Node && previewEl.contains(event.relatedTarget))) {
|
|
15312
15872
|
schedulePreviewClose();
|
|
15313
15873
|
}
|
|
15314
15874
|
});
|
|
15315
15875
|
|
|
15316
|
-
document.addEventListener('mousedown', event => {
|
|
15317
|
-
if (previewOpen() && !(event.target instanceof Node && previewEl.contains(event.target))) {
|
|
15318
|
-
closePreview();
|
|
15319
|
-
}
|
|
15320
|
-
}, true);
|
|
15321
|
-
|
|
15322
15876
|
window.addEventListener('scroll', () => {
|
|
15323
|
-
if (previewOpen() && !previewEl.matches(':hover')) {
|
|
15877
|
+
if (previewOpen() && previewMode === 'hover' && !previewEl.matches(':hover')) {
|
|
15324
15878
|
closePreview();
|
|
15325
15879
|
}
|
|
15326
15880
|
}, { passive: true });
|
|
@@ -15356,7 +15910,7 @@
|
|
|
15356
15910
|
return false;
|
|
15357
15911
|
}
|
|
15358
15912
|
|
|
15359
|
-
|
|
15913
|
+
openPreview(anchor, 'peek');
|
|
15360
15914
|
return true;
|
|
15361
15915
|
};
|
|
15362
15916
|
// =========================================================
|