Skip to content

Commit c18094e

Browse files
committed
Allow CSS styles to be passed for gutter backgrounds
Issue codemirror#5834
1 parent b28c41e commit c18094e

File tree

12 files changed

+72
-67
lines changed

12 files changed

+72
-67
lines changed

doc/manual.html

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -371,16 +371,16 @@ <h2>Configuration</h2>
371371
passed the line number, and should return a string that will be
372372
shown in the gutter.</dd>
373373

374-
<dt id="option_gutters"><code><strong>gutters</strong>: array&lt;string&gt;</code></dt>
374+
<dt id="option_gutters"><code><strong>gutters</strong>: array&lt;string | {className: string, style: ?string}&gt;</code></dt>
375375
<dd>Can be used to add extra gutters (beyond or instead of the
376-
line number gutter). Should be an array of CSS class names, each
377-
of which defines a <code>width</code> (and optionally a
378-
background), and which will be used to draw the background of
379-
the gutters. <em>May</em> include
380-
the <code>CodeMirror-linenumbers</code> class, in order to
381-
explicitly set the position of the line number gutter (it will
382-
default to be to the right of all other gutters). These class
383-
names are the keys passed
376+
line number gutter). Should be an array of CSS class names or
377+
class name / CSS string pairs, each of which defines
378+
a <code>width</code> (and optionally a background), and which
379+
will be used to draw the background of the gutters. <em>May</em>
380+
include the <code>CodeMirror-linenumbers</code> class, in order
381+
to explicitly set the position of the line number gutter (it
382+
will default to be to the right of all other gutters). These
383+
class names are the keys passed
384384
to <a href="#setGutterMarker"><code>setGutterMarker</code></a>.</dd>
385385

386386
<dt id="option_fixedGutter"><code><strong>fixedGutter</strong>: boolean</code></dt>

src/display/Display.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { gecko, ie, ie_version, mobile, webkit } from "../util/browser.js"
22
import { elt, eltP } from "../util/dom.js"
33
import { scrollerGap } from "../util/misc.js"
4+
import { getGutters, renderGutters } from "./gutters.js"
45

56
// The display handles the DOM integration, both for input reading
67
// and content drawing. It holds references to DOM nodes and
78
// display-related state.
89

