Jsdom: реализация внутреннего текста

Созданный на 25 сент. 2015  ·  26Комментарии  ·  Источник: jsdom/jsdom

jsdom — отличный инструмент для textContent — очень неудобный способ получить читаемый текст для преобразования html2text.

Есть замечательная статья о полезности ничтожных innerText во многих случаях:

http://perfectionkills.com/the-poor-misunderstood-innerText/

Автор предлагает getSelection().toString() как очень медленный обходной путь, но getSelection еще не реализован в jsdom .

Не могли бы вы рассмотреть возможность реализации innerText в jsdom ? Автор провел большое исследование этого, он даже добавил простую спецификацию в конце.

feature layout

Самый полезный комментарий

В случае, если кто-то еще сталкивается с этой проблемой, я сделал еще один шаг и использовал пакет sanitize-html , чтобы получить в основном то, что делает браузер (обратите внимание, что я не импортировал настройку JSDOM, поскольку обнаружил, что она не нужна когда помещаю это в мой установочный файл Jest, но если вы не используете Jest, вам нужно использовать настройку global.Element = (new JSDOM()).window.Element , рекомендованную @bennypowers ):

Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return sanitizeHtml(this.textContent, {
      allowedTags: [], // remove all tags and return text content only
      allowedAttributes: {}, // remove all tags and return text content only
    });
  },
  configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
});

Все 26 Комментарий

И как жаль , что стройный Selection и innerText библиотека не совместима с jsdom: https://github.com/timdown/rangy/issues/348

Итак, innerText не является стандартным и не реализован как минимум в одном крупном движке (Firefox). Без стандарта я не думаю, что мы должны его внедрять.

Похоже, во всем этом есть какое-то движение с черновиком спецификации здесь . См. также все ссылки . Однако в репозитории нет проблем, поэтому мне интересно, насколько он уже завершен / насколько быстрым будет прогресс.

В Firefox реализовано: https://bugzilla.mozilla.org/show_bug.cgi?id=264412.

Семмы WHATWG для утверждения: https://github.com/whatwg/compat/issues/5#issuecomment -168049752

Из спецификации кажется, что мы не можем правильно реализовать innerText без базовой поддержки макета.

Да, это все равно не будет реализовано в jsdom, без большой работы с инфраструктурой... никто не надеется :(.

Что касается требований к поддержке макета: https://github.com/rocallahan/innerText-spec/issues/2

Есть ли какие-либо планы по его внедрению в связи с принятием WHATWG?

Да ... Хотя спецификация требует много вещей, которых нет в jsdom, вокруг блоков CSS :(. Не знаю, что делать.

Есть ли какая-нибудь библиотека для этого, чтобы подключиться к jsdom?

@domenic не могли бы рассказать, почему это такая перестройка инфраструктуры? Мы думали, что 800-фунтовая горилла в комнате уйдет из дома. Но, похоже, никуда не денется. Как вы знаете, я ломал голову над внутренностями jsdom. С какого места в репозитории можно начать просмотр кода для новичка в jsdom?

Заранее спасибо 🙏 /cc @vsemozhetbyt

Основная проблема заключается в том, что innerText руководствуется механизмом компоновки, а jsdom не имеет механизма компоновки. См. https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-attribute и
http://perfectionkills.com/the-poor-misunderstood-innerText/ . Из второй ссылки:

Обратите внимание, как innerText почти точно представляет, как текст отображается на странице. textContent, с другой стороны, делает что-то странное — он игнорирует новые строки, созданные
и вокруг блочных элементов ( в данном случае).

Все еще выходит за рамки и нет обходного пути?

Видимо в спецификации написано:

Если этот элемент не визуализируется или если пользовательский агент не является пользовательским агентом CSS, [курсив мой] верните то же значение, что и IDL-атрибут textContent для этого элемента.

Я думаю, что тогда обходным путем было бы просто вернуть textContent .

Мы реализуем столько CSS, что я не думаю, что это применимо. Мы просто не реализуем части макета...

Привет, ребята, есть новости по этому поводу?

Просто используйте безголовый хром :)

@domenic из той спецификации, которую упомянул
https://html.spec.whatwg.org/multipage/dom.html#the -innertext-idl-атрибут

Если этот элемент не обрабатывается или если пользовательский агент не использует CSS, верните то же значение, что и IDL-атрибут textContent для этого элемента.

https://html.spec.whatwg.org/multipage/rendering.html#being -рендеринг

Элемент визуализируется, если он имеет какие-либо связанные блоки макета CSS, блоки макета SVG или некоторый эквивалент в других языках стилей.

Если jsdom не реализует части макета, не означает ли это, что применяется «не отображается»?

Это сообщение предназначено для всех, кто обращается к этой ветке github и просто хочет, чтобы их тесты проходили без изменения реализации их функций.

копипаст для верхней части ваших тестовых файлов:

// Expose JSDOM Element constructor
global.Element = (new JSDOM()).window.Element;
// 'Implement' innerText in JSDOM: https://github.com/jsdom/jsdom/issues/1245
Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return this.textContent;
  },
});

