From a44f7116a2bf8c7299d3e96ff42ec9b561a7ada5 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Mon, 14 Sep 2015 11:34:13 +0200 Subject: [PATCH] Start building nodes via document.createElement --- src/lines-tile-component.coffee | 152 +++++++++++++++++--------------- 1 file changed, 81 insertions(+), 71 deletions(-) diff --git a/src/lines-tile-component.coffee b/src/lines-tile-component.coffee index f823ea8ac..aee13e4b4 100644 --- a/src/lines-tile-component.coffee +++ b/src/lines-tile-component.coffee @@ -118,24 +118,30 @@ class LinesTileComponent {width} = @newState {screenRow, tokens, text, top, lineEnding, fold, isSoftWrapped, indentLevel, decorationClasses} = @newTileState.lines[id] - classes = '' + lineNode = document.createElement("div") + lineNode.classList.add("line") if decorationClasses? for decorationClass in decorationClasses - classes += decorationClass + ' ' - classes += 'line' + lineNode.classList.add(decorationClass) - lineHTML = "
" + lineNode.style.position = "absolute" + lineNode.style.top = top + "px" + lineNode.style.width = width + "px" + lineNode.dataset.screenRow = screenRow if text is "" - lineHTML += @buildEmptyLineInnerHTML(id) + @appendEmptyLineInnerNodes(id, lineNode) else - lineHTML += @buildLineInnerHTML(id) + @appendLineInnerNodes(id, lineNode) - lineHTML += '' if fold - lineHTML += "
" - lineHTML + if fold + foldMarker = document.createElement("span") + foldMarker.classList.add("fold-marker") + lineNode.appendChild(foldMarker) - buildEmptyLineInnerHTML: (id) -> + lineNode.outerHTML + + appendEmptyLineInnerNodes: (id, lineNode) -> {indentGuidesVisible} = @newState {indentLevel, tabLength, endOfLineInvisibles} = @newTileState.lines[id] @@ -143,35 +149,46 @@ class LinesTileComponent invisibleIndex = 0 lineHTML = '' for i in [0...indentLevel] - lineHTML += "" + indentGuide = document.createElement("span") + indentGuide.classList.add("indent-guide") for j in [0...tabLength] if invisible = endOfLineInvisibles?[invisibleIndex++] - lineHTML += "#{invisible}" + invisibleCharacter = document.createElement("span") + invisibleCharacter.classList.add("invisible-character") + invisibleCharacter.textContent = invisible + indentGuide.appendChild(invisibleCharacter) else - lineHTML += ' ' - lineHTML += "" + indentGuide.insertAdjacentText("beforeend", " ") + lineNode.appendChild(indentGuide) while invisibleIndex < endOfLineInvisibles?.length - lineHTML += "#{endOfLineInvisibles[invisibleIndex++]}" - - lineHTML + invisibleCharacter = document.createElement("span") + invisibleCharacter.classList.add("invisible-character") + invisibleCharacter.textContent = endOfLineInvisibles[invisibleIndex++] + lineNode.appendChild(invisibleCharacter) else - @buildEndOfLineHTML(id) or ' ' + unless @appendEndOfLineNodes(id, lineNode) + lineNode.insertAdjacentHTML("beforeend", " ") - buildLineInnerHTML: (id) -> + appendLineInnerNodes: (id, lineNode) -> lineState = @newTileState.lines[id] {firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, invisibles} = lineState lineIsWhitespaceOnly = firstTrailingWhitespaceIndex is 0 innerHTML = "" @tokenIterator.reset(lineState) + openScopeNode = lineNode while @tokenIterator.next() for scope in @tokenIterator.getScopeEnds() - innerHTML += "" + openScopeNode = openScopeNode.parentElement for scope in @tokenIterator.getScopeStarts() - innerHTML += "" + newScopeNode = document.createElement("span") + newScopeNode.className = scope.replace(/\.+/g, ' ') + openScopeNode.appendChild(newScopeNode) + + openScopeNode = newScopeNode tokenStart = @tokenIterator.getScreenStart() tokenEnd = @tokenIterator.getScreenEnd() @@ -196,87 +213,80 @@ class LinesTileComponent (invisibles?.tab and isHardTab) or (invisibles?.space and (hasLeadingWhitespace or hasTrailingWhitespace)) - innerHTML += @buildTokenHTML(tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) + @appendToken(openScopeNode, tokenText, isHardTab, tokenFirstNonWhitespaceIndex, tokenFirstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) - for scope in @tokenIterator.getScopeEnds() - innerHTML += "" + @appendEndOfLineNodes(id, lineNode) - for scope in @tokenIterator.getScopes() - innerHTML += "" - - innerHTML += @buildEndOfLineHTML(id) - innerHTML - - buildTokenHTML: (tokenText, isHardTab, firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) -> + appendToken: (scopeNode, tokenText, isHardTab, firstNonWhitespaceIndex, firstTrailingWhitespaceIndex, hasIndentGuide, hasInvisibleCharacters) -> if isHardTab - classes = 'hard-tab' - classes += ' leading-whitespace' if firstNonWhitespaceIndex? - classes += ' trailing-whitespace' if firstTrailingWhitespaceIndex? - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if hasInvisibleCharacters - return "#{@escapeTokenText(tokenText)}" + hardTab = document.createElement("span") + hardTab.classList.add("hard-tab") + hardTab.classList.add("leading-whitespace") if firstNonWhitespaceIndex? + hardTab.classList.add("trailing-whitespace") if firstTrailingWhitespaceIndex? + hardTab.classList.add("indent-guide") if hasIndentGuide + hardTab.classList.add("invisible-character") if hasInvisibleCharacters + hardTab.textContent = tokenText + + scopeNode.appendChild(hardTab) else startIndex = 0 endIndex = tokenText.length - leadingHtml = '' - trailingHtml = '' + leadingWhitespaceNode = null + trailingWhitespaceNode = null if firstNonWhitespaceIndex? - leadingWhitespace = tokenText.substring(0, firstNonWhitespaceIndex) + leadingWhitespaceNode = document.createElement("span") + leadingWhitespaceNode.classList.add("leading-whitespace") + leadingWhitespaceNode.classList.add("indent-guide") if hasIndentGuide + leadingWhitespaceNode.classList.add("invisible-character") if hasInvisibleCharacters + leadingWhitespaceNode.textContent = tokenText.substring(0, firstNonWhitespaceIndex) - classes = 'leading-whitespace' - classes += ' indent-guide' if hasIndentGuide - classes += ' invisible-character' if hasInvisibleCharacters - - leadingHtml = "#{leadingWhitespace}" startIndex = firstNonWhitespaceIndex if firstTrailingWhitespaceIndex? tokenIsOnlyWhitespace = firstTrailingWhitespaceIndex is 0 - trailingWhitespace = tokenText.substring(firstTrailingWhitespaceIndex) - classes = 'trailing-whitespace' - classes += ' indent-guide' if hasIndentGuide and not firstNonWhitespaceIndex? and tokenIsOnlyWhitespace - classes += ' invisible-character' if hasInvisibleCharacters - - trailingHtml = "#{trailingWhitespace}" + trailingWhitespaceNode = document.createElement("span") + trailingWhitespaceNode.classList.add("trailing-whitespace") + trailingWhitespaceNode.classList.add("indent-guide") if hasIndentGuide and not firstNonWhitespaceIndex? and tokenIsOnlyWhitespace + trailingWhitespaceNode.classList.add("invisible-character") if hasInvisibleCharacters + trailingWhitespaceNode.textContent = tokenText.substring(firstTrailingWhitespaceIndex) endIndex = firstTrailingWhitespaceIndex - html = leadingHtml + scopeNode.appendChild(leadingWhitespaceNode) if leadingWhitespaceNode? + if tokenText.length > MaxTokenLength while startIndex < endIndex - html += "" + @escapeTokenText(tokenText, startIndex, startIndex + MaxTokenLength) + "" + tokenNode = document.createElement("span") + tokenNode.textContent = @sliceText(tokenText, startIndex, startIndex + MaxTokenLength) + scopeNode.appendChild(tokenNode) startIndex += MaxTokenLength else - html += @escapeTokenText(tokenText, startIndex, endIndex) + scopeNode.insertAdjacentText("beforeend", @sliceText(tokenText, startIndex, endIndex)) - html += trailingHtml - html + scopeNode.appendChild(trailingWhitespaceNode) if trailingWhitespaceNode? - escapeTokenText: (tokenText, startIndex, endIndex) -> + sliceText: (tokenText, startIndex, endIndex) -> if startIndex? and endIndex? and startIndex > 0 or endIndex < tokenText.length tokenText = tokenText.slice(startIndex, endIndex) - tokenText.replace(TokenTextEscapeRegex, @escapeTokenTextReplace) + tokenText - escapeTokenTextReplace: (match) -> - switch match - when '&' then '&' - when '"' then '"' - when "'" then ''' - when '<' then '<' - when '>' then '>' - else match - - buildEndOfLineHTML: (id) -> + appendEndOfLineNodes: (id, lineNode) -> {endOfLineInvisibles} = @newTileState.lines[id] - html = '' + hasInvisibles = false if endOfLineInvisibles? for invisible in endOfLineInvisibles - html += "#{invisible}" - html + hasInvisibles = true + + invisibleCharacter = document.createElement("span") + invisibleCharacter.classList.add("invisible-character") + invisibleCharacter.textContent = invisible + lineNode.appendChild(invisibleCharacter) + + hasInvisibles updateLineNode: (id) -> oldLineState = @oldTileState.lines[id]