Windows that never close

Ограничения window.close()

Порой веб-разработчики с удивлением обнаруживают, что команда windows.close() не всегда закрывает окно браузера. А в консоли инструментов разработчика браузера при этом выводится сообщение, указывающее на то, что скрипты могут закрывать только окна, которые ими же и открыты:

Почему браузеры ограничивают команду close()?

Прежде чем мы перейдём к разговору о том, какие факторы влияют на поведение браузера при вызове close() , важно сначала разобраться с тем, почему вообще существуют ограничения, применяемые при выполнении этой команды.

Иногда такое поведение браузеров объясняют, ссылаясь на некие таинственные «соображения безопасности». Но основная причина ограничений, применяемых к close() , больше связана с тем, что называют «пользовательский опыт». А именно, если скрипты смогут свободно закрывать любые вкладки браузеров, пользователь может потерять важные данные, состояние веб-приложения, работающего во вкладке. Это, кроме того, если вкладка или окно браузера неожиданно закрывается, может привести к нарушению механизмов перемещения по истории посещения страниц. Такие перемещения выполняются браузерными кнопками Вперёд и Назад (в Internet Explorer мы называли этот механизм TravelLog ). Предположим, пользователь применяет вкладку браузера для исследования результатов поиска. Если одна из изучаемых им страниц сможет закрыть вкладку, хранящую стек навигации, историю посещённых страниц, среди которых — страница с результатами поиска, это будет довольно-таки неприятно.

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

Что написано в стандартах?

Вот что об этом всём говорится в разделе dom-window-close стандарта HTML:

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

Тут, вроде бы, всё достаточно просто и понятно, хотя те части текста, которые я выделил, скрывают в себе много сложностей и тонкостей. (Совершенно закономерным можно счесть такой вопрос: «Что делать, если скрипт был запущен в ответ на действия пользователя?».)

Как поступают браузеры?

К нашему сожалению, у каждого браузера имеется собственный набор моделей поведения, связанный с window.close() (можете поэкспериментировать с этой тестовой страницей). Отчасти это так из-за того, что большинство этих моделей поведения было реализовано до появления соответствующего стандарта.

▍Internet Explorer

В Internet Explorer вкладка или окно браузера закрывается без лишних вопросов в том случае, если для создания этой вкладки или этого окна была использована команда window.open() . Браузер не пытается удостовериться в том, что история посещений страниц вкладки содержит лишь один документ. Даже если у вкладки будет большой TravelLog , она, если открыта скриптом, просто закроется. (IE, кроме того, позволяет HTA-документам закрывать самих себя без каких-либо ограничений).

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

Окна для подтверждения закрытия вкладки или окна

▍Chromium (Microsoft Edge, Google Chrome и другие браузеры)

В Chromium 88 команда window.close() выполняется успешно в том случае, если у нового окна или у новой вкладки что-то записано в свойство opener, или в том случае, если стек навигации страницы содержит менее двух записей .

Как видите, тут наблюдается небольшое отличие того, что требует спецификация, от того, что реализовано в браузере.

Во-первых — обратите внимание на то, что я упомянул свойство opener , а не сказал о том, что «страница была создана скриптом». Вспомним о том, что свойство opener позволяет всплывающему окну обращаться к создавшей его вкладке.

  • Если пользователь создаёт новую вкладку, щёлкнув по соответствующей кнопке, воспользовавшись комбинацией клавиш Ctrl + T , щёлкнув по ссылке и нажав при этом Shift , открыв URL из командной оболочки, то у открытой в результате вкладки свойство opener установлено не будет.
  • А если вкладка была открыта с помощью команды open() или через гиперссылку с заданным атрибутом target (не _blank ), тогда, по умолчанию, в свойство opener записывается некое значение.
  • У любой ссылки может быть атрибут rel=opener или rel=noopener , указывающий на то, будет ли у новой вкладки установлено свойство opener .
  • При выполнении JavaScript-вызова open() можно, в строке windowFeatures , указать noopener , что приведёт к установке свойства opener новой вкладки в null .
