Pull to refresh

Кроссбраузерные закладки на произвольное место страницы

Reading time 4 min
Views 4.2K

Введение


Бывают случаи, когда в браузере приходится читать большой текст в несколько приёмов. Это может быть роман, статья или техническое руководство. Хорошо, когда документ разделён на главы и снабжён удобной навигацией. Тогда, прерывая чтение, можно создать временную закладку на страницу раздела или на якорную точку в документе. А если текст сплошной? Или ссылки на внутренние разделы не предусмотрены? Или сами разделы слишком велики и трудно потом искать нужный абзац внутри раздела?

Один из выходов — сохранить документ на диск и читать при помощи любой программы, позволяющей создавать внутренние закладки или запоминающей место, на котором закрыли текст.

Но такое умножение сущностей не для всех удобно. Попробуем найти способ попроще.

Чтобы этот способ был универсальным, придётся ориентироваться не на структуру документа (он может вообще не содержать никаких тегов кроме body и, может быть, pre) и не на текстовое содержимое (в тексте могут быть повторяющиеся строки или документ может быть коллекцией неподписанных картинок). Остаётся ориентироваться на самое шаткое — на метрику. А именно — на расстояние, прокрученное от начала документа (страницы с горизонтальной прокруткой редки и пока можно ими пренебречь).

Вырисовывается алгоритм: нам нужно получить расстояние от начала документа до места чтения и где-то сохранить его, чтобы потом затребовать для прокрутки страницы до нужного участка. Для этого понадобится: кроссбраузерный способ определять расстояние прокрутки, кроссбраузерное хранилище для базы закладок и кроссбраузерный интерфейс для сохранения и восстановления позиции в документе (алгоритм можно использовать и для серверных решений, но нас пока интересует клиентская сторона).

У алгоритма будет по крайней мере два минуса: привязка к размерам окна браузера (правда, вряд ли пользователи часто меняют этот размер; вдобавок есть идея, как минимизировать эту зависимость) и поддержка только статичных документов (использовать, например, для часто изменяющейся страницы друзей в ЖЖ или для ленты новостей не получится).

1. Определение прокрутки


Так как Internet Explorer не поддерживает свойства window.scrollY и window.pageYOffset, будем использовать element.scrollTop. Какой элемент брать, зависит от режима работы браузера, то есть — от doctype страницы. В режиме следования стандартам (standards mode) нужно использовать document.documentElement.scrollTop, в режиме совместимости (quirks mode) — document.body.scrollTop. К счастью, нам нет нужды проверять режим: свойство scrollTop ошибочно выбранного элемента всегда будет равно нулю при любой прокрутке, поэтому можно просто перебрать оба элемента и сохранить значение, отличное от нуля.

2. Хранилище закладок


Единственный кроссбраузерный способ хранения, который представляется удобным, это технология Web Storage. Её поддерживают все последние версии популярных браузеров (Chrome 4+, Firefox 3.5+, Internet Explorer 8+, Opera 10.5+, Safari 4+). Скрепя сердце распрощаемся с поддержкой старых версий. Единственный минус: не все браузеры поддерживают эту технологию для локальных файлов. Поскольку функции объекта localStorage создают и запрашивают данные в базе, ориентируясь на домены страниц, а все локальные файлы (то есть страницы, загруженные по протоколу file:///) не имеют домена, налицо трудность, с которой не все браузеры до сих пор справились. Chrome, Opera и Safari поддерживают технологию localStorage для оффлайн-документов, создавая общее хранилище ключей для всех локальных файлов. Internet Explorer выдаёт ошибку, не находя объекта localStorage для документов без домена. Firefox вообще по-партизански молчит и ничего не делает в местах вызова функций (баг запротоколирован здесь и здесь). Поэтому для последних двух браузеров единственным выходом остаётся чтение онлайн или из кэша браузера.

Для каждой интересующей нас страницы мы будем создавать в базе уникальный ключ, состоящий из произвольного префикса и полного URL документа. Так закладки будут автоматически соотнесены с со своими объектами и их можно будет сохранять и запрашивать двумя миниатюрными универсальными функциями.

3. Интерфейс


До настоящего времени, кажется, нет общего способа создавать расширения под все браузеры. Поэтому нам остаётся старый проверенный путь — букмарклеты.

Соединяем компоненты


Создадим код для трёх функций: первая будет получать расстояние прокрутки и сохранять его в базе, вторая будет восстанавливать прокрутку страницы, третья — удалять закладку из базы (это уже факультативная прибавка).

Код сохранения прокрутки (создание закладки):
localStorage['bm_' + document.location.href] =
    document.documentElement.scrollTop || document.body.scrollTop;

Код восстановления прокрутки (переход по закладке):
window.scrollTo(0, localStorage['bm_' + document.location.href] || 0);

Код удаления закладки:
localStorage.removeItem('bm_' + document.location.href);

Когда мы удалим пробелы (пару пришлось оставить, иначе куски длинных строк исчезает за границами топика) и, следуя правилам, обернём код в анонимные функции, не возвращающие значения, мы получим следующие букмарклеты:

Код сохранения прокрутки (создание закладки):
javascript:(function(){localStorage['bm_'+document.location.href]= document.documentElement.scrollTop||document.body.scrollTop})()

Код восстановления прокрутки (переход по закладке):
javascript:(function(){window.scrollTo(0,localStorage['bm_'+document.location.href] ||0)})()

Код удаления закладки:
javascript:(function(){localStorage.removeItem('bm_'+document.location.href)})()

К сожалению, фильтры Хабрахабра не позволяют вставлять ссылки с кодом букмарклетов: из соображений безопасности подменяется название протокола javascript. Поэтому остаётся создать с нуля три закладки и вместо адреса ввести код функций.

Если кому-то это покажется неудобным, можно перетащить ссылки отсюда (в Internet Explorer лучше действовать через контекстное меню ссылок, добавляя их в нужную папку Избранного, потому что перетаскивание букмарклетов не всегда срабатывает).

Конечно, эти зачатки функций можно развивать уже средствами каждого браузера. Можно использовать GreaseMonkey или Custom Buttons для Firefox (или создать полноценное расширение), можно оформить алгоритм как виджет для Opera или расширение для Chrome. Можно наладить автоматическое создание закладок перед закрытием для нужных страниц и автоматический переход к последней позиции при их открытии. Можно добавлять к названию ключей в базе данных текущую метрику окна браузера, чтобы для разных размеров устанавливались свои закладки. Можно реализовать серверное решение (благо, никакой базы данных на стороне сервера не потребуется, ценой будет несколько строчек кода).

Будем считать это ещё одной иллюстрацией возможностей замечательной технологии Web Storage.
Tags:
Hubs:
+6
Comments 25
Comments Comments 25

Articles