9-
export function Display(place, doc, input) {
10+
export function Display(place, doc, input, options) {
1011
let d = this
1112
this.input = input
1213

@@ -102,5 +103,8 @@ export function Display(place, doc, input) {
102103

103104
d.activeTouch = null
104105

106+
d.gutterSpecs = getGutters(options.gutters, options.lineNumbers)
107+
renderGutters(d)
108+
105109
input.init(d)
106110
}

src/display/gutters.js

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,44 @@
11
import { elt, removeChildren } from "../util/dom.js"
2-
import { indexOf } from "../util/misc.js"
3-
2+
import { regChange } from "./view_tracking.js"
3+
import { alignHorizontally } from "./line_numbers.js"
44
import { updateGutterSpace } from "./update_display.js"
55

6+
export function getGutters(gutters, lineNumbers) {
7+
let result = [], sawLineNumbers = false
8+
for (let i = 0; i < gutters.length; i++) {
9+
let name = gutters[i], style = null
10+
if (typeof name != "string") { style = name.style; name = name.className }
11+
if (name == "CodeMirror-linenumbers") {
12+
if (!lineNumbers) continue
13+
else sawLineNumbers = true
14+
}
15+
result.push({className: name, style})
16+
}
17+
if (lineNumbers && !sawLineNumbers) result.push({className: "CodeMirror-linenumbers", style: null})
18+
return result
19+
}
20+
621
// Rebuild the gutter elements, ensure the margin to the left of the
722
// code matches their width.
8-
export function updateGutters(cm) {
9-
let gutters = cm.display.gutters, specs = cm.options.gutters
23+
export function renderGutters(display) {
24+
let gutters = display.gutters, specs = display.gutterSpecs
1025
removeChildren(gutters)
11-
let i = 0
12-
for (; i < specs.length; ++i) {
13-
let gutterClass = specs[i]
14-
let gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass))
15-
if (gutterClass == "CodeMirror-linenumbers") {
16-
cm.display.lineGutter = gElt
17-
gElt.style.width = (cm.display.lineNumWidth || 1) + "px"
26+
display.lineGutter = null
27+
for (let i = 0; i < specs.length; ++i) {
28+
let {className, style} = specs[i]
29+
let gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + className))
30+
if (style) gElt.style.cssText = style
31+
if (className == "CodeMirror-linenumbers") {
32+
display.lineGutter = gElt
33+
gElt.style.width = (display.lineNumWidth || 1) + "px"
1834
}
1935
}
20-
gutters.style.display = i ? "" : "none"
21-
updateGutterSpace(cm)
36+
gutters.style.display = specs.length ? "" : "none"
37+
updateGutterSpace(display)
2238
}
2339

24-
// Make sure the gutters options contains the element
25-
// "CodeMirror-linenumbers" when the lineNumbers option is true.
26-
export function setGuttersForLineNumbers(options) {
27-
let found = indexOf(options.gutters, "CodeMirror-linenumbers")
28-
if (found == -1 && options.lineNumbers) {
29-
options.gutters = options.gutters.concat(["CodeMirror-linenumbers"])
30-
} else if (found > -1 && !options.lineNumbers) {
31-
options.gutters = options.gutters.slice(0)
32-
options.gutters.splice(found, 1)
33-
}
40+
export function updateGutters(cm) {
41+
renderGutters(cm.display)
42+
regChange(cm)
43+
alignHorizontally(cm)
3444
}

src/display/line_numbers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function maybeUpdateLineNumberWidth(cm) {
4141
display.lineNumWidth = display.lineNumInnerWidth + padding
4242
display.lineNumChars = display.lineNumInnerWidth ? last.length : -1
4343
display.lineGutter.style.width = display.lineNumWidth + "px"
44-
updateGutterSpace(cm)
44+
updateGutterSpace(cm.display)
4545
return true
4646
}
4747
return false

src/display/update_display.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,9 @@ function patchDisplay(cm, updateNumbersFrom, dims) {
248248
while (cur) cur = rm(cur)
249249
}
250250

251-
export function updateGutterSpace(cm) {
252-
let width = cm.display.gutters.offsetWidth
253-
cm.display.sizer.style.marginLeft = width + "px"
251+
export function updateGutterSpace(display) {
252+
let width = display.gutters.offsetWidth
253+
display.sizer.style.marginLeft = width + "px"
254254
}
255255

256256
export function setDocumentHeight(cm, measure) {

src/display/update_line.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,8 @@ function updateLineGutter(cm, lineView, lineN, dims) {
113113
elt("div", lineNumberFor(cm.options, lineN),
114114
"CodeMirror-linenumber CodeMirror-gutter-elt",
115115
`left: ${dims.gutterLeft["CodeMirror-linenumbers"]}px; width: ${cm.display.lineNumInnerWidth}px`))
116-
if (markers) for (let k = 0; k < cm.options.gutters.length; ++k) {
117-
let id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]
116+
if (markers) for (let k = 0; k < cm.display.gutterSpecs.length; ++k) {
117+
let id = cm.display.gutterSpecs[k].className, found = markers.hasOwnProperty(id) && markers[id]
118118
if (found)
119119
gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
120120
`left: ${dims.gutterLeft[id]}px; width: ${dims.gutterWidth[id]}px`))

src/edit/CodeMirror.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Display } from "../display/Display.js"
22
import { onFocus, onBlur } from "../display/focus.js"
3-
import { setGuttersForLineNumbers, updateGutters } from "../display/gutters.js"
43
import { maybeUpdateLineNumberWidth } from "../display/line_numbers.js"
54
import { endOperation, operation, startOperation } from "../display/operations.js"
65
import { initScrollbars } from "../display/scrollbars.js"
@@ -33,17 +32,15 @@ export function CodeMirror(place, options) {
3332
this.options = options = options ? copyObj(options) : {}
3433
// Determine effective options based on given values and defaults.
3534
copyObj(defaults, options, false)
36-
setGuttersForLineNumbers(options)
3735

3836
let doc = options.value
3937
if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction)
4038
else if (options.mode) doc.modeOption = options.mode
4139
this.doc = doc
4240

4341
let input = new CodeMirror.inputStyles[options.inputStyle](this)
44-
let display = this.display = new Display(place, doc, input)
42+
let display = this.display = new Display(place, doc, input, options)
4543
display.wrapper.CodeMirror = this
46-
updateGutters(this)
4744
themeChanged(this)
4845
if (options.lineWrapping)
4946
this.display.wrapper.className += " CodeMirror-wrap"

src/edit/methods.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ export default function(CodeMirror) {
414414
this.curOp.forceUpdate = true
415415
clearCaches(this)
416416
scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop)
417-
updateGutterSpace(this)
417+
updateGutterSpace(this.display)
418418
if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
419419
estimateLineHeights(this)
420420
signal(this, "refresh", this)

src/edit/mouse_events.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,12 @@ function gutterEvent(cm, e, type, prevent) {
380380
if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e)
381381
mY -= lineBox.top - display.viewOffset
382382

383-
for (let i = 0; i < cm.options.gutters.length; ++i) {
383+
for (let i = 0; i < cm.display.gutterSpecs.length; ++i) {
384384
let g = display.gutters.childNodes[i]
385385
if (g && g.getBoundingClientRect().right >= mX) {
386386
let line = lineAtHeight(cm.doc, mY)
387-
let gutter = cm.options.gutters[i]
388-
signal(cm, type, cm, line, gutter, e)
387+
let gutter = cm.display.gutterSpecs[i]
388+
signal(cm, type, cm, line, gutter.className, e)
389389
return e_defaultPrevented(e)
390390
}
391391
}

src/edit/options.js

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { onBlur } from "../display/focus.js"
2-
import { setGuttersForLineNumbers, updateGutters } from "../display/gutters.js"
3-
import { alignHorizontally } from "../display/line_numbers.js"
2+
import { getGutters, updateGutters } from "../display/gutters.js"
43
import { loadMode, resetModeState } from "../display/mode_state.js"
54
import { initScrollbars, updateScrollbars } from "../display/scrollbars.js"
65
import { updateSelection } from "../display/selection.js"
@@ -86,7 +85,7 @@ export function defineOptions(CodeMirror) {
8685

8786
option("theme", "default", cm => {
8887
themeChanged(cm)
89-
guttersChanged(cm)
88+
updateGutters(cm)
9089
}, true)
9190
option("keyMap", "default", (cm, val, old) => {
9291
let next = getKeyMap(val)
@@ -98,9 +97,9 @@ export function defineOptions(CodeMirror) {
9897
option("configureMouse", null)
9998

10099
option("lineWrapping", false, wrappingChanged, true)
101-
option("gutters", [], cm => {
102-
setGuttersForLineNumbers(cm.options)
103-
guttersChanged(cm)
100+
option("gutters", [], (cm, val) => {
101+
cm.display.gutterSpecs = getGutters(val, cm.options.lineNumbers)
102+
updateGutters(cm)
104103
}, true)
105104
option("fixedGutter", true, (cm, val) => {
106105
cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"
@@ -113,12 +112,12 @@ export function defineOptions(CodeMirror) {
113112
cm.display.scrollbars.setScrollTop(cm.doc.scrollTop)
114113
cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft)
115114
}, true)
116-
option("lineNumbers", false, cm => {
117-
setGuttersForLineNumbers(cm.options)
118-
guttersChanged(cm)
115+
option("lineNumbers", false, (cm, val) => {
116+
cm.display.gutterSpecs = getGutters(cm.options.gutters, val)
117+
updateGutters(cm)
119118
}, true)
120-
option("firstLineNumber", 1, guttersChanged, true)
121-
option("lineNumberFormatter", integer => integer, guttersChanged, true)
119+
option("firstLineNumber", 1, updateGutters, true)
120+
option("lineNumberFormatter", integer => integer, updateGutters, true)
122121
option("showCursorWhenSelecting", false, updateSelection, true)
123122

124123
option("resetSelectionOnContextMenu", true)
@@ -160,12 +159,6 @@ export function defineOptions(CodeMirror) {
160159
option("phrases", null)
161160
}
162161

163-
function guttersChanged(cm) {
164-
updateGutters(cm)
165-
regChange(cm)
166-
alignHorizontally(cm)
167-
}
168-
169162
function dragDropChanged(cm, value, old) {
170163
let wasOn = old && old != Init
171164
if (!value != !wasOn) {

0 commit comments

Comments
 (0)