Text nodeValue, содержащий объект HTML

Я создаю HTML-редактор в режиме реального времени, который загружается после того, как DOM был визуализирован, и создает источник, перебирая все узлы. Я заметил, что когда я пытаюсь прочитать nodeValue текста node, содержащего объект HTML, я всегда получаю отображаемое значение unicode этого объекта.

Как я могу прочитать визуализированный текст node и сохранить код объекта HTML? (с использованием ванили JS)

Пример:

<div id="test">copyright &copy;</div>
<script>
var test = document.getElementById('test');
console.log(test.childNodes[0].nodeValue);
// expected: copyright &copy;
// actual: copyright ©
</script>

Ответ 1

К сожалению, вы не можете. Интерфейс Text наследует от CharacterData, и оба интерфейса обеспечивают только DOMStrings как возвращаемое значение, которое содержит символы Юникода.

Кроме того, алгоритм синтаксического анализа HTML5 в основном полностью удаляет объект. Это определено в нескольких разделах 8.2.4 Tokenization.

  • 8.2.4.1 Состояние данных: описывает, что амперсанд помещает синтаксический анализатор в ссылку Character в состоянии данных
  • 8.2.4.2 Символьная ссылка в состоянии данных описывает, что токены, за которыми следует амперсанд, должны потребляться. Если все работает нормально, оно вернет маркеры символов Unicode, а не сущность!
  • 8.2.4.69 Обозначение символьных ссылок описывает, как интерпретировать &...; (в основном делать что-то, и если все в порядке, look это в таблице).

Таким образом, к моменту завершения вашего анализатора объект уже ушел и был заменен символами Unicode. Это не удивительно, так как вы можете просто поместить символ © прямо в свой HTML-код, если хотите.

Тем не менее, вы все равно можете отменить это преобразование: вам нужно взять копию table и проверить наличие любого символа в вашем документе независимо от того, в нем есть запись:

var entityTable = {
  169: "&copy;"
}

function reEntity(character){
  var index = character.charCodeAt(0), name;

  if( index < 127) // ignore ASCII symbols
    return character;

  if( entityTable[index] ) {
    name = entityTable[index];
  } else {
    name = "#"+index;
  }
  return "&"+name+";"
}

Это довольно громоздкая задача, но из-за поведения парсера вы, вероятно, должны это сделать. (Не забудьте проверить, действительно ли кто-то это сделал).