Читайте также:  Star stable windows 10

Вышеприведённый список позволяет сделать вывод о том, что и обычный щелчок по ссылке, и использование JavaScript-команды open() может привести к созданию вкладки как с установленным, так и с неустановленным свойством opener . Это может вылиться в серьёзную путаницу: открытие ссылки с зажатой клавишей Shift может привести к открытию вкладки, которая не может сама себя закрыть. А обычный щелчок мыши по такой ссылке приводит к открытию вкладки, которая всегда может закрыть себя сама.

Во-вторых — обратите внимание на то, что в начале этого раздела я, говоря о стеке навигации, употребил слово «записи», а не «объекты Document». В большинстве случаев понятия «запись» и «объект Document» эквивалентны, но это — не одно и то же. Представьте себе ситуацию, когда в новой вкладке открывается HTML-документ, в верхней части которого содержится нечто вроде оглавления. Пользователь щёлкает по ToC-ссылке, ведущей к разделу страницы #Section3 , после чего браузер послушно прокручивает страницу к нужному разделу. Стек навигации теперь содержит две записи, каждая из которых указывает на один и тот же документ. В результате Chromium-браузер блокирует вызов window.close() , а делать этого ему не следует. Этот давний недостаток с выходом Chromium 88 стал заметнее, чем раньше, так как после этого ссылкам с атрибутом target , установленным в _blank , по умолчанию назначается атрибут rel=noopener .

В ветке трекера ошибок Chromium, посвящённой проблеме 1170131, можно видеть, как эту проблему пытаются решить путём подсчёта количества объектов Document в стеке навигации. Но сделать это непросто, так как в настоящее время у процесса, отвечающего за рендеринг страницы, в котором выполняется JavaScript-код, есть доступ только к количеству записей в стеке навигации, но не к их URL.

▍Chromium: пользовательский опыт

Когда браузер Chrome блокирует команду close() , он выводит в консоль следующее сообщение, которое мы уже обсуждали:

А пользователю, который в консоль обычно не смотрит, об этом никак не сообщается. Это может показаться странным тому, кто щёлкнул по кнопке или по ссылке, предназначенной для закрытия страницы. В недавно появившемся сообщении об ошибке 1170034 предлагается показывать пользователю в такой ситуации диалоговое окно, вроде того, что показывается в Internet Explorer. (Между прочим, это сообщение об ошибке задаёт новый стандарт подготовки подобных сообщений. В нём, в виде, напоминающем комикс, показано, как несчастный пользователь превращается в счастливого в том случае, если в Chromium будет реализован предлагаемый функционал.)

▍Chromium: любопытные факты об очень редкой ошибке

То, о чём пойдёт речь, представляет собой весьма хитрый сбой, «пограничный случай», возникающий лишь в особых ситуациях. Но я, в течение пяти лет, встречался с сообщениями о подобном сбое, касающимися и Chrome, и Edge.

Речь идёт о том, что если установить свойство Chromium On Startup (При запуске) в значение Continue where you left off (Восстановить вкладки предыдущего сеанса), перейти на страницу, которая пытается сама себя закрыть, а после этого закрыть окно браузера, то браузер потом, при каждом запуске, будет сам себя закрывать.

Попасть в такую ситуацию довольно сложно, но в Chrome/Edge 90 это вполне возможно.

Вот как воспроизвести эту ошибку. Посетите страницу https://webdbg.com/test/opener/. Щёлкните по ссылке Page that tries to close itself (Страница, которая пытается себя закрыть). Воспользуйтесь сочетанием клавиш Ctrl+Shift+Delete для очистки истории просмотра (стека навигации). Закройте браузер с помощью кнопки X . Теперь попробуйте запустить браузер. Он будет запускаться, а потом сам собой закрываться.

▍Safari/WebKit

Код WebKit похож на код Chromium (что неудивительно, учитывая их генеалогию). Исключением является лишь тот факт, что WebKit не уравнивает переходы по noopener-страницам с переходами, инициированными через интерфейс браузера. В результате пользователь, работая в Safari, может перемещаться по множеству страниц с одного сайта, а команда close() при этом будет работоспособна.

