Prepare DOMElementPool to account for text nodes

This commit is contained in:
Antonio Scandurra
2015-10-06 09:54:05 +02:00
parent b31d3d1a3f
commit c79cc87172
5 changed files with 64 additions and 50 deletions

View File

@@ -10,23 +10,32 @@ class DOMElementPool
freeElements.length = 0
return
build: (tagName, className, textContent = "") ->
build: (tagName, factory, reset) ->
element = @freeElementsByTagName[tagName]?.pop()
element ?= document.createElement(tagName)
delete element.dataset[dataId] for dataId of element.dataset
element.removeAttribute("class")
element.removeAttribute("style")
element.className = className if className?
element.textContent = textContent
element ?= factory()
reset(element)
@freedElements.delete(element)
element
buildElement: (tagName, className, textContent = "") ->
factory = -> document.createElement(tagName)
reset = (element) ->
delete element.dataset[dataId] for dataId of element.dataset
element.removeAttribute("class")
element.removeAttribute("style")
element.className = className if className?
element.textContent = textContent
@build(tagName, factory, reset)
buildText: (textContent) ->
factory = -> document.createTextNode(textContent)
reset = (element) -> element.textContent = textContent
@build("#text", factory, reset)
freeElementAndDescendants: (element) ->
@free(element)
for index in [element.children.length - 1..0] by -1
child = element.children[index]
for index in [element.childNodes.length - 1..0] by -1
child = element.childNodes[index]
@freeElementAndDescendants(child)
return
@@ -34,7 +43,7 @@ class DOMElementPool
throw new Error("The element cannot be null or undefined.") unless element?
throw new Error("The element has already been freed!") if @freedElements.has(element)
tagName = element.tagName.toLowerCase()
tagName = element.nodeName.toLowerCase()
@freeElementsByTagName[tagName] ?= []
@freeElementsByTagName[tagName].push(element)
@freedElements.add(element)

View File

@@ -9,7 +9,7 @@ class HighlightsComponent
@highlightNodesById = {}
@regionNodesByHighlightId = {}
@domNode = @domElementPool.build("div", "highlights")
@domNode = @domElementPool.buildElement("div", "highlights")
getDomNode: ->
@domNode
@@ -29,7 +29,7 @@ class HighlightsComponent
# add or update highlights
for id, highlightState of newState
unless @oldState[id]?
highlightNode = @domElementPool.build("div", "highlight")
highlightNode = @domElementPool.buildElement("div", "highlight")
@highlightNodesById[id] = highlightNode
@regionNodesByHighlightId[id] = {}
@domNode.appendChild(highlightNode)
@@ -73,7 +73,7 @@ class HighlightsComponent
for newRegionState, i in newHighlightState.regions
unless oldHighlightState.regions[i]?
oldHighlightState.regions[i] = {}
regionNode = @domElementPool.build("div", "region")
regionNode = @domElementPool.buildElement("div", "region")
# This prevents highlights at the tiles boundaries to be hidden by the
# subsequent tile. When this happens, subpixel anti-aliasing gets
# disabled.

View File

@@ -7,7 +7,7 @@ class LineNumbersTileComponent
constructor: ({@id, @domElementPool}) ->
@lineNumberNodesById = {}
@domNode = @domElementPool.build("div")
@domNode = @domElementPool.buildElement("div")
@domNode.style.position = "absolute"
@domNode.style.display = "block"
@domNode.style.top = 0 # Cover the space occupied by a dummy lineNumber
@@ -99,7 +99,7 @@ class LineNumbersTileComponent
{screenRow, bufferRow, softWrapped, top, decorationClasses, zIndex} = lineNumberState
className = @buildLineNumberClassName(lineNumberState)
lineNumberNode = @domElementPool.build("div", className)
lineNumberNode = @domElementPool.buildElement("div", className)
lineNumberNode.dataset.screenRow = screenRow
lineNumberNode.dataset.bufferRow = bufferRow
@@ -115,7 +115,7 @@ class LineNumbersTileComponent
lineNumber = (bufferRow + 1).toString()
padding = _.multiplyString("\u00a0", maxLineNumberDigits - lineNumber.length)
iconRight = @domElementPool.build("div", "icon-right")
iconRight = @domElementPool.buildElement("div", "icon-right")
lineNumberNode.textContent = padding + lineNumber
lineNumberNode.appendChild(iconRight)

View File

