メタブ表示

    @@ -1,5 +1,5 @@ /* - * @titleブクマカのメタブ表示 + * @title ブクマカのメタブ表示 * @description my bookmarklet * @include http://b.hatena.ne.jp/entry/* * @license MIT License @@ -9,104 +9,225 @@ /* * CONSTANTS */ - var DEBUG = true; - var HBBP_URL = "http://b.hatena.ne.jp/js/bookmark_blogparts.js"; + var DEBUG = true; + var HBBP_URL = "http://b.hatena.ne.jp/js/bookmark_blogparts.js"; + var HATEB_DOMAIN = "http://b.hatena.ne.jp"; + var API_DOMAIN = "//b.hatena.ne.jp"; + var ICON_DOMAIN = "http://cdn1.www.st-hatena.com/users/"; + var CSS = [ + '.metab-container {', + '}', + '.metab-container > .metab-count{', + ' font-size: 10px;', + ' font-weight: 900;', + ' color: #F00;', + ' background-color: #FCC;', + ' display: inline-block;', + ' text-decoration: none;', + ' line-height: 12px;', + ' padding: 2px;', + '}', + '.metab-container > ul{', + ' display: block;', + ' margin: 0px;', + ' padding: 0px;', + '}', + '.metab-container > ul > li{', + ' width: auto;', + ' margin: 0px;', + ' padding: 0px;', + ' display: block;', + ' list-style: none;', + '}', + '.metab-container > ul > li > a.username{', + ' display: inline-block;', + ' margin: 0px 11px;', + '}', + '.metab-container > ul > li > span.comment{', + ' font-size: 11px;', + '}', + ''].join("\n"); + ////////////////////////////// + var doc = document; + var win = window; + var loc = location; + - var p = function() { + var p = function p() { if ( !DEBUG ) return; console.log.apply(console, arguments); }; - var forEach = function(a,f){ + var forEach = function forEach(a,f){ if(!a) return; for (var i=0,l=a.length;i<l;i++){ if(f(a[i]) === false) break; } }; + var gensym = (function(){ + var rnd = function(){return Math.floor(Math.random() * (1<<30)).toString(16);}; + var cnt = 0; + var prefix = 'sym_' + Date.now().toString(16) + '_' + rnd() + '_'; + return function gensym(){ return prefix + (cnt++).toString(16); }; + })(); + + var receiver = function(cb){ + var name = gensym(); + var func = function(){ + delete win[name]; + cb.apply(this, arguments); + }; + win[name] = func; + return encodeURIComponent( name ); + }; + + ////////////////////////////// - var targets = {}; + var users = {}; - var insert = function(container, url){ - var h = HBBlogParts; - var sel = 'a[href="'+targets[url]+'"]'; - forEach( document.querySelectorAll('ul.bookmark-list'), function(li){ - var target = li.querySelector(sel); - if(!target) return; - var parent = target.parentNode; - parent.appendChild(container); - });}; - - var catchJsonMetab = function(entry){ - var h = HBBlogParts; - if ( !entry ){ - //p('No Bookmarks'); - }else{ - var container = new h.BookmarkContainer(entry); - if( h.isPermalinkPage() ) { - container.commentLimit = h.permalinkCommentLimit; - } else { - container.commentLimit = h.listPageCommentLimit; + + /*/ + hoge:( + {"count":2, + "bookmarks":[ + {"timestamp":"2016/06/24 18:41:59", + "comment":"","user":"aflat_1000dai4","tags":["meta bookmark"]}, + {"timestamp":"2014/11/27 23:31:08", + "comment":"","user":"kcolmun", + "tags":["\u30e1\u30bf\u30d6\u30c3\u30af\u30de\u30fc\u30af"]}], + "url":"http://b.hatena.ne.jp/guru_guru/", + "eid":234900219, + "title":"\u306f\u3066\u306a\u30d6\u30c3\u30af\u30de\u30fc\u30af - guru_guru \u306e\u30d6\u30c3\u30af\u30de\u30fc\u30af", + "screenshot":"http://screenshot.hatena.ne.jp/images/200x150/7/7/5/1/8/4cdd713947a7e5c74bf0b8244024e6ea7ae.jpg", + "entry_url":"http://b.hatena.ne.jp/entry/b.hatena.ne.jp/guru_guru/"} + ) + //*/ + + + var htmlifyComment = function(comment){ + var node = doc.createElement('span'); + node.className = 'comment'; + node.appendChild(doc.createTextNode(comment)); + return node; + }; + + var toHTML = function(entry, user){ + var slot = users[user]; + var node = slot.html || null; + if(!node){ + node = doc.createElement('div'); + if(entry){ + node.className = 'metab-container'; + var count = doc.createElement('a'); + count.className = 'metab-count'; + count.href = entry.url; + count.target = "_blank"; + count.appendChild(doc.createTextNode(String(entry.count) + " users")); + node.appendChild(count); + if((entry.bookmarks || []).length > 0){ + var ul = doc.createElement('ul'); + forEach(entry.bookmarks, function(bm){ + var li = doc.createElement('li'); + var a = doc.createElement('a'); + a.href = HATEB_DOMAIN + '/' + bm.user + '/'; + a.target = '_blank'; + a.title = bm.user; + var un = a.cloneNode(true); + a.className = 'profile-icon'; + un.className = 'username'; + var icon = doc.createElement('img'); + icon.src = + ICON_DOMAIN + '/' + bm.user.substring(0,2) + '/' + bm.user + + '/profile_l.gif'; + icon.alt = bm.user; + a.appendChild(icon); + li.appendChild(a); + un.appendChild(doc.createTextNode(bm.user)); + li.appendChild(un); + + + var tags = bm.tags || []; + if(tags.lengh > 0){ + var tagSpan = doc.createElement('span'); + tagSpan.className = 'tags'; + forEach(tags , function(tagName){ + var tagLink = doc.createElement('a'); + tagLink.className = 'user-tag'; + tagLink.href = HATEB_DOMAIN + '/' + bm.user + '/' + tagName; + tagLink.appendChild(doc.createTextNode(tagName)); + tagSpan.appendChild(tagLink);}); + li.appendChild(tagSpan);} + + li.appendChild(htmlifyComment(bm.comment)); + + var meta = doc.createElement('div'); + meta.className = 'user-comment-meta'; + var tspan = doc.createElement('span'); + tspan.className = 'timestamp'; + meta.appendChild(tspan); + tspan.appendChild(doc.createTextNode(bm.timestamp)); + li.appendChild(meta); + ul.appendChild(li); + }); + node.appendChild(ul); + } } - var url = entry.url; - insert(container.toHTML(h.Design),url); - h.setStyles(); - h.shownPermalinks[url] = 1; + slot.html = node; } - h.catchCount++; - if( h.catchCount >= h.Entries.length ) h.showEmptyEntries(); + var retval = node.cloneNode(true); + return retval; }; - var showBookmarkComment = function(uri){ - var h = HBBlogParts; - var apiEndPoint = h.API_DOMAIN + '/entry/jsonlite/?'; - var request = apiEndPoint + 'url=' + encodeURIComponent(uri) + - '&callback=HBBlogParts.CatchJsonMetab'; - var scriptTag = Ten.Element('script',{ src: request, type: 'text/javascript'}); - document.body.appendChild(scriptTag); + var received = function(user, entry){ + var slot = users[user]; + slot.entry = entry || false; + slot.cont.forEach(function(c){c(entry, user);}); }; - - - var showBlogPart = function(n){ - var h = HBBlogParts; - var uri = n.href; - if(targets[uri]) return; - targets[uri] = n.getAttribute('href'); - showBookmarkComment(uri); + var reserve = function(user, cont){ + p(user); + var slot = ( users[user] || (users[user] = {entry: null,cont:[],req: false} )); + if(slot.entry !== null){ + cont(slot.entry, user); + return; + } + slot.cont.push(cont || function(){}); + if(slot.req) return; + slot.req = true; + var uri = HATEB_DOMAIN + '/' + user + '/'; + var apiEndPoint = API_DOMAIN + '/entry/jsonlite/?'; + var request = apiEndPoint + 'url=' + encodeURIComponent(uri) + + '&callback=' + receiver(function(entry){ received(user, entry);}); + var scriptTag = doc.createElement('script'); + scriptTag.src = request; + scriptTag.type = 'text/javascript'; + doc.body.appendChild(scriptTag); }; var main = function(){ - var h = HBBlogParts; - h.debug = DEBUG; - h.CatchJsonMetab = catchJsonMetab; var entries = []; - forEach(document.querySelectorAll('a.profile-icon'), showBlogPart);}; + var style = doc.createElement('style'); + style.type = 'text/css'; + style.appendChild(doc.createTextNode(CSS)); + doc.querySelector('head').appendChild(style); + forEach(doc.querySelectorAll('a.profile-icon'), function(n){ + var user = n.href.match(/([^\/]+)\/$/)[1]; + reserve(user, function(entry, user){ + n.parentNode.appendChild(toHTML(entry, user));});});}; - - /* - * START - */ + //// if((function(pn){ if(pn.match(/^\/entry\/\d+\/comment\//)) return true; return false; - })(String(location.pathname))) return; - - - if( typeof HBBlogParts == 'undefined' ){ - var mainjs = document.createElement('script'); - mainjs.src = HBBP_URL; - document.querySelector('head').appendChild(mainjs);} - - (function(){ - if(typeof HBBlogParts == 'undefined'){ - setTimeout(arguments.callee,20);}else{main();}})(); + })(String(loc.pathname))) return; + main(); })();
  • /*
     * @title ブクマカのメタブ表示
     * @description my bookmarklet
     * @include http://b.hatena.ne.jp/entry/*
     * @license MIT License
     * @require 
     */
    (function(){
      /*
       * CONSTANTS
       */
      var DEBUG        = true;
      var HBBP_URL     = "http://b.hatena.ne.jp/js/bookmark_blogparts.js";
      var HATEB_DOMAIN = "http://b.hatena.ne.jp";
      var API_DOMAIN   = "//b.hatena.ne.jp";
      var ICON_DOMAIN  = "http://cdn1.www.st-hatena.com/users/";
      var CSS = [
        '.metab-container {',
        '}',
        '.metab-container > .metab-count{',
        '  font-size: 10px;',
        '  font-weight: 900;',
        '  color: #F00;',
        '  background-color: #FCC;',
        '  display: inline-block;',
        '  text-decoration: none;',
        '  line-height: 12px;',
        '  padding: 2px;',
        '}',
        '.metab-container > ul{',
        '  display: block;',
        '  margin: 0px;',
        '  padding: 0px;',
        '}',
        '.metab-container > ul > li{',
        '  width: auto;',
        '  margin: 0px;',
        '  padding: 0px;',
        '  display: block;',
        '  list-style: none;',
        '}',
        '.metab-container > ul > li >  a.username{',
        '  display: inline-block;',
        '  margin: 0px 11px;',
        '}',
        '.metab-container > ul > li > span.comment{',
        '  font-size: 11px;',
        '}',
        ''].join("\n");
    
    
      //////////////////////////////
      var doc = document;
      var win = window;
      var loc = location;
    
      
      var p = function p() {
        if ( !DEBUG ) return;
        console.log.apply(console, arguments);
      };
    
    
      var forEach = function forEach(a,f){
        if(!a) return;
        for (var i=0,l=a.length;i<l;i++){
          if(f(a[i]) === false) break;
        }
      };
    
      var gensym = (function(){
        var rnd = function(){return Math.floor(Math.random() * (1<<30)).toString(16);};
        var cnt = 0;
        var prefix = 'sym_' + Date.now().toString(16) + '_' + rnd() + '_';
        return function gensym(){ return prefix + (cnt++).toString(16); };
      })();
    
      var receiver = function(cb){
        var name = gensym();
        var func = function(){
          delete win[name];
          cb.apply(this, arguments);
        };
        win[name] = func;
        return encodeURIComponent( name );
      };
    
    
    
      //////////////////////////////
      var users = {};
    
    
        /*/
        hoge:(
          {"count":2,
           "bookmarks":[
             {"timestamp":"2016/06/24 18:41:59",
              "comment":"","user":"aflat_1000dai4","tags":["meta bookmark"]},
             {"timestamp":"2014/11/27 23:31:08",
              "comment":"","user":"kcolmun",
              "tags":["\u30e1\u30bf\u30d6\u30c3\u30af\u30de\u30fc\u30af"]}],
           "url":"http://b.hatena.ne.jp/guru_guru/",
           "eid":234900219,
           "title":"\u306f\u3066\u306a\u30d6\u30c3\u30af\u30de\u30fc\u30af - guru_guru \u306e\u30d6\u30c3\u30af\u30de\u30fc\u30af",
           "screenshot":"http://screenshot.hatena.ne.jp/images/200x150/7/7/5/1/8/4cdd713947a7e5c74bf0b8244024e6ea7ae.jpg",
           "entry_url":"http://b.hatena.ne.jp/entry/b.hatena.ne.jp/guru_guru/"}
        )
         //*/
    
    
      var htmlifyComment = function(comment){
        var node = doc.createElement('span');
        node.className = 'comment';
        node.appendChild(doc.createTextNode(comment));
        return node;
      };
    
      var toHTML = function(entry, user){
        var slot = users[user];
        var node = slot.html || null;
        if(!node){
          node = doc.createElement('div');
          if(entry){
            node.className = 'metab-container';
            var count = doc.createElement('a');
            count.className = 'metab-count';
            count.href = entry.url;
            count.target = "_blank";
            count.appendChild(doc.createTextNode(String(entry.count) + " users"));
            node.appendChild(count);
            if((entry.bookmarks || []).length > 0){
              var ul = doc.createElement('ul');
              forEach(entry.bookmarks, function(bm){
                var li = doc.createElement('li');
                var a  = doc.createElement('a');
                a.href      = HATEB_DOMAIN + '/' + bm.user + '/';
                a.target    = '_blank';
                a.title     = bm.user;
                var un = a.cloneNode(true);
                a.className = 'profile-icon';
                un.className = 'username';
                var icon = doc.createElement('img');
                icon.src =
                  ICON_DOMAIN + '/' + bm.user.substring(0,2) + '/' + bm.user +
                  '/profile_l.gif';
                icon.alt = bm.user;
                a.appendChild(icon);
                li.appendChild(a);
                un.appendChild(doc.createTextNode(bm.user));
                li.appendChild(un);
    
    
                var tags = bm.tags || [];
                if(tags.lengh > 0){
                  var tagSpan = doc.createElement('span');
                  tagSpan.className = 'tags';
                  forEach(tags , function(tagName){
                    var tagLink = doc.createElement('a');
                    tagLink.className = 'user-tag';
                    tagLink.href = HATEB_DOMAIN + '/' + bm.user + '/' + tagName;
                    tagLink.appendChild(doc.createTextNode(tagName));
                    tagSpan.appendChild(tagLink);});
                  li.appendChild(tagSpan);}
    
                li.appendChild(htmlifyComment(bm.comment));
    
                var meta = doc.createElement('div');
                meta.className = 'user-comment-meta';
                var tspan = doc.createElement('span');
                tspan.className = 'timestamp';
                meta.appendChild(tspan);
                tspan.appendChild(doc.createTextNode(bm.timestamp));
                li.appendChild(meta);
                ul.appendChild(li);
              });
              node.appendChild(ul);
            }
          }
          slot.html = node;
        }
        var retval = node.cloneNode(true);
        return retval;
      };
    
    
      var received = function(user, entry){
        var slot = users[user];
        slot.entry = entry || false;
        slot.cont.forEach(function(c){c(entry, user);});
      };
    
      var reserve = function(user, cont){
        p(user);
        var slot =  ( users[user] || (users[user] = {entry: null,cont:[],req: false} ));
        if(slot.entry !== null){
          cont(slot.entry, user);
          return;
        }
        slot.cont.push(cont || function(){});
        if(slot.req) return;
        slot.req = true;
        var uri = HATEB_DOMAIN + '/' + user + '/';
        var apiEndPoint = API_DOMAIN + '/entry/jsonlite/?';
        var request = apiEndPoint + 'url=' + encodeURIComponent(uri) +
              '&callback=' + receiver(function(entry){ received(user, entry);});
        var scriptTag  = doc.createElement('script');
        scriptTag.src  = request;
        scriptTag.type = 'text/javascript';
        doc.body.appendChild(scriptTag);
      };
    
      var main = function(){
        var entries = [];
        var style = doc.createElement('style');
        style.type = 'text/css';
        style.appendChild(doc.createTextNode(CSS));
        doc.querySelector('head').appendChild(style);
        forEach(doc.querySelectorAll('a.profile-icon'), function(n){
          var user = n.href.match(/([^\/]+)\/$/)[1];
          reserve(user, function(entry, user){
            n.parentNode.appendChild(toHTML(entry, user));});});};
    
      ////
      
      if((function(pn){
        if(pn.match(/^\/entry\/\d+\/comment\//)) return true;
        return false;
      })(String(loc.pathname))) return;
      main();
    
    
    })();
    
    // Local Variables:
    // mode: hatena-let
    // End:
    
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。

History

  1. 2016/08/15 20:22:44 - 2016-08-15
  2. 2016/08/02 21:43:13 - 2016-08-02
  3. 2016/07/11 19:41:45 - 2016-07-11
  4. 2016/07/11 06:44:39 - 2016-07-11
  5. 2016/07/11 03:34:28 - 2016-07-11
  6. 2016/07/11 03:12:04 - 2016-07-11
  7. 2016/07/11 02:59:16 - 2016-07-11
  8. 2016/07/03 09:28:27 - 2016-07-03
  9. 2016/07/02 06:31:25 - 2016-07-02
  10. 2016/07/01 10:22:11 - 2016-07-01
  11. 2016/06/28 10:16:34 - 2016-06-28
  12. 2016/06/27 09:43:45 - 2016-06-27
  13. 2016/06/27 09:41:26 - 2016-06-27
  14. 2016/06/25 17:14:17 - 2016-06-25
  15. 2016/06/18 13:39:29 - 2016-06-18
  16. 2016/06/18 10:40:52 - 2016-06-18
  17. 2016/06/17 06:47:34 - 2016-06-17