Естественно, применяются оговорки из приведенного выше обсуждения.

В случае, если кто-то еще сталкивается с этой проблемой, я сделал еще один шаг и использовал пакет sanitize-html , чтобы получить в основном то, что делает браузер (обратите внимание, что я не импортировал настройку JSDOM, поскольку обнаружил, что она не нужна когда помещаю это в мой установочный файл Jest, но если вы не используете Jest, вам нужно использовать настройку global.Element = (new JSDOM()).window.Element , рекомендованную @bennypowers ):

Object.defineProperty(global.Element.prototype, 'innerText', {
  get() {
    return sanitizeHtml(this.textContent, {
      allowedTags: [], // remove all tags and return text content only
      allowedAttributes: {}, // remove all tags and return text content only
    });
  },
  configurable: true, // make it so that it doesn't blow chunks on re-running tests with things like --watch
});

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

function innerText(el)
  el = el.cloneNode(true) // can skip if mutability isn't a concern
  el.querySelectorAll('script,style').forEach(s => s.remove())
  return el.textContent
}

Какая жалость!

Видимо в спецификации написано:

Если этот элемент не визуализируется или если пользовательский агент не является пользовательским агентом CSS , [выделение добавлено], верните то же значение, что и IDL-атрибут textContent для этого элемента.

Я думаю, что обходным путем было бы просто вернуть textContent.

Мы реализуем столько CSS, что я не думаю, что это применимо. Мы просто не реализуем части макета...

@domenic, пожалуйста, рассмотрите более либеральную интерпретацию спецификации

textContent явно разрешено в качестве запасного варианта, когда применение правил CSS слишком дорого.

также, innerText указан как геттер и сеттер

Учитывая, что я редактор спецификации, я могу с уверенностью заявить, что «когда применение правил CSS слишком дорого» — это не то, о чем говорится в спецификации.

.. это была моя интерпретация «если пользовательский агент не является пользовательским агентом CSS»

в чем разница между «пользовательским агентом CSS» и «пользовательским агентом без CSS»?

как насчет:
пользовательский агент CSS может «применять правила CSS» и выводить результат (графический или текстовый)
пользовательский агент, не использующий CSS, слишком глуп, чтобы «применять правила CSS»

Мы реализуем столько CSS, что я не думаю, что это применимо.

что ты имеешь в виду? окно.getComputedStyle?

откат к textContent все же лучше, чем отсутствие стандартного интерфейса

Возможно, мы можем просто использовать значение textContent для замены результата innerText при выполнении тестов с помощью jsdom . Например:

describe('mytest', () => {
  beforeAll(() => {
    Object.defineProperty(HTMLElement.prototype, 'innerText', {
      get() {
        return this.textContent;
      }
    });
  });
  it('should ok', () => {
  // test assertions
  });
});
Была ли эта страница полезной?
0 / 5 - 0 рейтинги