@@ -19,7 +19,7 @@ class LinesTileComponent
@lineNodesByLineId = {}
@screenRowsByLineId = {}
@lineIdsByScreenRow = {}
@domNode = @domElementPool.build("div")
@domNode = @domElementPool.buildElement("div")
@domNode.style.position = "absolute"
@domNode.style.display = "block"
@@ -126,7 +126,7 @@ class LinesTileComponent
{width} = @newState
{screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newTileState.lines[id]
lineNode = @domElementPool.build("div", "line")
lineNode = @domElementPool.buildElement("div", "line")
lineNode.dataset.screenRow = screenRow
if decorationClasses?
@@ -138,7 +138,7 @@ class LinesTileComponent
else
@setLineInnerNodes(id, lineNode)
lineNode.appendChild(@domElementPool.build("span", "fold-marker")) if fold
lineNode.appendChild(@domElementPool.buildElement("span", "fold-marker")) if fold
lineNode
setEmptyLineInnerNodes: (id, lineNode) ->
@@ -148,11 +148,11 @@ class LinesTileComponent
if indentGuidesVisible and indentLevel > 0
invisibleIndex = 0
for i in [0...indentLevel]
indentGuide = @domElementPool.build("span", "indent-guide")
indentGuide = @domElementPool.buildElement("span", "indent-guide")
for j in [0...tabLength]
if invisible = endOfLineInvisibles?[invisibleIndex++]
indentGuide.appendChild(
@domElementPool.build("span", "invisible-character", invisible)
@domElementPool.buildElement("span", "invisible-character", invisible)
)
else
indentGuide.insertAdjacentText("beforeend", " ")
@@ -161,7 +161,7 @@ class LinesTileComponent
while invisibleIndex < endOfLineInvisibles?.length
invisible = endOfLineInvisibles[invisibleIndex++]
lineNode.appendChild(
@domElementPool.build("span", "invisible-character", invisible)
@domElementPool.buildElement("span", "invisible-character", invisible)
)
else
unless @appendEndOfLineNodes(id, lineNode)
@@ -180,7 +180,7 @@ class LinesTileComponent
openScopeNode = openScopeNode.parentElement
for scope in @tokenIterator.getScopeStarts()
newScopeNode = @domElementPool.build("span", scope.replace(/\.+/g, ' '))
newScopeNode = @domElementPool.buildElement("span", scope.replace(/\.+/g, ' '))
openScopeNode.appendChild(newScopeNode)
openScopeNode = newScopeNode
@@ -213,7 +213,7 @@ class LinesTileComponent
appendTokenNodes: (tokenText, isHardTab, firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters, scopeNode) ->
if isHardTab
hardTabNode = @domElementPool.build("span", "hard-tab", tokenText)
hardTabNode = @domElementPool.buildElement("span", "hard-tab", tokenText)
hardTabNode.classList.add("leading-whitespace") if firstNonWhitespaceIndex?
hardTabNode.classList.add("trailing-whitespace") if firstTrailingWhitespaceIndex?
hardTabNode.classList.add("indent-guide") if hasIndentGuide
@@ -228,7 +228,7 @@ class LinesTileComponent
trailingWhitespaceNode = null
if firstNonWhitespaceIndex?
leadingWhitespaceNode = @domElementPool.build(
leadingWhitespaceNode = @domElementPool.buildElement(
"span",
"leading-whitespace",
tokenText.substring(0, firstNonWhitespaceIndex)
@@ -241,7 +241,7 @@ class LinesTileComponent
if firstTrailingWhitespaceIndex?
tokenIsOnlyWhitespace = firstTrailingWhitespaceIndex is 0
trailingWhitespaceNode = @domElementPool.build(
trailingWhitespaceNode = @domElementPool.buildElement(
"span",
"trailing-whitespace",
tokenText.substring(firstTrailingWhitespaceIndex)
@@ -256,7 +256,7 @@ class LinesTileComponent
if tokenText.length > MaxTokenLength
while startIndex < endIndex
text = @sliceText(tokenText, startIndex, startIndex + MaxTokenLength)
scopeNode.appendChild(@domElementPool.build("span", null, text))
scopeNode.appendChild(@domElementPool.buildElement("span", null, text))
startIndex += MaxTokenLength
else
scopeNode.insertAdjacentText("beforeend", @sliceText(tokenText, startIndex, endIndex))
@@ -276,7 +276,7 @@ class LinesTileComponent
for invisible in endOfLineInvisibles
hasInvisibles = true
lineNode.appendChild(
@domElementPool.build("span", "invisible-character", invisible)
@domElementPool.buildElement("span", "invisible-character", invisible)
)
hasInvisibles