とりあえず JapanTimes と NYTimes をクーリエ・ジャポンみたいに見るブックマークレット(超適当)


iPad 買いました。おもしろいです。土日は iPad を持って外出してましたが、電池切れになることはありませんでした。あとは Evernote をプレミアムアカウントにしてローカルにファイルを保存できるようにすれば、今週は寮に MacBook を持ってく必要がないかもしれない!
で、iPad で JapanTimes とかを読んでみたのですが、僕は英語が苦手なので、画面いっぱいにアルファベットが表示されると読む気が失せてしまうのです。そこで前に感動したクーリエ・ジャポンの UI みたいなのを実現するブックマークレットを書いてみました。ブックマークレットを読み込むと本文の最初のパラグラフをハイライトして、暗い部分をタッチすると次のパラグラフにスクロールします。
ただ、ものっそい適当です。ハイライトのスクロールが遅いし、いろいろずれるし。まぁこれからしばらく使ってみて、いい感じなら改良していくことにします。

(function(){
   const db = {
      "search.japantimes.co.jp":"#mainbody > p",
      "www.nytimes.com":"#article p"
   };

   const duration = 0.4;
   const paragraphs =
      document.querySelectorAll(db[window.location.hostname]);

   function createCover(pos){
      var cover = document.createElement("div");
      cover.className = "couriercover";
      cover.style.position = "absolute";
      cover.style.left = "0px";
      cover.style.width = "100%";
      cover.style.zIndex = 65535;
      cover.style.backgroundColor = "black";
      cover.style.opacity = "0.5";
      if (pos == "upper") {
         cover.style.WebkitTransitionProperty = "height";
         cover.style.WebkitTransitionDuration = ""+duration+"s";
         cover.style.top = "0px";
         cover.style.height = "0px";
      } else if (pos == "lower") {
         cover.style.WebkitTransitionProperty = "top";
         cover.style.WebkitTransitionDuration = ""+duration+"s";
         cover.style.top = ""+(window.pageYOffset+window.innerHeight)+"px";
         cover.style.height =
            ""+(document.body.scrollHeight-
                (window.pageYOffset+window.innerHeight))+"px";
      }
      document.body.appendChild(cover);
      return cover;
   }

   var upperCover = createCover("upper");
   var lowerCover = createCover("lower");

   function getRect(element){
      function loop(element){
         var top = element.offsetTop;
         var left = element.offsetLeft;
         if (element.offsetParent) {
            var rect = loop(element.offsetParent);
            return {top:rect.top+top, left:rect.left+left};
         }
         return {top:top, left:left};
      }
      var rect = loop(element);
      rect.top = rect.top;
      rect.left = rect.left;
      rect.width = element.offsetWidth;
      rect.height = element.offsetHeight;
      rect.bottom = rect.top+rect.height;
      rect.right = rect.left+rect.width;
      return rect;
   }

   function smartScrollTo(element){
      var rect = getRect(element);
      if (rect.bottom > window.pageYOffset+window.innerHeight ||
          rect.top < window.pageYOffset) {
         window.scrollTo(0, rect.top-10);
      }
   }
   function forcusTo(element){
      smartScrollTo(element);
      var rect = getRect(element);
      upperCover.style.top = ""+window.pageYOffset+"px";
      upperCover.style.height = ""+(rect.top-window.pageYOffset)+"px";
      lowerCover.style.top = ""+rect.bottom+"px";
      setTimeout(function(){
         lowerCover.style.height =
            ""+(window.innerHeight-(rect.bottom-window.pageYOffset))+"px";
      }, duration*1000);
   }

   var counter = 0;
   function next(){
      if(counter<paragraphs.length)
         forcusTo(paragraphs[counter++]);
   }
   function prev(){
      if(counter>0)
         forcusTo(paragraphs[--counter]);
   }

   upperCover.addEventListener("touch",prev,false);
   upperCover.addEventListener("click",prev,false);
   lowerCover.addEventListener("touch",next,false);
   lowerCover.addEventListener("click",next,false);

   next();
})()