annotate .cms/lib/codemirror/src/display/scrollbars.js @ 0:78edf6b517a0 draft

24.10
author Coffee CMS <info@coffee-cms.ru>
date Fri, 11 Oct 2024 22:40:23 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
1 import { addClass, elt, rmClass } from "../util/dom.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
2 import { on } from "../util/event.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
3 import { scrollGap, paddingVert } from "../measurement/position_measurement.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
4 import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
5 import { updateHeightsInViewport } from "./update_lines.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
6 import { Delayed } from "../util/misc.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
7
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
8 import { setScrollLeft, updateScrollTop } from "./scrolling.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
9
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
10 // SCROLLBARS
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
11
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
12 // Prepare DOM reads needed to update the scrollbars. Done in one
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
13 // shot to minimize update/measure roundtrips.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
14 export function measureForScrollbars(cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
15 let d = cm.display, gutterW = d.gutters.offsetWidth
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
16 let docH = Math.round(cm.doc.height + paddingVert(cm.display))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
17 return {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
18 clientHeight: d.scroller.clientHeight,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
19 viewHeight: d.wrapper.clientHeight,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
20 scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
21 viewWidth: d.wrapper.clientWidth,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
22 barLeft: cm.options.fixedGutter ? gutterW : 0,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
23 docHeight: docH,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
24 scrollHeight: docH + scrollGap(cm) + d.barHeight,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
25 nativeBarWidth: d.nativeBarWidth,
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
26 gutterWidth: gutterW
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
27 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
28 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
29
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
30 class NativeScrollbars {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
31 constructor(place, scroll, cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
32 this.cm = cm
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
33 let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
34 let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
35 vert.tabIndex = horiz.tabIndex = -1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
36 place(vert); place(horiz)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
37
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
38 on(vert, "scroll", () => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
39 if (vert.clientHeight) scroll(vert.scrollTop, "vertical")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
40 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
41 on(horiz, "scroll", () => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
42 if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
43 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
44
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
45 this.checkedZeroWidth = false
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
46 // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
47 if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
48 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
49
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
50 update(measure) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
51 let needsH = measure.scrollWidth > measure.clientWidth + 1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
52 let needsV = measure.scrollHeight > measure.clientHeight + 1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
53 let sWidth = measure.nativeBarWidth
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
54
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
55 if (needsV) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
56 this.vert.style.display = "block"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
57 this.vert.style.bottom = needsH ? sWidth + "px" : "0"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
58 let totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
59 // A bug in IE8 can cause this value to be negative, so guard it.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
60 this.vert.firstChild.style.height =
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
61 Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
62 } else {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
63 this.vert.scrollTop = 0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
64 this.vert.style.display = ""
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
65 this.vert.firstChild.style.height = "0"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
66 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
67
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
68 if (needsH) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
69 this.horiz.style.display = "block"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
70 this.horiz.style.right = needsV ? sWidth + "px" : "0"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
71 this.horiz.style.left = measure.barLeft + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
72 let totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
73 this.horiz.firstChild.style.width =
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
74 Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
75 } else {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
76 this.horiz.style.display = ""
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
77 this.horiz.firstChild.style.width = "0"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
78 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
79
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
80 if (!this.checkedZeroWidth && measure.clientHeight > 0) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
81 if (sWidth == 0) this.zeroWidthHack()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
82 this.checkedZeroWidth = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
83 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
84
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
85 return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
86 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
87
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
88 setScrollLeft(pos) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
89 if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
90 if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
91 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
92
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
93 setScrollTop(pos) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
94 if (this.vert.scrollTop != pos) this.vert.scrollTop = pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
95 if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert, "vert")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
96 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
97
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
98 zeroWidthHack() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
99 let w = mac && !mac_geMountainLion ? "12px" : "18px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
100 this.horiz.style.height = this.vert.style.width = w
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
101 this.horiz.style.visibility = this.vert.style.visibility = "hidden"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
102 this.disableHoriz = new Delayed
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
103 this.disableVert = new Delayed
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
104 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
105
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
106 enableZeroWidthBar(bar, delay, type) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
107 bar.style.visibility = ""
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
108 function maybeDisable() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
109 // To find out whether the scrollbar is still visible, we
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
110 // check whether the element under the pixel in the bottom
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
111 // right corner of the scrollbar box is the scrollbar box
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
112 // itself (when the bar is still visible) or its filler child
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
113 // (when the bar is hidden). If it is still visible, we keep
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
114 // it enabled, if it's hidden, we disable pointer events.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
115 let box = bar.getBoundingClientRect()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
116 let elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
117 : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
118 if (elt != bar) bar.style.visibility = "hidden"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
119 else delay.set(1000, maybeDisable)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
120 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
121 delay.set(1000, maybeDisable)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
122 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
123
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
124 clear() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
125 let parent = this.horiz.parentNode
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
126 parent.removeChild(this.horiz)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
127 parent.removeChild(this.vert)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
128 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
129 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
130
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
131 class NullScrollbars {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
132 update() { return {bottom: 0, right: 0} }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
133 setScrollLeft() {}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
134 setScrollTop() {}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
135 clear() {}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
136 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
137
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
138 export function updateScrollbars(cm, measure) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
139 if (!measure) measure = measureForScrollbars(cm)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
140 let startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
141 updateScrollbarsInner(cm, measure)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
142 for (let i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
143 if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
144 updateHeightsInViewport(cm)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
145 updateScrollbarsInner(cm, measureForScrollbars(cm))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
146 startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
147 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
148 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
149
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
150 // Re-synchronize the fake scrollbars with the actual size of the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
151 // content.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
152 function updateScrollbarsInner(cm, measure) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
153 let d = cm.display
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
154 let sizes = d.scrollbars.update(measure)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
155
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
156 d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
157 d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
158 d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
159
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
160 if (sizes.right && sizes.bottom) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
161 d.scrollbarFiller.style.display = "block"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
162 d.scrollbarFiller.style.height = sizes.bottom + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
163 d.scrollbarFiller.style.width = sizes.right + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
164 } else d.scrollbarFiller.style.display = ""
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
165 if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
166 d.gutterFiller.style.display = "block"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
167 d.gutterFiller.style.height = sizes.bottom + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
168 d.gutterFiller.style.width = measure.gutterWidth + "px"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
169 } else d.gutterFiller.style.display = ""
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
170 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
171
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
172 export let scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
173
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
174 export function initScrollbars(cm) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
175 if (cm.display.scrollbars) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
176 cm.display.scrollbars.clear()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
177 if (cm.display.scrollbars.addClass)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
178 rmClass(cm.display.wrapper, cm.display.scrollbars.addClass)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
179 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
180
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
181 cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](node => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
182 cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
183 // Prevent clicks in the scrollbars from killing focus
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
184 on(node, "mousedown", () => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
185 if (cm.state.focused) setTimeout(() => cm.display.input.focus(), 0)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
186 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
187 node.setAttribute("cm-not-content", "true")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
188 }, (pos, axis) => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
189 if (axis == "horizontal") setScrollLeft(cm, pos)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
190 else updateScrollTop(cm, pos)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
191 }, cm)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
192 if (cm.display.scrollbars.addClass)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
193 addClass(cm.display.wrapper, cm.display.scrollbars.addClass)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
194 }