Букмарклеты в Internet Explorer 11: формат хранения, лимиты и негласные правила, коварный баг

    После того, как сразу два букмарклета, работавшие в Google Chrome и Firefox, отказались работать в Internet Explorer 11, причём не выдавали в консоль никаких сообщений об ошибках и вообще не подавали признаков жизни, я стал разбираться, в чём же дело.

    Сначала я решил, что дело в лимите на длину URL и тем самым на длину букмарклета. В IE 7 ограничение было в 2083 символа, в IE 11, по уверениям экспериментировавших пользователей, лимит увеличили. Нужно было выяснить опытным путём, какова теперь эта граница.

    Но сперва небольшое предисловие.

    Google Chrome хранит закладки в JSON, Firefox — в базе данных sqlite. Поэтому названия у закладок могут быть произвольные. IE хранит каждую закладку как отдельный файл, например, в папке %userprofile%\Favorites\Links. Поэтому браузер будет корректировать названия закладок, чтобы они подходили под нормы файловой системы (заменять знаки вопроса, например). Поэтому же в IE не могут быть в одной папке две закладки с одинаковым именем, а в Google Chrome и Firefox — могут (закладки в них могут быть даже вообще без имени, только со значком сайта или стандартным заменителем).

    Google Chrome и Firefox позволяют создавать закладку с нуля, вводя в соответствующие поля название и URL, в том числе код букмарклета. При этом Google Chrome и Firefox удаляют в коде переводы строки, а с пробельными символами поступают по-разному: первый их частично удаляет, а частично оставляет, насколько позволяет синтаксис; второй превращает пробельные символы в знак %20, как это делают функции encodeURI() и encodeURIComponent(). После создания оба браузера позволяют редактировать и обычные закладки, и букмарклеты.

    В IE добавить букмарклет можно только путём перетаскивания ссылки на панель Избранного. Редактировать код после создания закладки в самом браузере уже нельзя (его даже нельзя в браузере посмотреть: во всплывающей подсказке видно только начало, а вызов свойств закладки открывает окно, в котором нет поля для URL или кода). Но есть обходной путь: можно редактировать файлы закладок в упомянутой папке.

    Эти файлы имеют расширение .url, а по формату идентичны текстовым файлам конфигурации .ini. Вот пример простого сохранённого в файл букмарклета для IE 11.

    [{000214A0-0000-0000-C000-000000000046}]
    Prop3=19,15
    [InternetShortcut]
    URL=javascript:(function(){alert('Hello, world!');})()
    IDList=
    [Bookmarklet]
    ExtendedURL=javascript:(function(){alert('Hello, world!');})()


    Эту заготовку можно использовать как шаблон: если заменить в ней обе строки кода и сохранить с допустимым именем файла в упомянутую папку, на панели Избранного появится новый букмарклет. При этом нужно учитывать такую особенность: IE считывает закладки один раз во время открытия окна или вкладки. Если вы отредактируете файл, окно или вкладка всё равно будут оперировать старой версией. Если же вы закроете окно и вновь его откроете или откроете новую вкладку, тогда изменения файла вступят для них в силу. Поэтому может быть такая ситуация, что нажатие на одну и ту же закладку в пяти разных вкладках может выдавать пять разных результатов, если перед каждым открытием вкладки вы редактировали файл. Путаницу усугубляет то обстоятельство, что IE экономит запущенные процессы: вы можете закрыть вкладку, IE оставит дочерний процесс в памяти и использует его при открытии другой вкладки, и наследие считанных закладок отойдёт к этой, уже не совсем новой вкладке. Поэтому при тестировании кода букмарклетов и прямом редактировании их файлов или перезапускайте одно окно, или открывайте новые вкладки, не закрывая предыдущие (наверное, проще будет использовать консоль).

    Теперь о формате файла, вернее об интересующей нас части. Как мы видим, URL или код букмарклета хранится в двух ключах-дубликатах. Но между ними есть как различие, так и взаимосвязь. Экспериментальным путём удалось выяснить следующие правила:

    1. Лимит ключа URL = 2083 знака. Лимит ключа ExtendedURL = 5119 знаков.
    2. При коде букмарклета более чем в 2083 знака IE обрывает значение ключа URL точно на 2083 знаке, отсекая механически всё оставшееся. Рабочий код он, очевидно, берёт только из второго ключа.
    3. При коде букмарклета более чем в 5119 знаков IE оставляет в ключе URL 2083 знака, а в ключе ExtendedURL оставляет весь код. При добавлении такой закладки в Избранное никаких предупреждений пользователю не выносится, букмарклет потом просто не работает, при безуспешных запусках никаких сообщений об ошибках в консоли тоже нет.
    4. При большом коде первые 2083 знака обоих ключей должны совпадать до символа. Если они будут отличаться хотя бы одним знаком или если первый ключ будет хотя бы 2082 знака, букмарклет не будет работать.

    Выяснив эти нормы, я проверил свои неработающие букмарклеты на соответствие. Никаких нарушений не было. Были они по три тысячи символов с лишним, все правила формата в файлах были соблюдены.

    Видно, придётся проверять с разными вариантами и размером кода, может, есть ещё скрытые правила, подумал я. Или есть неотлавливаемые ошибки, и нужно навставлять try-catch. В общем, готовиться к непредсказуемому количеству тестов.

    И тут я заметил, что оба файла имеют странное сходство в одной странной детали. В обоих значение ключа URL заканчивалось на пробеле. Я ещё раньше удивился, зачем это IE вставил пробел в конце строки. Но, присмотревшись, понял, что ничего IE не вставлял. По забавному стечению обстоятельств оба кода моих букмарклетов имели пробел на 2083 символе. И меня осенила сколь страшная, столь и спасительная догадка, которая тут же оправдалась испытаниями. Пришлось сформулировать ещё одно правило букмарклетов для IE 11, которое на самом деле скорее баг, нежели правило:

    5. Если в коде букмарклета на месте 2083 символа окажется пробел и, тем самым, пробел будет последним символом ключа URL, такой букмарклет работать не будет. Как и при перечисленных нарушениях правил, ни предварительных предупреждений, ни последующих сообщений об ошибках пользователь не получит.

    Из всего этого следуют как минимум два совета создающим букмарклеты для IE 11:

    — Проверяйте лимит символов в 5119 знаков.
    — Проверяйте отсутствие пробела на 2083 символе, или вычищайте пробелы по максимуму, или кодируйте javascript: URL при помощи функций, или вставляйте его из закладок Firefox.

    Напоследок приведу пример файла .url с пороговым размером ключей, для тех, кто захочет проверить описанное:

    test.url
    [{000214A0-0000-0000-C000-000000000046}]
    Prop3=19,15
    [InternetShortcut]
    URL=javascript:(function(){alert('123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123
    IDList=
    [Bookmarklet]
    ExtendedURL=javascript:(function(){alert('123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 12');})()
    


    Это код рабочего букмарклета. Он перестанет работать, если вы:

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

    Написано в надежде сохранить кому-то время и здоровье.

    Если кто-то знает сайт, куда есть смысл направить сообщение об этом сомнительном поведении (вроде bugzilla.mozilla.org для Firefox или code.google.com/p/chromium/issues/list для Google Chrome), сообщите, пожалуйста. Спасибо за внимание.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 6

      +1
      Баги IE принимаются на коннекте connect.microsoft.com/ie/feedback но стоит учесть, что он уже discontinued, и вряд ли в нём что-то будут менять.

      А у Edge публичный трекер на юзервойсе — wpdev.uservoice.com/forums/257854-microsoft-edge-developer (или можно послать ишью прямо из самого браузера, в менюхе есть соответствующий пункт).
        +1
        Хм. Выходит, сообщать об IE 11 поздно, а об Edge — рано? Ну, может, кто-то проверит, как с этим дела обстоят в Internet Explorer Developer Channel, и тогда отошлёт впрок. Это ведь предварительная версия Edge, насколько я понимаю?
          +1
          Edge отправится в свободное плавание через 5 дней, так что я бы не сказал, что рано. В Windows 10 помимо Edge есть MSIE12 с вроде бы как тем же движком.
            0
            Их ведь в Windows 7 не поставишь? Если нет, проверьте кто-нибудь из читавших после релиза, не поменялись ли обстоятельства, если это не отнимет много времени и усилий.
        0
        IE давно не торт, в нём даже нормальные расширения и виджеты невозможно писать.
          +1
          Хотя вроде скоро в EDGE будут доступны расширения в стиле Chrome.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое