| 128 | // Build up the DOM representation for a single token, and add it to |
| 129 | // the line map. Takes care to render special characters separately. |
| 130 | function buildToken(builder, text, style, startStyle, endStyle, css, attributes) { |
| 131 | if (!text) return |
| 132 | let displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text |
| 133 | let special = builder.cm.state.specialChars, mustWrap = false |
| 134 | let content |
| 135 | if (!special.test(text)) { |
| 136 | builder.col += text.length |
| 137 | content = document.createTextNode(displayText) |
| 138 | builder.map.push(builder.pos, builder.pos + text.length, content) |
| 139 | if (ie && ie_version < 9) mustWrap = true |
| 140 | builder.pos += text.length |
| 141 | } else { |
| 142 | content = document.createDocumentFragment() |
| 143 | let pos = 0 |
| 144 | while (true) { |
| 145 | special.lastIndex = pos |
| 146 | let m = special.exec(text) |
| 147 | let skipped = m ? m.index - pos : text.length - pos |
| 148 | if (skipped) { |
| 149 | let txt = document.createTextNode(displayText.slice(pos, pos + skipped)) |
| 150 | if (ie && ie_version < 9) content.appendChild(elt("span", [txt])) |
| 151 | else content.appendChild(txt) |
| 152 | builder.map.push(builder.pos, builder.pos + skipped, txt) |
| 153 | builder.col += skipped |
| 154 | builder.pos += skipped |
| 155 | } |
| 156 | if (!m) break |
| 157 | pos += skipped + 1 |
| 158 | let txt |
| 159 | if (m[0] == "\t") { |
| 160 | let tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize |
| 161 | txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")) |
| 162 | txt.setAttribute("role", "presentation") |
| 163 | txt.setAttribute("cm-text", "\t") |
| 164 | builder.col += tabWidth |
| 165 | } else if (m[0] == "\r" || m[0] == "\n") { |
| 166 | txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar")) |
| 167 | txt.setAttribute("cm-text", m[0]) |
| 168 | builder.col += 1 |
| 169 | } else { |
| 170 | txt = builder.cm.options.specialCharPlaceholder(m[0]) |
| 171 | txt.setAttribute("cm-text", m[0]) |
| 172 | if (ie && ie_version < 9) content.appendChild(elt("span", [txt])) |
| 173 | else content.appendChild(txt) |
| 174 | builder.col += 1 |
| 175 | } |
| 176 | builder.map.push(builder.pos, builder.pos + 1, txt) |
| 177 | builder.pos++ |
| 178 | } |
| 179 | } |
| 180 | builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32 |
| 181 | if (style || startStyle || endStyle || mustWrap || css || attributes) { |
| 182 | let fullStyle = style || "" |
| 183 | if (startStyle) fullStyle += startStyle |
| 184 | if (endStyle) fullStyle += endStyle |
| 185 | let token = elt("span", [content], fullStyle, css) |
| 186 | if (attributes) { |
| 187 | for (let attr in attributes) if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class") |