はてなブログカードの iframe 内を弄る(自サイトのみ)

はてなブログカードの iframe 内を弄る(自サイトのみ)

01外部リンクを別ウィンドウで開く方法

はてなブログでは、公式のエディタを使ってリンクを挿入しますと外部サイトであっても同じウィンドウ(タブ)で開いてしまいます。

HTML編集で target="_blank" を直書きすればいいのですが、面倒ですし、うっかり忘れたりすることも多いので、当サイトでは、javascript で target="_blank" を挿入するようにしています。興味のある方は下記記事をご覧ください。

02ブログカードはすべてのリンクが別ウィンドウで開く

で、この記事の本題はそのことではなく、ブログカードでリンクを挿入した場合には逆に自サイトも別ウィンドウで開いてしまうのをなんとかしようというものです。

ブログカードとはこれです。

www.imuza.com

HTMLソースを見ますとこうなっています。

<iframe
  src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fwww.imuza.com%2Fentry%2F2019%2F01%2F07%2F210817"
  title="はてなブログ簡単カスタマイズ imzModules バージョンアップ - IMUZA.com"
  class="embed-card embed-blogcard"
  scrolling="no" frameborder="0" style="display: block; width: 100%; height: 190px; max-width: 500px; margin: 10px 0px;"></iframe>
<cite class="hatena-citation">
  <a href="https://www.imuza.com/entry/2019/01/07/210817">www.imuza.com</a>
</cite>

iframe 内のリンクを見てみますと、

<a href="https://www.imuza.com/entry/2019/01/07/210817" target="_blank">はてなブログ簡単カスタマイズ imzModules バージョンアップ</a>

のように、target="_blank" が挿入されています。これ、当たり前で、何も指定しないと iframe内に表示されてしまいます。

で、この target要素の値を自サイトのブログカードだけ _parent に変更できないかということです。

03クロスドメインで iframe内を弄れない

iframe内のコンテンツを取得するには contentWindow.document プロパティがあります。ただ、これが使えるのはドメイン名が同じ自サイトに限ります。ドメインが違う場合は次のようなクロスドメインのエラーが出ます。

Uncaught DOMException: Blocked a frame with origin "https://www.imuza.com" from accessing a cross-origin frame.

え、自サイトなのに? と思うのですが、ブログカードのソースを見てみますと、src属性が https://hatenablog-parts.com になっていますのでクロスドメインになってしまいます。独自ドメインといえどもブログシステムのバーチャルドメイン(でいいのかな?)ですので当然です。

04自サイト名/embed でもブログカードはできる

いろいろ調べますと、クロスドメイン通信ができる window.postMessage というメソッドがあることがわかったのですが、これで可能かどうかは別にしても、外部サイト側(iframe内のページ)にもスクリプトが必要になるというとても面倒なことになりますので早々にあきらめ、さらに調べましたら、iframeの src属性が 自サイト名/embed/エントリー でもブログカードはできることがわかりました。

たとえば、ブログカードにしたい自サイトのページが https://www.imuza.com/entry/2019/01/07/210817 であれば、iframe の src属性にそのURLの entryembed に差し替えた値を指定すればクロスドメインにならずにブログカードをつくることができます。

手作業で行う場合は、見たまま編集に限りますが、ブログカードを挿入した後にHTML編集で src属性を変更しておけば、後は表示する際に javascriptで aタグの taget属性を変更することが可能になるはずです。

05iframe内の aタグを target=_parent に変更する javascript

