Files
atom/src/custom-gutter-component.coffee
2015-04-22 07:28:59 -07:00

118 lines
4.3 KiB
CoffeeScript

{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}) ->
@decorationNodesById = {}
@decorationItemsById = {}
@visible = true
@domNode = atom.views.getView(@gutter)
@decorationsNode = @domNode.firstChild
getDomNode: ->
@domNode
getName: ->
@gutter.name
hideNode: ->
if @visible
@domNode.style.display = 'none'
@visible = false
showNode: ->
if not @visible
@domNode.style.removeProperty('display')
@visible = true
updateSync: (state) ->
@oldDimensionsAndBackgroundState ?= {}
newDimensionsAndBackgroundState = state.gutters
setDimensionsAndBackground(@oldDimensionsAndBackgroundState, newDimensionsAndBackgroundState, @decorationsNode)
@oldDecorationPositionState ?= {};
decorationState = state.gutters.customDecorations[@getName()]
updatedDecorationIds = new Set
for decorationId, decorationInfo of decorationState
updatedDecorationIds.add(decorationId)
existingDecoration = @decorationNodesById[decorationId]
if existingDecoration
@updateDecorationHTML(existingDecoration, decorationId, decorationInfo)
else
newNode = @buildDecorationHTML(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.
buildDecorationHTML: (decorationId, decorationInfo) ->
@oldDecorationPositionState[decorationId] = positionState = {};
newNode = document.createElement('div')
newNode.classList.add('decoration')
newNode.style.top = decorationInfo.top + 'px'
positionState.top = decorationInfo.top + 'px'
newNode.style.height = decorationInfo.height + 'px'
positionState.height = decorationInfo.height + 'px'
newNode.style.position = 'absolute'
if decorationInfo.class
newNode.classList.add(decorationInfo.class)
@setDecorationItem(decorationInfo.item, decorationInfo.height, decorationId, newNode)
newNode
# Updates the existing HTMLNode with the new decoration info. Attempts to
# minimize changes to the DOM.
updateDecorationHTML: (existingNode, decorationId, newDecorationInfo) ->
oldPositionState = @oldDecorationPositionState[decorationId];
if oldPositionState.top isnt newDecorationInfo.top + 'px'
existingNode.style.top = newDecorationInfo.top + 'px'
oldPositionState.top = newDecorationInfo.top + 'px'
if oldPositionState.height isnt newDecorationInfo.height + 'px'
existingNode.style.height = newDecorationInfo.height + 'px'
oldPositionState.height = newDecorationInfo.height + 'px'
if newDecorationInfo.class and not existingNode.classList.contains(newDecorationInfo.class)
existingNode.className = 'decoration'
existingNode.classList.add(newDecorationInfo.class)
else if not newDecorationInfo.class
existingNode.className = 'decoration'
@setDecorationItem(newDecorationInfo.item, newDecorationInfo.height, decorationId, existingNode)
# 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
# `item` should be either an HTMLElement or a space-pen View.
newItemNode = null
if newItem instanceof HTMLElement
newItemNode = newItem
else
newItemNode = newItem.element
newItemNode.style.height = decorationHeight + 'px'
decorationNode.appendChild(newItemNode)
@decorationItemsById[decorationId] = newItem