postMessageを使ってIframeの高さを内容の高さに合わせる

前のブログにあった物の改良版
ここのスクリプトではニコニコ大百科にあるニコニコ動画のIframeの高さが
内容の高さより低い場合、内容の高さに合わせるようにしています。


(FORCE_FIT_CONTENTをtrueにすれば元々の高さにかかわらずIframeの高さを
内容に合わせます)


@includeを増やせば大百科以外のページに貼られたニコニコ動画
Iframeの高さも調節できるはずです。


// ==UserScript==
// @name Nico Adjust Height Of Iframes To Fit Content
// @namespace http://d.hatena.ne.jp/kiyo_hoge/
// @description ニコニコ動画のIframeを内容の大きさに合わせて高さを調節します
// @author kiyo
// @version 0.1
// @run-at document-start
// @include http://dic.nicovideo.jp/*
// @include http://ext.nicovideo.jp/*
// ==/UserScript==

(function() {
const FORCE_FIT_CONTENT = false;
if (document.URL.indexOf('http://ext.nicovideo.jp/') == 0) {
var sended = false;
var sendHeight = function () {
if (self == parent) {
return;
}
var offsetHeight = (document.compatMode == "BackCompat") ?
document.body.offsetHeight : document.documentElement.offsetHeight;
parent.postMessage('height=' + offsetHeight + ';src=' + document.URL, '*');
};

window.addEventListener('load', function() {
location.href = 'javascript:(' + sendHeight.toString() + ')();';
sended = true;
}, false);

window.addEventListener('message', function(evt) {
if (sended && evt.data == 'parentLoaded') {
location.href = 'javascript:(' + sendHeight.toString() + ')();';
}
}, false);
}
else {
var doneSrc = {};
var receiveMessage = function(evt) {
if (evt.origin != 'http://ext.nicovideo.jp') {
return;
}

var o = {};
var data = evt.data.split(';');

var temp;
for (var i = 0, l = data.length; i < l; i++) {
temp = data[i].split('=');
o[temp.shift()] = temp.join("=");
}

var src = o.src;
var height = o.height;

if (doneSrc[src] || isNaN(height)) {
return;
}
doneSrc[src] = true;
var originIframes = document.evaluate('//iframe[@src="' + src +'" or @src="' + src.replace('http://ext.', 'http://www.') + '"]', document, null, 7, null);

for (var i = 0, l = originIframes.snapshotLength; i < l; i++) {
var originIframe = originIframes.snapshotItem(i);
var style = document.defaultView.getComputedStyle(originIframe, '');
if (FORCE_FIT_CONTENT || (originIframe.clientHeight - parseFloat(style.borderTopWidth) - parseFloat(style.borderBottomWidth)) < height) {
originIframe.style.height = height + 'px';
originIframe.style.verticalAlign = 'top';
}
}
};

var sendLoaded = function() {
var nicoIframes = document.evaluate('//iframe[starts-with(@src, "http://ext.nicovideo.jp/") or starts-with(@src, "http://www.nicovideo.jp/")]', document, null, 7, null);
for (var i = 0, l = nicoIframes.snapshotLength; i < l; i++) {
nicoIframes.snapshotItem(i).contentWindow.postMessage('parentLoaded', '*');
}
};

window.addEventListener('message', receiveMessage, false);
location.href = 'javascript:(' + sendLoaded.toString() + ')();';
}
})();

Iframeを埋め込んでいるページとIframeで表示されているページの
どちらが先にJavaScriptが実行されるか分からないので、
Iframeを埋め込んでいるページが読み込まれると確認のためそれぞれのIframeに
そのことを伝えるにしてあります。


Operaでは「user.js」として保存するより「js」として保存した方がいいかも。


一応Firefox3.6とGoogle Chrome 5.0、Opera10.6で確認を取っています。