/*
* @title メディア再生窓生成
* @description マルチメディア要素へのリンクのクリックイベントに<audio>や<video>なウィンドウをポップアップする機能をオーバーライドする
* @include http://*
* @license NYSL
*/
// 一つのウィンドウでaudioとvideoを同時再生するとウィンドウのサイズがえらいことになりますが、
// 非常にレアケースだと思われるので無視しています。「運用回避してください。」
(function(){
var checked = []; // 同じURLに複数回リクエストを送るのを防ぐためのリストを格納
var timeout = 30 * 1000; // タイムアウトになるまでの時間(単位:ms)
var allowList = ["audio", "video"];
if (!HTMLElement.prototype.addPopup) { // addPopupメソッドを要素に追加
Object.defineProperty(HTMLElement.prototype, "addPopup", {
value: function(url){
var self = this;
var xhr = new XMLHttpRequest(); // HEADリクエストを送る
xhr.open("HEAD", url, true);
xhr.onreadystatechange = function(){
if (xhr.readyState === 4) {
console.log(xhr.status + " : " + url);
if (xhr.status !== 200) return;
var header = xhr.getResponseHeader("Content-Type");
var type = header.split("/")[0];
if (allowList.some(function(v){ return v === type })) { // いずれかにヒットすれば true
console.log(header + " - OK");
addPopupItem(self, type);
}
}
};
xhr.send(null);
window.setTimeout(function(){ // 一定時間でタイムアウト
xhr.abort();
}, timeout);
}
});
}
else {
return false;
}
var elems = document.querySelectorAll("a[href], area[href]");
elems = Array.prototype.slice.call(elems); // リンカブル要素を全て抽出
for (var i in elems) {
var url = elems[i].href;
if (url.indexOf("http") === 0) {
url = url.split("#")[0]; // URLに # を含む場合は除去
if (checked.every(function(li){ return url !== li })) { // 全てとアンマッチなら true
checked.push(url);
elems[i].addPopup(url);
}
}
}
function addPopupItem(target, mediaType) { // ポップアップを生成
target.onclick = function(evt){
if (evt.ctrlKey && evt.altKey) {
return true; // Ctrl+Alt を押しながらクリックすれば普段のクリックと同じ効果
}
else {
openPopup();
evt.preventDefault();
}
};
function openPopup() {
var popup = window.open("", "media-popup", "titlebar=no,menubar=no,toolbar=no,location=no,status=no,scrollbars=no");
var doc = popup.document;
var rect;
var element;
var diff = {
width: popup.outerWidth - doc.documentElement.clientWidth,
height: popup.outerHeight - doc.documentElement.clientHeight
};
if (!rect) {
element = doc.createElement(mediaType);
element.setAttribute("controls", "controls");
doc.body.appendChild(element);
rect = element.getBoundingClientRect();
doc.body.removeChild(element);
}
doc.body.addEventListener("DOMSubtreeModified", function(){ // 要素数が変化したらウィンドウサイズを変える
var len = this.childNodes.length;
popup.resizeTo( rect.width + diff.width, rect.height * len + diff.height );
}, false);
var style = doc.createElement("style");
doc.querySelector("head").appendChild(style);
var s = style.sheet, i = 0;
[
"body {"
+ "margin: 0;"
+ "padding: 0;"
+ "}",
"audio {"
+ "display: block;"
+ "margin: auto;"
+ "}"
].forEach(function(value){
s.insertRule(value, i++);
});
element = doc.createElement(mediaType);
element.setAttribute("src", target.href);
element.setAttribute("autoplay", "autoplay");
element.setAttribute("controls", "controls");
element.addEventListener("ended", function(){ // 終端まで移動したら自らを削除する
this.parentElement.removeChild(this);
close();
}, false);
/*
末尾に挿入する
appendChildでないのはIEがDOMSubtreeModifiedに反応しない(らしい)ため
http://msdn.microsoft.com/en-us/library/gg558014(v=vs.85).aspx
*/
doc.body.insertBefore(element, null);
function close() { // ポップアップ内のメディアがゼロのとき、子ウィンドウを閉じる
doc.querySelectorAll( allowList.join(",") ).length === 0
? popup.close() : 0;
}
}
}
})();