Название довольно много:
Можно ли добавить Greasemonkey script на iframed-сайт?
Если да, то как?
Спасибо.
Название довольно много:
Можно ли добавить Greasemonkey script на iframed-сайт?
Если да, то как?
Спасибо.
В Greasemonkey (And Tampermonkey и большинстве пользовательских скриптов) скрипт автоматически запускает iframe, если он соответствует директивам @include, @exclude и/или @match.
И, популярный вопрос, как остановить Greasemonkey от запуска iframes.
Итак, если ваш сценарий имеет совпадение:
@match https://fiddle.jshell.net/*
Он будет запускаться на "выходных" страницах jsFiddle независимо от того, появляются они в фрейме или нет.
Тогда вы бы проверили свойство window.self
.
Например, предположим, что у вас была целевая страница, например:
<body>
<h1>I'm some webpage, either same-domain or not.</h1>
<iframe src="//domain_B.com/somePath/somePage.htm">
...
Тогда вы можете использовать скрипт как:
// ==UserScript==
// @name _Fires specially on domain_B.com iframes
// @match *://domain_B.com/somePath/*
// ==/UserScript==
if (window.top === window.self) {
//--- Script is on domain_B.com when/if it is the MAIN PAGE.
}
else {
//--- Script is on domain_B.com when/if it is IN AN IFRAME.
// DO YOUR STUFF HERE.
}
С выпуском Greasemonkey 4 обработка iframes сильно ограничена (и многие другие, кроме того, нарушены).
Он по- прежнему работает должным образом с Tampermonkey, Violentmonkey и практически со всеми другими движками usercript.
Настоятельно рекомендуется (в том числе самой Greasemonkey) не использовать Greasemonkey 4 или более позднюю версию.
Обратите внимание, что если вы создаете расширение chrome для вашего пользователя, вам также нужно добавить "all_frames": true
в ваш манифест или расширение не будет работать на iframes.
Пример:
"content_scripts": [
{
"matches": ["*://*/*"],
"all_frames": true,
"js":["dont.js"],
"run_at":"document_start"
}
]
Это решение для случаев, когда у iframe
нет места для запуска @include
или @match
.
Это работает с Greasemonkey 4.
Мы должны ждать загрузки каждого кадра, прежде чем мы сможем работать с ним. Я делаю это с помощью waitForKeyElements.js
, который ожидает элементы, соответствующие заданному селектору CSS, точно так же, как просматривая совпадения в document.querySelectorAll("selector")
, а затем применяет данную функцию к ответу:
// ==UserScript==
// @include https://blah.example.com/*
// @require https://git.io/waitForKeyElements.js
// ==/UserScript==
function main(where) {
// do stuff here with where instead of document
// e.g. use where.querySelector() in place of document.querySelector()
// and add stylesheets with where.head.appendChild(stylesheet)
}
main(document); // run it on the top level document (as normal)
waitForKeyElements("iframe, frame", function(elem) {
elem.removeAttribute("wfke_found"); // cheat wfke been_there, use our own
for (let f=0; f < frames.length; f++) {
if (!frames[f].document.body.getAttribute("been_there")) {
main(frames[f].document);
frames[f].document.body.setAttribute("been_there", 1);
}
}
});
Обратите внимание, что выбранный элемент является просто заполнителем, указывающим, что загружен iframe
. Мы удаляем трекер "бывал там" из waitForKeyElements
потому что кадр может быть снова загружен позже (мы не можем просто использовать этот iframe
потому что его содержимое загружено в другом месте).
Когда мы знаем, что фрейм загружен, мы перебираем каждый фрейм и ищем наш маркер, HTML-атрибут в body
фрейма, называемый been_there
(например, <body been_there="1">
). Если он отсутствует, мы можем запустить нашу функцию main()
для документа фрейма. Когда мы закончим, мы добавим атрибут been_there
чтобы мы больше не запускались.