MarkIt Хайлайтер
Это ссылка на расширение Chrome, которая позволяет выделять важный текст на любой веб-странице. Посетите страницу повторно через 1 минуту, 1 неделю или 1 год — ваши данные всегда будут там.
Технологии
- (Ванильный) JavaScript
- Google API
Функции
- Выделите любой текст и нажмите Command+K, чтобы сохранить его автоматически.
- Пользователь может очистить сохраненные выделения для любого URL-адреса с помощью одной простой команды: Command+Shift+A.
- Синхронизируется на всех устройствах — если вы выделяете текст с ноутбука, а затем просматриваете ту же веб-страницу с телефона, ваши выделения будут там (если вы вошли в Chrome на обоих устройствах).
Моя сохраненная структура данных (объект)
highlights = {
google.com: {
text1: ["query selector", index, note, color]
text2: ["query selector", index, note, color]
},
yahoo.com: {
text3: ["query selector", index, note, color],
text4: ["query selector", index, note, color]
},
https://developer.mozilla.org/en-US/docs/Web/API/document/execCommand: {
"When an HTML document has been switched to designMode, its document object exposes an execCommand": ["p.summary", 20],
"A DOMString specifying the name of the command to execute. See Commands for a list of possible commands.": ["p", 0, "example note", #CFFFDF]
}
}
Как это работает
У меня есть два скрипта, которые загружаются на каждой странице. Первый — фоновый.js, который прослушивает определенное событие. Событие Command+K запускает функцию, которая вставляет в браузер скрипт (injection_script.js), который выделяет выделенный текст.
Чтобы выделить, перетащите указатель мыши на текст и нажмите Command+K. Это запускает функцию, которая вызывает несколько других. Последовательность событий:
- Захватывает выделенный текст
- Включает режим разработки, позволяя нам вносить временные изменения в DOM.
- Если фон уже подсвечен, то нам нужно убрать подсветку:
- Выбирает тег <span>, окружающий текст, и устанавливает style.backgroundColor = прозрачный (удаляет подсветку)
- Получает объект «Основные моменты» из хранилища —
chrome.storage.get()
- Просматривает все ключи (которые представляют собой сохраненные основные моменты) в поисках совпадения и удаляет их из хранилища.
- В противном случае оберните текст в <span> и примените цвет фона.
- При обновлении страницы: получение «основных моментов» из хранилища.
- Если данных для активного URL-адреса нет, установите ключ для текущего URL-адреса и значение для пустого объекта (aol.com: {}).
- Если есть, возьмите структуру данных основных моментов из хранилища (chrome.storage.get()).
- Получите и присвойте допустимое значение селектора запроса для выделенного текста (оно будет использоваться для запроса DOM и применения выделения позже. Для уточнения обратитесь к структуре объекта выше).
- Если родительский элемент выделенного текста имеет имя класса, сохраните строку «element.className» («p.firstParagraph», «h2.sectionHeader» и т. д.).
- Если имени класса нет, сохраните строку «элемент» («p», «h2», «li» и т. д.)
- Присвойте ключу (выделенному тексту) значение (массив, содержащий 2 значения: во-первых, селектор запроса и, во-вторых, индекс того, где выбранный текст встречается в родительском элементе)
- Я сохраняю индекс строки, потому что, если бы я сохранил только текст и селектор запроса, скажем, вы выделили «the» под тегом «p», при применении выделения, если вы обновите страницу, каждое отдельное появление «the» в Тег «p» будет выделен. Добавление значения indexOf позволяет мне убедиться, что индексы соответствуют DOM, и только затем применить выделение, поэтому я применяю выделение к правильному слову.
- Сохраните обновленную переменную Highlights, содержащую новый выделенный текст, используя chrome.storage.set().
- Выключите режим дизайна.
Второй файл JavaScript, который запускается на каждой странице, — content_script.js. Он проверяет, существует ли сохраненный объект под названием «highlights». Если его нет, это означает, что пользователь никогда ничего не выделял. Затем он создает пустой объект и сохраняет его в Chrome.
Если он находит объект «основные моменты», он проверяет, есть ли сохраненные данные для активного URL-адреса. Если нет, скрипт возвращается.
Если для URL-адреса сохранены основные моменты:
- Функция applyHighlights() запускается
- Он принимает два параметра: объект «Основные моменты» и активный URL-адрес.
- Проходит по ключам сохраненного объекта (ключи — это сохраненные основные моменты, тогда как значения этих ключей представляют собой массив, содержащий значения querySelector и indexOf)
- Запускает document.body.querySelectorAll(), чтобы получить массив всех совпадающих узлов.
- Проходит по каждому возвращенному узлу, и если внутренний HTML содержит «строку», соответствующую ключу объекта (выделенному тексту) И с тем же значением indexOf: 1. Запускает функцию .replace(), заключающую соответствующий текст в тег <span> с помощью встроенный атрибут стиля для цвета фона
- Примечание: изначально я рекурсивно просматривал каждый узел DOM, чтобы проверить совпадения, но сохранение значения querySelector и сравнение значений HTML только совпадающих узлов с моими сохраненными значениями происходит значительно быстрее.
Обновления для следующей версии
- Сохраните конкретную строку, которую вы выделили
- «Загрузите библиотеку jQuery с сайта jQuery.com».
- Если вы выделите второй «jQuery», сохраненное значение будет относиться к первому экземпляру.
- Это связано с тем, что значение indexOf, которое я сохраняю, возвращается после первого совпадения.
- PLAN — начать подсчет индекса после тега span.
- невозможно выделить элементы блока (если вы перетащите выделение из h2 в тег ap, будет зарегистрирован только h2)
- В ПРОГРЕССЕ: разрешить пользователям выбирать цвет выделения
- В настоящее время жестко запрограммировано
- Показывать количество выделенных и фактически выделенных моментов на странице в расширении popup.html.
- Ограничения/крайние случаи: электронная почта, PDF-файлы.
- Я запрашиваю разрешения для каждого сайта. к которому некоторые сайты блокируют доступ '*' (cnn.com)
- Если вы выделите «jQuery» в одном элементе, anxd выделите его еще раз в другом, второй переопределит первый (поскольку ключ тот же)
- Если родительский элемент является встроенным тегом, indexOf indexOf не регистрируется (-1) или завершает выделение в конце встроенного тега. Найдите индекс тега span и запустите indexOf там.
- Режим свертывания: сверните документ только до родительских элементов сохраненных выделенных фрагментов.
Решенные проблемы
- Сохранение основных моментов, охватывающих теги встроенных элементов (a, em, st и т. д.)
- Раньше сохранялся только текст перед встроенным тегом, потому что я сохранял внутренний текст
- Я решил это, сохранив вместо этого внутренний HTML
- Проблема, возникшая в результате этого изменения, заключалась в том, что я хранил indexOf для внутреннего текста, который повторно применял бы выделение к стандартному тексту внутри текстового элемента, например тега «p». Но indexOf отличается для элементов, окружающих строчные элементы, поскольку indexOf подсчитывает каждый символ в тегах.
- Чтобы решить эту проблему, я сравниваю значения InnerText.indexOf И InnerHTML.indexOf и сравниваю каждое из них с соответствующими узлами при применении выделения к страницам, которые пользователь посещает снова.
- Если вы дважды щелкнули, чтобы выделить раздел, значения indexOf не зарегистрируются, и поэтому мое приложение не сможет повторно применить выделение.
- Чтобы решить эту проблему, я добавил методы .toString() и .trim() в indexOf(...)
- Выделение тега <a> приведет к удалению ссылки при загрузке страницы.
Будущие обновления
## Пример изображения
Краевые случаи
- Если имена классов меняются
- Решение: если имя класса не существует в DOM, удалите имя класса из селектора запросов и просто выполните поиск по узлам тегов элементов.
- Если контент скрыт кнопкой, мои основные моменты не будут регистрироваться, поскольку он выполняет поиск on_load, а контент открывается только после события браузера (вот почему он не работает с электронной почтой)
Разрешить кому-либо доступ ко всем выделенным элементам в popup.html. Разрешить пользователям изменять цвет выделения. Исправить ошибку выделения встроенного элемента.