Читайте также:  Intel b85 chipset driver windows 10

Если же вызов close() окажется заблокированным, то в JavaScript-консоль Safari (надёжно скрытую от посторонних глаз) будет выведено сообщение, указывающее на то, что окно закрыть нельзя из-за того, что оно создано не средствами JavaScript:

▍Firefox

В браузере Firefox, в отличие от Chromium, та часть спецификации HTML, в которой говорится о «только одном Document», реализована корректно. Firefox вызывает функцию IsOnlyTopLevelDocumentInSHistory() , а она вызывает функцию IsEmptyOrHasEntriesForSingleTopLevelPage() , которая проверяет историю сессий. Если там больше одной записи, она уточняет, относятся ли они все к одному и тому же объекту Document. Если это так — вызов close() выполняется.

Firefox даёт в наше распоряжение настройку about:config , называемую dom.allow_scripts_to_close_windows , позволяющую переопределить стандартное поведение системы.

Когда Firefox блокирует close() — он выводит в консоль сообщение о том, что скрипты не могут закрывать окна, которые были открыты не скриптами:

В трекере ошибок Firefox уже 18 лет лежит просьба о том, чтобы браузер показывал бы в подобной ситуации соответствующее окно, а не ограничивался бы выводом сообщения в консоль.

Итоги

Что тут скажешь? Возможно, дело в том, что браузеры — это жутко сложные создания.

Приходилось ли вам сталкиваться с проблемами, вызванными отличиями реализаций чего-либо в разных браузерах?

The IPO window that never closes

Hello and welcome back to Equity, TechCrunch’s venture capital-focused podcast, where we unpack the numbers behind the headlines.

This week was a bit of a turn-about. Kate was off this week and Alex was back, so we brought back a few favorites to tide us over until our regular leader returns. For this IPO-themed episode, we had TechCrunch and Extra Crunch’s Danny Crichton in the studio along with Deloitte’s Barrett Daniels, a prior guest on the show and one of our favorite humans.

It being roughly the middle of the year, we decided to do a bit of a run through the first two-quarters’ worth of tech IPOs. There was, as you can expect, a lot to get chatting about.

We started with notes on how the Chinese venture capital market is changing, most notably in terms of its share of the world’s largest venture rounds. After leading the world for what felt like years, venture investment into China-based companies is slipping. And the declines are picking up attention (here, here).

But not all the news was gloomy on the show this week. Indeed, while some global data relating to the global IPO market wasn’t exactly sparkling, the U.S.-listed tech IPO market is doing really well.

After we went over a number of the companies that went out and did well post-IPO (nearly every company aside from the ride-hailing players), we conceded that things are pretty damn warm for companies going public. At the same time, we couldn’t agree on how long the IPO market would remain so welcoming.

If it stays open, more unicorns will make it out. If the IPO window closes soon, we’ll see hundreds of unicorns trapped on the wrong side of the glass.

And we wrapped with notes on everyone’s favorite space-faring SPAC. We’ll see you all really soon.

window.close и self.close не закрывают окно в Chrome

Проблема в том, что когда я вызываю window.close() или self.close() он не закрывает окно. Теперь кажется, что в Chrome невозможно закрыть с помощью скрипта любое окно, которое не было создано скриптом. Это явно неверно, но независимо от того, что он все еще должен это делать, даже если для подтверждения требуется всплывающее предупреждение. Это не происходит.

Так есть ли у кого-нибудь реальный, функциональный и проверенный метод закрытия окна с использованием чего-то подобного javascript:window.close() или javascript:self.close() действительно выполняющий то, что ожидается, и то, что происходит просто отлично в каждом браузере, НЕ основанном на Chrome? Любые предложения будут с благодарностью, и я ищу Javascript для конкретного решения, ничего JQuery или сторонней реализации.

