-
Notifications
You must be signed in to change notification settings - Fork 0
/
custom-gutter-component.coffee
109 lines (88 loc) · 3.92 KB
/
custom-gutter-component.coffee
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
{setDimensionsAndBackground} = require './gutter-component-helpers'
# This class represents a gutter other than the 'line-numbers' gutter.
# The contents of this gutter may be specified by Decorations.
module.exports =
class CustomGutterComponent
constructor: ({@gutter, @views}) ->
@decorationNodesById = {}
@decorationItemsById = {}
@visible = true
@domNode = @views.getView(@gutter)
@decorationsNode = @domNode.firstChild
# Clear the contents in case the domNode is being reused.
@decorationsNode.innerHTML = ''
getDomNode: ->
@domNode
hideNode: ->
if @visible
@domNode.style.display = 'none'
@visible = false
showNode: ->
if not @visible
@domNode.style.removeProperty('display')
@visible = true
# `state` is a subset of the TextEditorPresenter state that is specific
# to this line number gutter.
updateSync: (state) ->
@oldDimensionsAndBackgroundState ?= {}
setDimensionsAndBackground(@oldDimensionsAndBackgroundState, state.styles, @decorationsNode)
@oldDecorationPositionState ?= {}
decorationState = state.content
updatedDecorationIds = new Set
for decorationId, decorationInfo of decorationState
updatedDecorationIds.add(decorationId)
existingDecoration = @decorationNodesById[decorationId]
if existingDecoration
@updateDecorationNode(existingDecoration, decorationId, decorationInfo)
else
newNode = @buildDecorationNode(decorationId, decorationInfo)
@decorationNodesById[decorationId] = newNode
@decorationsNode.appendChild(newNode)
for decorationId, decorationNode of @decorationNodesById
if not updatedDecorationIds.has(decorationId)
decorationNode.remove()
delete @decorationNodesById[decorationId]
delete @decorationItemsById[decorationId]
delete @oldDecorationPositionState[decorationId]
###
Section: Private Methods
###
# Builds and returns an HTMLElement to represent the specified decoration.
buildDecorationNode: (decorationId, decorationInfo) ->
@oldDecorationPositionState[decorationId] = {}
newNode = document.createElement('div')
newNode.style.position = 'absolute'
@updateDecorationNode(newNode, decorationId, decorationInfo)
newNode
# Updates the existing HTMLNode with the new decoration info. Attempts to
# minimize changes to the DOM.
updateDecorationNode: (node, decorationId, newDecorationInfo) ->
oldPositionState = @oldDecorationPositionState[decorationId]
if oldPositionState.top isnt newDecorationInfo.top + 'px'
node.style.top = newDecorationInfo.top + 'px'
oldPositionState.top = newDecorationInfo.top + 'px'
if oldPositionState.height isnt newDecorationInfo.height + 'px'
node.style.height = newDecorationInfo.height + 'px'
oldPositionState.height = newDecorationInfo.height + 'px'
if newDecorationInfo.class and not node.classList.contains(newDecorationInfo.class)
node.className = 'decoration'
node.classList.add(newDecorationInfo.class)
else if not newDecorationInfo.class
node.className = 'decoration'
@setDecorationItem(newDecorationInfo.item, newDecorationInfo.height, decorationId, node)
# Sets the decorationItem on the decorationNode.
# If `decorationItem` is undefined, the decorationNode's child item will be cleared.
setDecorationItem: (newItem, decorationHeight, decorationId, decorationNode) ->
if newItem isnt @decorationItemsById[decorationId]
while decorationNode.firstChild
decorationNode.removeChild(decorationNode.firstChild)
delete @decorationItemsById[decorationId]
if newItem
newItemNode = null
if newItem instanceof HTMLElement
newItemNode = newItem
else
newItemNode = newItem.element
newItemNode.style.height = decorationHeight + 'px'
decorationNode.appendChild(newItemNode)
@decorationItemsById[decorationId] = newItem