メディア再生窓生成

    @@ -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 です。

History

  1. 2013/04/28 18:17:21 - 2013-04-28
  2. 2013/04/27 14:07:33 - 2013-04-27
  3. 2013/04/27 03:49:45 - 2013-04-27
  4. 2013/04/27 02:47:19 - 2013-04-27
  5. 2013/04/27 02:44:48 - 2013-04-27
  6. 2013/04/27 02:43:38 - 2013-04-27
  7. 2013/04/26 17:28:58 - 2013-04-26
  8. 2013/04/23 02:15:08 - 2013-04-23
  9. 2013/04/22 10:27:13 - 2013-04-22
  10. 2013/04/22 10:01:50 - 2013-04-22
  11. 2013/04/22 09:50:14 - 2013-04-22