メディア再生窓生成
by
htsign
2013-04-28 [2013/04/28 18:17:21]
マルチメディア要素へのリンクのクリックイベントに<audio>や<video>なウィンドウをポップアップする機能をオーバーライドする
@@ -6,110 +6,115 @@
*/
-var checked = []; // 同じURLに複数回リクエストを送るのを防ぐためのリストを格納
-var timeout = 30 * 1000; // タイムアウトになるまでの時間(単位:ms)
+(function(){
+ var checked = []; // 同じURLに複数回リクエストを送るのを防ぐためのリストを格納
+ var timeout = 30 * 1000; // タイムアウトになるまでの時間(単位:ms)
+
+ var allowList = ["audio", "video"];
+
+ if (!HTMLAnchorElement.prototype.addPopup) { // addPopupメソッドをA要素に追加
+
+ Object.defineProperty(HTMLAnchorElement.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;
-if (!HTMLAnchorElement.prototype.addPopup) { // addPopupメソッドをA要素に追加
+ var header = xhr.getResponseHeader("Content-Type");
+ var type = header.split("/")[0];
- Object.defineProperty(HTMLAnchorElement.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];
- var allowList = ["audio", "video"];
-
- if (allowList.some(function(v){ return v === type })) { // いずれかにヒットすれば true
- console.log(header + " - OK");
- addPopupItem(self, type);
+ 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;
-}
-
-// 他のスタイルから影響を受けないよう Date.now() を追加
-var thisClass = "media-popup-" + Date.now();
-
-var elems = document.getElementsByTagName("a");
-elems = Array.prototype.slice.call(elems); // A要素を全て抽出
-
-var popupItem = (function(){ // ポップアップ用の殻を作成
- var div = document.createElement("div");
- div.className = thisClass;
- return div;
-})();
+ };
+ xhr.send(null);
-var popupStyle = function(){ // スタイル定義
- var style = document.createElement("style");
- document.getElementsByTagName("head")[0].appendChild(style);
- var s = style.sheet;
-
- // カーソルを置いたらポップアップするように
- s.insertRule("." + thisClass + "{"
- + "display: none !important;"
- + "text-indent: 0 !important;"
- + "z-index: 100 !important;"
- + "}", 0);
- s.insertRule("a:hover + ." + thisClass + ", ." + thisClass + ":hover {"
- + "display: block !important;"
- + "}", s.cssRules.length);
-
- s.insertRule("." + thisClass + "{"
- + "position: absolute !important;"
- + "}", s.cssRules.length);
-};
-popupStyle();
+ window.setTimeout(function(){ // 一定時間でタイムアウト
+ xhr.abort();
+ }, timeout);
+ }
+ });
+ }
+ else {
+ return false;
+ }
-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);
+ var elems = document.getElementsByTagName("a");
+ elems = Array.prototype.slice.call(elems); // A要素を全て抽出
+
+ for (var i in elems) {
+ var url = elems[i].href;
+
+ if (url.indexOf("http") === 0) {
+
+ url = url.indexOf("#") + 1 ? url.split("#")[0] : url; // URLに # を含む場合は除去
+
+ if (checked.every(function(li){ return url !== li })) { // 全てとアンマッチなら true
+ checked.push(url);
+ elems[i].addPopup(url);
+ }
}
}
-}
-function addPopupItem(target, mediaType) { // ポップアップを生成
- var popup = popupItem.cloneNode(), s = popup.style;
- s.left = target.offsetLeft + "px";
- s.top = target.offsetTop + target.offsetHeight + "px";
-
- var element; // 殻の中身を定義
-
- element = document.createElement(mediaType);
- element.setAttribute("src", target.href);
- element.setAttribute("preload", "metadata");
- element.setAttribute("controls", "controls");
-
- popup.appendChild(element);
- target.parentElement.insertBefore(popup, target.nextSibling); // 目標の直後に配置
-
- // 某ADVの公式サイトでなぜかレイアウトが崩れるので対症療法的な何か
- var objRect = popup.getBoundingClientRect();
- if (objRect.left === 0 && objRect.top === 0) {
- s.left = s.top = "auto";
+ function addPopupItem(target, mediaType) { // ポップアップを生成
+ target.onclick = function(evt){
+ if (evt.ctrlKey && evt.altKey) {
+ return true; // Ctrl+Alt を押しながらクリックすれば普段のクリックと同じ効果
+ }
+ else {
+ openPopup();
+ return false;
+ }
+ };
+
+ function openPopup() {
+ var popup = window.open("", "media-popup", "menubar=no,toolbar=no,location=no,status=no,scrollbars=yes");
+ var doc = popup.document;
+
+ 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++);
+ });
+
+ var element; // 殻の中身を定義
+
+ 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);
+
+ doc.body.appendChild(element);
+ var rect = element.getBoundingClientRect();
+ popup.resizeTo(rect.width + 80, rect.height + 200);
+
+ function close() { // 再生中のメディアがゼロのとき、子ウィンドウを閉じる
+ doc.querySelectorAll( allowList.join(",") ).length === 0
+ ? popup.close() : 0;
+ }
+ }
}
-}
+
+})();
/*
* @title メディア再生窓生成
* @description マルチメディア要素へのリンクにhoverすると<audio>や<video>なウィンドウをポップアップしてくれるようにする
* @include http://*
* @license NYSL
*/
(function(){
var checked = []; // 同じURLに複数回リクエストを送るのを防ぐためのリストを格納
var timeout = 30 * 1000; // タイムアウトになるまでの時間(単位:ms)
var allowList = ["audio", "video"];
if (!HTMLAnchorElement.prototype.addPopup) { // addPopupメソッドをA要素に追加
Object.defineProperty(HTMLAnchorElement.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.getElementsByTagName("a");
elems = Array.prototype.slice.call(elems); // A要素を全て抽出
for (var i in elems) {
var url = elems[i].href;
if (url.indexOf("http") === 0) {
url = url.indexOf("#") + 1 ? url.split("#")[0] : url; // 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();
return false;
}
};
function openPopup() {
var popup = window.open("", "media-popup", "menubar=no,toolbar=no,location=no,status=no,scrollbars=yes");
var doc = popup.document;
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++);
});
var element; // 殻の中身を定義
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);
doc.body.appendChild(element);
var rect = element.getBoundingClientRect();
popup.resizeTo(rect.width + 80, rect.height + 200);
function close() { // 再生中のメディアがゼロのとき、子ウィンドウを閉じる
doc.querySelectorAll( allowList.join(",") ).length === 0
? popup.close() : 0;
}
}
}
})();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。