2

ポーリングせずに(またはスクリプトの孤立した世界から抜け出して、Webページのjavascriptコンテキストで呼び出しを傍受する)ことなく、chromeユーザースクリプト(拡張子ではないhistory.pushState)からURLの変更を検出できますか?

私の問題、より詳細には:

Githubは、サイト内のページ間のサイト ナビゲーションにpjax [最小化された例history.pushState] を介して[ WHAT-WG 仕様] を使用するため、サイトを閲覧するときにページ全体をリロードする代わりに、サイト上の特定の URL を対象とするユーザー スクリプトその URL でサイトに入るか、ページを手動で強制的にリロードした場合にのみ起動します。

私は、DRY 用の小さなユーザー スクリプト ライブラリon.jsを作成しています。ユーザー スクリプトを作成し、呼び出しをインターセプトしてpushState、ホスト スクリプトが実行したい新しいページにいるときを確認し、それを呼び出すだけで、ユーザー スクリプトを処理します。関連する場合。

history.pushState呼び出されたときにイベントが発生した場合、これは比較的簡単ですがpopstate、最初のページが読み込まれるか、ユーザーが履歴を前後に移動する場合を除いて、イベントは発生しません。これは私の目的にはかなり役に立ちません。

pjax/github のみのソリューションに制限することも検討しました。新しいページが読み込まれると、github が$(document).trigger('pageUpdate')イベントを発生させますが、jQueryこれらは DOM イベント経由ではなく内部で実装されるため、ユーザー スクリプトが実行する隔離された世界からはそれらを聞くことができません。ページ自体に小さなリスナーを挿入して、そのjQueryインスタンスにこのイベントを報告させない限り、ページ自体をハイジャックすることもできますhistory.pushState

これを達成するための他のきちんとした方法を見ている人はいますか?

4

2 に答える 2

0

GreaseMonkey がサンドボックス ポリシーを変更する前は (Firefox は変更しましたが、GM は後方互換性を持たせていませんでした) unsafeWindow、要素/ウィンドウ イベントを取得するために使用できました。これが変更されたので、GreaseMonkey APIで使用すると unsafeWindow が機能しなくなりました。

ページにスクリプトを挿入するという提案された回答は、インライン スクリプトを許可しない非常に厳格なコンテンツ セキュリティ ポリシー (CSP) のため、Github では機能しません。

Content-Security-Policy:default-src *; script-src assets-cdn.github.com コレクター-cdn.github.com; [...]

@grant none私の解決策は、GreaseMonkey API を使用する場合と、GreaseMonkey API を使用する場合の 2 つの異なる状況に対して 2 つ@grantです。

test-grant-none.user.js

// ==UserScript==
// @name      test @grant none
// @namespace https://github.com/jerone/UserScripts
// @include   https://github.com/*
// @version   1
// @grant     none
// ==/UserScript==

unsafeWindow.$(document).on("pjax:end", function() {
    console.log('test @grant none 1');
});
unsafeWindow.$(window).on('popstate', function() {
    console.log('test @grant none 2');
}); 

テスト許可-GM.user.js

// ==UserScript==
// @name      test @grant GM_*
// @namespace https://github.com/jerone/UserScripts
// @include   https://github.com/*
// @version   1
// @grant     GM_setValue
// ==/UserScript==

unsafeWindow.$(document).on("pjax:end", exportFunction(function() {
    console.log('test @grant GM_* 1');
}, unsafeWindow));
unsafeWindow.$(window).on('popstate', exportFunction(function() {
    console.log('test @grant GM_* 2');
}, unsafeWindow)); 

上記のスクリプトはこちらにあります: https://gist.github.com/jerone/e38e8637887559870d84

ここで詳細を読むことができます: https://greasyfork.org/en/forum/discussion/3648/hook-into-jquery-existing-events

私を正しい方向に向けてくれた Athorcis に感謝します。

于 2015-04-01T11:34:49.223 に答える
0

For now, I am taking the not excellent but working latter approach, of injecting a script that intercepts history.pushState calls and fires an event of the same name on the document, once the call has finished (and, optionally, after the pjax pageUpdate event has fired too):

function inject(fn, args) {
  var script = document.createElement('script')
    , parent = document.documentElement;
  args = JSON.stringify(args || []).slice(1, -1);
  script.textContent = '('+ fn +')('+ args +');';
  parent.appendChild(script);
  parent.removeChild(script);
}

inject(function(pjax_event) {
  function reportBack() {
    var e = document.createEvent('Events');
    e.initEvent('history.pushState', !'bubbles', !'cancelable');
    document.dispatchEvent(e);
  }
  var pushState = history.pushState;
  history.pushState = function on_pushState() {
    if (pjax_event && window.$ && $.pjax)
      $(document).one(pjax_event, reportBack);
    else
      setTimeout(reportBack, 0);
    return pushState.apply(this, arguments);
  };
}, ['pageUpdated']);

document.addEventListener('history.pushState', function() {
  console.log('history.pushState', location.pathname);
  // user script code here
}, false);
于 2012-11-07T08:30:56.847 に答える