<script>
window.addEventListener('load', function(){
    var contents = document.getElementById('main'); // メインコンテンツ内のiframeに限定するため
    var cards = contents.getElementsByTagName('iframe');
    Array.prototype.forEach.call(cards,function(card){
        var cFlag = card.classList.contains('embed-blogcard'); // ブログカードか?
        var reg = new RegExp('^http(s)?://' + location.hostname + '.+

このスクリプトをフッタにでも入れておけば、iframeの src属性が自サイトに変更されていればブログカードは同じウィンドウで開きます。イベントが発火するタイミングは iframe内のドキュメントが読み込まれていないと意味がありませんので、すべてのリソースが読み込まれた後に発火する loadにします。

iframeの src属性を自サイトに変更する javascript

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。

<script>
document.addEventListener('DOMContentLoaded', function(){
    var article = document.getElementsByTagName('article')[0];
    if(article !== undefined){
        var iframes = article.getElementsByTagName('iframe');
        var reg = new RegExp('http(s)?%3A%2F%2F' + location.hostname + '.+

iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。

<script>
document.addEventListener('DOMContentLoaded', function(){
    var article = document.getElementsByTagName('article')[0];
    if(article !== undefined){
        var iframes = article.getElementsByTagName('iframe');
        var reg = new RegExp('http(s)?%3A%2F%2F' + location.hostname + '.+

何だか面倒なことになりますね。他にいい方法はないものでしょうか?

); // 自サイトか? if(cFlag && reg.test(card.src)){ var body = card.contentWindow.document; var as = body.getElementsByTagName('a'); Array.prototype.forEach.call(as, function(a){ a.target = '_parent'; }); } }); }, false); </script>

このスクリプトをフッタにでも入れておけば、iframeの src属性が自サイトに変更されていればブログカードは同じウィンドウで開きます。イベントが発火するタイミングは iframe内のドキュメントが読み込まれていないと意味がありませんので、すべてのリソースが読み込まれた後に発火する loadにします。

iframeの src属性を自サイトに変更する javascript

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。


iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。


何だか面倒なことになりますね。他にいい方法はないものでしょうか?

); Array.prototype.forEach.call(iframes, function(iframe){ var embedUrl = reg.exec(iframe.src); if(embedUrl !== null) iframe.src = decodeURIComponent(embedUrl[0]).replace('entry', 'embed'); }); } }, false); </script>

iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。


何だか面倒なことになりますね。他にいい方法はないものでしょうか?

); // 自サイトか? if(cFlag && reg.test(card.src)){ var body = card.contentWindow.document; var as = body.getElementsByTagName('a'); Array.prototype.forEach.call(as, function(a){ a.target = '_parent'; }); } }); }, false); </script>

このスクリプトをフッタにでも入れておけば、iframeの src属性が自サイトに変更されていればブログカードは同じウィンドウで開きます。イベントが発火するタイミングは iframe内のドキュメントが読み込まれていないと意味がありませんので、すべてのリソースが読み込まれた後に発火する loadにします。

06iframeの src属性を自サイトに変更する javascript

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

07完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





何だか面倒なことになりますね。他にいい方法はないものでしょうか? ); Array.prototype.forEach.call(iframes, function(iframe){var embedUrl = reg.exec(iframe.src); if(embedUrl !== null) iframe.src = decodeURIComponent(embedUrl[0]).replace(‘entry’, ‘embed’); }); }}, false); window.addEventListener(‘load’, function(){var contents = document.getElementById(‘main’); // メインコンテンツ内のiframeに限定するためvar cards = contents.getElementsByTagName(‘iframe’); Array.prototype.forEach.call(cards,function(card){var cFlag = card.classList.contains(‘embed-blogcard’); // ブログカードか?var reg = newRegExp(‘^http(s)?://’ + location.hostname + ‘.+

何だか面倒なことになりますね。他にいい方法はないものでしょうか?

// 自サイトか? if { var document var ‘a’ Array function { ‘_parent’ } } } } false

このスクリプトをフッタにでも入れておけば、iframeの src属性が自サイトに変更されていればブログカードは同じウィンドウで開きます。イベントが発火するタイミングは iframe内のドキュメントが読み込まれていないと意味がありませんので、すべてのリソースが読み込まれた後に発火する loadにします。

08iframeの src属性を自サイトに変更する javascript

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

09完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





何だか面倒なことになりますね。他にいい方法はないものでしょうか? ); Array.prototype.forEach.call(iframes, function(iframe){var embedUrl = reg.exec(iframe.src); if(embedUrl !== null) iframe.src = decodeURIComponent(embedUrl[0]).replace(‘entry’, ‘embed’); }); }}, false); </script>

iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

10完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





何だか面倒なことになりますね。他にいい方法はないものでしょうか? ); // 自サイトか?if(cFlag && reg.test(card.src)){var body = card.contentWindow.document; var as = body.getElementsByTagName(‘a’); Array.prototype.forEach.call(as, function(a){ a.target = ‘_parent’; }); }}); }, false); </script>

このスクリプトをフッタにでも入れておけば、iframeの src属性が自サイトに変更されていればブログカードは同じウィンドウで開きます。イベントが発火するタイミングは iframe内のドキュメントが読み込まれていないと意味がありませんので、すべてのリソースが読み込まれた後に発火する loadにします。

11iframeの src属性を自サイトに変更する javascript

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

12完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





何だか面倒なことになりますね。他にいい方法はないものでしょうか? ); // 自サイトか?if(cFlag && reg.test(card.src)){var body = card.contentWindow.document; var as = body.getElementsByTagName(‘a’); Array.prototype.forEach.call(as, function(a){ a.target = ‘_parent’; }); }}); }, false); </script>

何だか面倒なことになりますね。他にいい方法はないものでしょうか? ); // 自サイトか?if(cFlag && reg.test(card.src)){var body = card.contentWindow.document; var as = body.getElementsByTagName(‘a’); Array.prototype.forEach.call(as, function(a){ a.target = ‘_parent’; }); }}); }, false); </script>

このスクリプトをフッタにでも入れておけば、iframeの src属性が自サイトに変更されていればブログカードは同じウィンドウで開きます。イベントが発火するタイミングは iframe内のドキュメントが読み込まれていないと意味がありませんので、すべてのリソースが読み込まれた後に発火する loadにします。

13iframeの src属性を自サイトに変更する javascript

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

14完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





何だか面倒なことになりますね。他にいい方法はないものでしょうか? ); Array.prototype.forEach.call(iframes, function(iframe){var embedUrl = reg.exec(iframe.src); if(embedUrl !== null) iframe.src = decodeURIComponent(embedUrl[0]).replace(‘entry’, ‘embed’); }); }}, false); </script>

iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

15完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





何だか面倒なことになりますね。他にいい方法はないものでしょうか? ); // 自サイトか?if(cFlag && reg.test(card.src)){var body = card.contentWindow.document; var as = body.getElementsByTagName(‘a’); Array.prototype.forEach.call(as, function(a){ a.target = ‘_parent’; }); }}); }, false); </script>

このスクリプトをフッタにでも入れておけば、iframeの src属性が自サイトに変更されていればブログカードは同じウィンドウで開きます。イベントが発火するタイミングは iframe内のドキュメントが読み込まれていないと意味がありませんので、すべてのリソースが読み込まれた後に発火する loadにします。

16iframeの src属性を自サイトに変更する javascript

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





iframeの src属性は iframe内が展開される前に変更しておかないとクロスドメインになってしまうようですので、イベントの発火は COMContentLoadedを使います。

ということで、ふたつ合わせて次のスクリプトをフッタにでも入れておけば、はてな公式のエディタで挿入したブログカードのうち、自サイトのものは同じウィンドウで開くはずです。

17完成

(2019/1/20)この項目の内容はうまくいかない場合があります。原因は調査中です。





何だか面倒なことになりますね。他にいい方法はないものでしょうか?