-
-
Notifications
You must be signed in to change notification settings - Fork 210
Expand file tree
/
Copy pathread_only.js
More file actions
119 lines (108 loc) · 5.04 KB
/
read_only.js
File metadata and controls
119 lines (108 loc) · 5.04 KB
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
class ReadOnlyPlugin extends BasePlugin {
styleTemplate = () => true
hotkey = () => [{ hotkey: this.config.HOTKEY, callback: this.call }]
process = () => {
this.inReadOnlyMode = false
this.eventHandlers = this._buildEventHandlers()
this.utils.eventHub.addEventListener(this.utils.eventHub.eventType.allPluginsHadInjected, () => {
this.utils.decorator.afterCall(() => File, "freshLock", this._afterFreshLock)
if (this.config.READ_ONLY_DEFAULT) {
this.utils.waitUntil(() => File?.lock).then(this.toggleLock)
}
})
}
_afterFreshLock = () => {
const updateCheckbox = wantToLock => {
const elements = this.utils.entities.querySelectorAllInWrite('input[type="checkbox"]')
elements.forEach(box => box.toggleAttribute("disabled", wantToLock))
}
const updateInput = wantToLock => {
if (!wantToLock) return
const selectors = ["#typora-quick-open-input input", "#plugin-search-multi-form input", "#plugin-commander-form input", "#plugin-command-palette-input", "#plugin-ripgrep-form input"]
selectors.forEach(s => document.querySelector(s)?.removeAttribute("readonly"))
}
const updateReplaceButton = wantToLock => {
const selectors = ["#search-panel-replace-btn", "#search-panel-replaceall-btn", "#search-panel-replace-input"]
selectors.forEach(s => document.querySelector(s).toggleAttribute("disabled", wantToLock))
}
const wantToLock = File.isLocked
updateCheckbox(wantToLock)
updateInput(wantToLock)
updateReplaceButton(wantToLock)
}
_buildEventHandlers = () => {
const forbiddenKeys = ["Enter", "Backspace", "Delete", " "]
const isInline = el => el.closest('#write span[md-inline="image"], #write span[md-inline="inline_math"]')
const isLink = el => el.closest('#write span[md-inline="link"], #write .md-link')
const stopEvent = ev => {
if (File.isLocked) {
document.activeElement.blur()
ev.preventDefault()
ev.stopPropagation()
File.lock()
}
}
const stopForbiddenKey = ev => {
if (File.isLocked && forbiddenKeys.includes(ev.key)) stopEvent(ev)
}
const recoverExpand = ev => {
if (!isInline(ev.target)) $(".md-expand").removeClass("md-expand")
}
const openHyperlink = ev => {
if (this.config.DISABLE_EXPAND_WHEN_READ_ONLY && isInline(ev.target)) {
ev.stopPropagation()
ev.preventDefault()
return
}
if (this.config.CLICK_HYPERLINK_TO_OPEN_WHEN_READ_ONLY && !this.utils.metaKeyPressed(ev) && isLink(ev.target)) {
ev.stopPropagation()
ev.preventDefault()
const dict = { ctrlKey: true, metaKey: true, bubbles: true, cancelable: true }
ev.target.dispatchEvent(new MouseEvent("click", dict))
}
}
const handlers = { keydown: stopForbiddenKey, compositionstart: stopEvent, compositionend: stopEvent, paste: stopEvent }
if (this.config.CLICK_HYPERLINK_TO_OPEN_WHEN_READ_ONLY || this.config.DISABLE_EXPAND_WHEN_READ_ONLY) {
handlers.click = openHyperlink
}
if (this.config.AUTO_COLLAPSE_WHEN_READ_ONLY) {
handlers.mousedown = recoverExpand
}
return handlers
}
_toggleLock = (wantToLock) => {
const handleEvents = wantToLock => {
File[wantToLock ? "lock" : "unlock"]()
if (wantToLock) document.activeElement.blur()
const fn = wantToLock ? "addEventListener" : "removeEventListener"
for (const [ev, handler] of Object.entries(this.eventHandlers)) {
this.utils.entities.eWrite[fn](ev, handler, true)
}
}
const setLabel = wantToLock => {
if (!this.config.SHOW_TEXT) return
document.getElementById("footer-word-count-label").dataset.value = wantToLock ? this.config.SHOW_TEXT + String.fromCharCode(160).repeat(3) : ""
}
const toggleMenu = (wantToLock) => {
if (this.config.DISABLE_CONTEXT_MENU_WHEN_READ_ONLY) {
const exclude = "li" + this.config.REMAIN_AVAILABLE_MENU_KEY.map(key => `:not([data-key="${key}"])`).join("")
document.querySelectorAll(`#context-menu > ${exclude}`).forEach(el => el.classList.toggle("plu-disable-menu", wantToLock))
}
}
this.inReadOnlyMode = wantToLock
handleEvents(wantToLock)
setLabel(wantToLock)
toggleMenu(wantToLock)
}
toggleLock = () => this._toggleLock(!File.isLocked)
lock = () => this._toggleLock(true)
unlock = () => this._toggleLock(false)
call = () => {
this.toggleLock()
const msg = this.i18n.t(this.inReadOnlyMode ? "modeEnabled" : "modeDisabled")
this.utils.notification.show(msg)
}
}
module.exports = {
plugin: ReadOnlyPlugin
}