С обновлением Greasemonkey 4 многие пользовательские скрипты, использующие jQuery, похоже, были сломаны. В предыдущих версиях следующий код работал бы на странице, использующей jQuery в теге <script>
:
// ==UserScript==
// <strong i="7">@name</strong> Variable access test
// <strong i="8">@namespace</strong> example.com
// ==/UserScript==
$.ready(document, function() {
console.log("Accessed jQuery successfully.")
});
Однако это больше не работает - вместо этого вы получаете классический $ is not defined
. Это говорит мне, что Greasemonkey может запустить пользовательский скрипт до загрузки тега <script>
. Однако это странно, поскольку сценарий все еще выполняется, когда document.readyState
равно interactive
!
Однако для уверенности я попытался получить доступ к jQuery после window.addEventListener('load', ...)
. И вот, следующее показывает другую ошибку:
// ==UserScript==
// <strong i="19">@name</strong> Variable access test
// <strong i="20">@namespace</strong> example.com
// ==/UserScript==
window.addEventListener('load', function() {
console.log("Before accessing jQuery")
$;
console.log("Accessed jQuery successfully!")
});
Он не запускается и не выдает ошибку - вместо этого он зависает при попытке доступа к $
. Сценарий просто доходит до этой строки и не дальше.
Попробуйте на любой странице, использующей jQuery, и вы получите тот же результат. Использование @require
не является решением этой проблемы - для некоторых приложений требуется доступ к тому же экземпляру jQuery, что и страница. Скорее всего, это повлияет и на другие сценарии, кроме jQuery.
Не совсем проблема Greasemonkey, скорее проблема скрипта содержимого Firefox.
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#Accessing_page_script_objects_from_content_scripts
Либо назначьте свой собственный window.wrappedJSObject
либо используйте unsafeWindow
в котором Greasemonkey уже назначил обернутый объект.
@Sxderp Я не знаю, что "не совсем проблема Greasemonkey" - и Tampermonkey, и Violentmonkey справляются с этим как раз без проблем. Не только это, но это критическое изменение, которое не упоминается ни в одном из сообщений блога.
Разве это не должно быть исправлено для правильной работы с существующими пользовательскими скриптами и обеспечения перекрестной совместимости с другими популярными менеджерами пользовательских скриптов?
Кроме того ... это действительно объясняет проблему? Почему сценарий зависает, а не просто не удается выполнить поиск?
Я не уверен насчет заморозки. Скопировал ваш код, и он у меня не зависает.
Изменить: извините, неправильно понял комментарий «замораживание». Я думал, вы имели в виду, что Greasemonkey больше не работает. Он «зависает» (прекращает выполнение) в этой строке, потому что Javascript попадает в ошибку использования до объявления. Совершенно уверен, что это считается «фатальным». То есть, не продолжает выполнение кода.
Если взглянуть на код Violentmonkey, похоже, что они внедряют скрипты, создавая элементы <script>
. Вместо использования метода tabs.executeScripts()
API.
Конечно, у этого есть свои недостатки.
Итак ... когда Firefox сталкивается с этой строкой, он просто молча прекращает выполнение? Без сообщения об ошибке? Какая невероятно странная вещь.
В любом случае, разве не целью является поддержание совместимости с существующими пользовательскими скриптами? В конце концов, это не нишевая функция - взаимодействие с собственным JavaScript страницы - очень распространенная вещь.
В любом случае, разве не целью является поддержание совместимости с существующими пользовательскими скриптами?
Конечно, это является. Мы не идеальны, и это бесплатный проект с открытым исходным кодом, созданный волонтерами, у которых так много свободного времени.
На данный момент у меня есть план, как это улучшить, но он ожидает, что Mozilla реализует функцию, которая сделает это безопасным. # 2549
@arantius Думаю, я мог оторваться немного конфронтированно ... Прошу прощения за это.
Я предполагаю, что это продуманное решение поставить безопасность выше удобства использования. Пока ситуация не разрешится, что мы можем сделать в качестве обходного пути со стороны автора сценария? В моем конкретном случае я пробовал как var $ = window.wrappedJSObject.$;
и var $= unsafeWindow.$;
в верхней части скрипта, но это дало мне еще одну ошибку при попытке использовать $(document).ready(...)
: Error: Permission denied to access property Symbol.toStringTag
.
Ошибка: отказано в доступе к свойству Symbol.toStringTag
Я не думаю, что это проблема window.wrappedJSObject.$
а скорее какой-то другой объект, который вы создали в пользовательском скрипте, либо как литерал объекта, либо с конструктором new
, не был должным образом импортирован в область, в которой вы пытаетесь получить к ней доступ (возможно, область окна страницы).
Ссылка выше предоставляет подробную информацию о cloneInto
которое вам понадобится.
Нет, я почти уверен, что проблема в window.wrappedJSObject.$
. Следующее не работает с той же ошибкой:
// ==UserScript==
// <strong i="7">@name</strong> Variable access test
// <strong i="8">@namespace</strong> example.com
// ==/UserScript==
var $ = window.wrappedJSObject.$;
$(document).ready(function() {});
Это, однако, молча терпит неудачу:
// ==UserScript==
// <strong i="12">@name</strong> Variable access test
// <strong i="13">@namespace</strong> example.com
// ==/UserScript==
var $ = window.wrappedJSObject.$;
$.ready(function() {});
Я пробовал использовать cloneInto
, но это не помогает. Как вы думаете, можете ли вы предоставить короткий пример пользовательского скрипта, который использует экземпляр страницы $
?
Ах, в этом случае у вас нет разрешения на доступ к функции. Затем вам нужно использовать exportFunction
.
// ==UserScript==
// <strong i="7">@name</strong> ExampleJQuery
// <strong i="8">@version</strong> 1
// <strong i="9">@include</strong> *
// <strong i="10">@grant</strong> none
// ==/UserScript==
var unsafeWindow = window.wrappedJSObject;
var $;
// For sanity just return if we don't have the object
if (typeof unsafeWindow.$ === 'undefined') {
console.log('No jQuery object, returning');
return;
} else {
$ = unsafeWindow.$;
}
// Create the function we want to export
function onReady() {
console.log("I'm ready!");
}
// Export it. Some details on this.
// Argument 1. The function to export
// Argument 2. The scope to export it to. In general this will be window,
// or some object in the scope. While it is valid to use
// "window", I prefer to use "unsafeWindow" if I'm exporting
// into that scope. I find it less confusing.
// Return This is a reference to exported function. In general you'll
// assign this to some property of the scope you're exporting
// into. However, it's not always neccessary. For example, if
// you're going to use it as a callback (like for .ready())
// then you don't need to assign it into the exported scope.
// But if you want it globally (or scopally) accessable then
// you need to assign it.
let exported_onReady = exportFunction(onReady, unsafeWindow);
// OR
// unsafeWindow.onReady = exportFunction(onReady, unsafeWindow);
$(document).ready(exported_onReady);
// OR
// $(document).ready(unsafeWindow.onReady);
Я пробовал этот подход сейчас (в разных конфигурациях) и продолжаю получать ошибки прав доступа, что бы я ни делал. На данный момент это действительно не стоит того.
Это звучит жестко, но я думаю, что мне просто нужно порекомендовать людям использовать Tampermonkey, пока это не решится. Скрипты контента в их текущем воплощении действительно не очень хорошо подходят для сценария использования пользовательского скрипта.
Согласитесь с @obskyr , просто порекомендуйте моим людям использовать tampermonkey
+1, перенесен в Tampermonkey (https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/), похоже, все мои скрипты там работают.
+1, перенесен в Tampermonkey (https://addons.mozilla.org/en-US/firefox/addon/tampermonkey/), похоже, все мои скрипты там работают.
Это может сработать в краткосрочной перспективе и отлично работает, чтобы скрипты продолжали работать, но в долгосрочной перспективе это может быть ложным решением полагаться на полную замену. Краткосрочный успех может быть недальновидным ... ;-)
Я использую ТМ как замену, но с ней есть некоторые проблемы, которых я не могу отрицать. Кроме того, с FF Quantum могут быть некоторые проблемы с безопасностью, поэтому он работает, но не следует полагаться только на одно решение ...
Что ж, мне все равно нужно поддерживать TM в моих скриптах, потому что не все используют Firefox. Итак, раньше я поддерживал GM и TM, теперь это просто TM. Пока проблем не заметил.
Самый полезный комментарий
Я пробовал этот подход сейчас (в разных конфигурациях) и продолжаю получать ошибки прав доступа, что бы я ни делал. На данный момент это действительно не стоит того.
Это звучит жестко, но я думаю, что мне просто нужно порекомендовать людям использовать Tampermonkey, пока это не решится. Скрипты контента в их текущем воплощении действительно не очень хорошо подходят для сценария использования пользовательского скрипта.