Обновление: хотя большая часть из того, что было предложено, имеет серьезные ограничения и проблемы с удобством использования, последнее предложение (специфичное для TamperMonkey), используемое // @grant window.close в заголовке скрипта, часто помогает, даже на тех вкладках, которые обычно не могут обработать метод close. Хотя это не совсем идеально и не обобщается на каждый случай, в моем случае это хорошее решение.

Читайте также:  Ets 2 для linux

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

close() Метод на Window объекты должны, если все следующие условия, близко контекст просмотра :

  • Соответствующий контекст просмотра A является закрываемым сценарием .
  • Контекстное просмотр действующего сценария знаком с контекстным просмотра A .
  • Просмотра контекста сценария действующего разрешено перемещаться контекстным просмотр A .

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

Это означает, что за одним небольшим исключением нельзя разрешать JavaScript закрывать окно, которое не было открыто этим же JavaScript.

Chrome допускает это исключение, которое не распространяется на пользовательские скрипты, а Firefox — нет. Реализация Firefox гласит :

Этот метод разрешается вызывать только для тех окон, которые были открыты скриптом с использованием window.open метода.

Если вы пытаетесь использовать window.close с Greasemonkey / Tampermonkey / userscript вы получите:
Firefox: Сообщение об ошибке « Scripts may not close windows that were not opened by script. »
Chrome: просто молча терпит неудачу.

Долгосрочное решение:

Лучший способ справиться с этим — создать вместо него расширение Chrome и / или дополнение для Firefox. Они могут надежно закрыть текущее окно.

Тем не менее, поскольку риски безопасности, связанные с этим window.close , намного меньше для сценария Greasemonkey / Tampermonkey; Greasemonkey и Tampermonkey могли бы разумно предоставить эту функциональность в их API (по сути, упаковывая работу расширения для вас).
Рассмотрите возможность запроса функции.

Хакерские обходные пути:

В настоящее время Chrome был уязвим для эксплойта «самостоятельного перенаправления». Так что код, подобный этому, работал в целом:

Это ошибочное поведение, IMO, и сейчас (по состоянию на апрель 2015 года) в основном заблокировано. Он все равно будет работать из введенного кода, только если вкладка была недавно открыта и не имеет страниц в истории просмотра. Так что это полезно только в очень небольших обстоятельствах.

Тем не менее, вариант все еще работает на Chrome (v43 и v44) плюс Tampermonkey (v3.11 или более поздняя версия) . Используйте явное @grant и простое window.close() . НАПРИМЕР:

Спасибо zanetu за обновление. Обратите внимание, что это не будет работать, если открыта только одна вкладка. Закрывает только дополнительные вкладки.

Fire Fox защищен от этой атаки. Таким образом, единственный способ javascript — нанести вред настройкам безопасности, по одному браузеру за раз.

Вы можете открыть about:config и установить
allow_scripts_to_close_windows на true .

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

Там в настоящее время нет эквивалентной настройки для Chrome.

Chrome Исправлены проблемы безопасности в версии 36.0.1985.125

Chrome 36.0.1985.125 СРЕДА, 16 ИЮЛЯ 2014 выпуске

По моим наблюдениям, это обновление исправило проблему с использованием window.close() для закрытия всплывающего окна. Вы увидите это в консоли, когда произойдет сбой: «Сценарии могут закрывать только те окна, которые были открыты им». Это означает, что хакерские обходные пути (ответ Брока Адамса) могут не работать в последней версии.

Таким образом, в предыдущих выпущенных сборках Chrome приведенный ниже блок кода мог работать, но не с этим обновлением.

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

способ удалить это. API-интерфейс расширений Chrome можно найти по адресу chrome.windows .

Собственно мое хромовое расширение MarkView столкнулось с этой проблемой, и мне пришлось обновить свой код, чтобы он работал для этого обновления Chrome. Кстати, MarkView — это инструмент для чтения и записи Awesome Markdown Files, он предоставляет такие функции, как структура содержимого, сортируемые таблицы и подсветка синтаксиса блока кода с номером строки.

Я также создал этот пост , любые комментарии приветствуются.

Оцените статью