m2O

2013/06/23 (日)

<script> を含む要素に innerHTML += するとどうなるか

|  <script> を含む要素に innerHTML += するとどうなるか - m2O を含むブックマーク

こんな HTML があるとします。いったいどんな動きになるでしょう?

<aside id="pc_ch_top_468x60_north" class="ads_nicovideo ads_header size_468x60">
    <script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!';</script>
</aside>

「a += b」は「a = a + b」の短縮表記なので

document.getElementById('pc_ch_top_468x60_north').innerHTML = " <script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!';</script> " + 'AAA!';

と同じ意味です。
要するに innerHTML に <script> を代入するとそれが実行されるかどうか、という問いになります。もし実行されるとしたらこの script だと無限再帰になって死んでしまいますからゆゆしき問題です。


というわけで実際に動かしてみました。

http://jsdo.it/miya2000/ndUU

身の回りのブラウザ(Opera(10.10, 12, Next15), Chrome27, Firefox21, ie10) ではどれも再実行はされず、「AAA!」が1つだけ表示される結果になりました。

これがどこかの仕様で決まっている動きなのかどうかわからないですが、意図的に script を実行させようとしたら上記のようなコードにはならないと思いますので、安全側に倒した挙動になっていると思います。つまり何も問題はありませんでした。



で、ここからが Opera クオリティ。
以下のようにコードを上に追加してみましょう。

<script>
document.addEventListener('DOMNodeInserted', function() {}, false);
</script>

<aside id="pc_ch_top_468x60_north" class="ads_nicovideo ads_header size_468x60">
    <script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!'</script>
</aside>

http://jsdo.it/miya2000/ofvz

なんと DOMNodeInserted イベントリスナを追加しただけで、script が再実行されて「AAA!」がいくつも出力されるようになってしまいました!
(Opera Next15 は大丈夫でした。)


そういうわけで DOMNodeInserted イベントを監視する User Javascript を使用していると、ニコニコチャンネルのトップページ広告がわらわらと増えていく現象が起こっていました。
原因がわかって対応もしたのでもう大丈夫なんですが、http://ads.nicovideo.jp/assets/js/ads-2.js の 234 行目あたりは修正した方がいいんじゃないかな、と思います。

--

というか普通はこうですかね。

<aside id="pc_ch_top_468x60_north" class="ads_nicovideo ads_header size_468x60"></aside>
<script>document.getElementById('pc_ch_top_468x60_north').innerHTML += 'AAA!';</script>

 

トラックバック - http://orera.g.hatena.ne.jp/miya2000/20130623

2008/02/06 (水)

Opera のポップアップブロックが setTimeout で回避できる?

|  Opera のポップアップブロックが setTimeout で回避できる? - m2O を含むブックマーク

あれ? そーだったかな?

id:seltsam より、setTimeoutでずらして回避というアイディアを頂きました。Thx!

Minibufferで複数のPinを開くとブロックされる件の対応 - os0x.blog

確認した。

まずそのまま2回開く

(function(){
  open('http://www.google.co.jp/');
  open('http://www.google.co.jp/');
})()

問題なく2つ目はポップアップブロックされる。

2つ目を setTimeout

(function(){
  open('http://www.google.co.jp/');
  setTimeout(function(){ open('http://www.google.co.jp/') }, 0);
})()

これも問題なく2つ目はブロック。

2つとも setTimeout

(function(){
  setTimeout(function(){ open('http://www.google.co.jp/') }, 0);
  setTimeout(function(){ open('http://www.google.co.jp/') }, 0);
})()

ひらけちゃったよオイ。いいのこれ?

--

おまけ

(function(){
  setTimeout(function(){ open('http://www.google.co.jp/') }, 0);
  open('http://www.google.co.jp/');
})()

2つひらけた。どういう実装なんだろ?

トラックバック - http://orera.g.hatena.ne.jp/miya2000/20080206

2007/12/07 (金)

どこでもマイリスト v0.0.2

|  どこでもマイリスト v0.0.2 - m2O を含むブックマーク

ニコニコ動画の user.js どこでもマイリスト を更新しました。
主にサムネイルへの対応です。
詳細は該当ページにて。

--

以下、使うだけなら関係ない話。

マイリストの一覧を取得して select 要素を作る部分

    function main() {
        getMylist(makeMylistControls);
    }

これが

    function main() {
        var d = Ajax.Deferred.get('/mylistgroup_edit');
        d.addCallback(parseMylist);
        d.addCallback(makeMylistControls);
    }

こうなりました。

あースッキリ!

トラックバック - http://orera.g.hatena.ne.jp/miya2000/20071207

2007/09/02 (日)

ユニコードエスケープ

|  ユニコードエスケープ - m2O を含むブックマーク

Operauser.js では日本語を直接扱えないのでユニコードエスケープする bookmarklet を書きました。

javascript:(function(a){if(a)alert(unescape(escape(a).replace(/%u/g,'\\u')))})(prompt())

正確にはASCII文字はエスケープしてないけど Operauser.js で使うのが目的なのでこれでよしとしました。

escape 関数は例えば「()」を「'%u0028%u0029'」とはしてくれず「%28%29」にしますね。なんだか変な感じです。

--

追記

クォートもエスケープする必要が出たので結局対応しました。

javascript:(function(a){if(a)alert(escape(a).replace(/%([0-9A-F]{2})/g,'\\u00$1').replace(/%u/g,'\\u'))})(prompt())
トラックバック - http://orera.g.hatena.ne.jp/miya2000/20070902

2007/06/19 (火)

text/XXXX で開かれたページを別の MIME タイプで開く

|  text/XXXX で開かれたページを別の MIME タイプで開く - m2O を含むブックマーク

先にコード

var xhr = new XMLHttpRequest();
xhr.open( 'GET', location.href, true );
xhr.onreadystatechange = function() {
    if ( xhr.readyState == 4 ) {
        location.href = 'data:video/x-ms-asf;charset=utf-8,'+encodeURI(xhr.responseText);
    }
};
xhr.send(null);

感想

ここまでの流れ

先日の「Opera から GyaO」に続いて「Yahoo! 動画Opera から見たい!」と思って user.jsコードを書いていて、ほぼ完成というところで既にあるのを見つけてしまいました*1

見てみると僕のコードが恥ずかしくて見せられないくらいシンプルに実現されてました。みんなコレを使えばいいと思うよ!

今回のエントリはその恥ずかしいコードの一部です。

*1orz...