display all bookmarks including no-comment @ Hatena::Bookmark Fork

    @@ -1,249 +1,44 @@ /* - * @title display all bookmarks including no-comment @ Hatena::Bookmark - * @description コメントがないブックマークも全て表示する - * @include http://b.hatena.ne.jp/entry/* + * @question:1521455576 + * @description question:1521455576 * @license MIT http://opensource.org/licenses/MIT * @javascript_url */ - /* - Changelog - - 記事につけられたスターを表示してみる - - ブックマークした時刻も表示 - - ツイートのクリック数を表示 - */ - /* - test case - http://b.hatena.ne.jp/entry/s/www.slideshare.net/enakai/it-51854916 - コメントなしブックマークが多い - http://b.hatena.ne.jp/entry/s/kazayo.com/gozaisho-sounan/ - コメントありブックマークが多い - http://b.hatena.ne.jp/entry/kazayo.com/gozaisho-sounan/ - コメントありの最初のブックマークよりも前に、コメントなしのブックマークがある - http://b.hatena.ne.jp/entry/ift.tt/2wV68BP - コメントありのブックマークがない - */ - (() => { - const d_ = document; - const entry_url = encodeURIComponent(d_.documentElement.dataset['entryUrl']); - let bookmark_container; - const bookmark_template = d_.getElementById("autoloader-bookmark-item").innerHTML.replace(/^\s+/, ""); - const _2d = n => (n < 10 ? "0" : "") + n; - const date_string = (d, sep) => [ - d.getFullYear(), - _2d(d.getMonth() + 1), - _2d(d.getDate()) - ].join(sep || ""); - const datetime_string = d => [ - d.getFullYear(), - _2d(d.getMonth() + 1), - _2d(d.getDate()), - ].join("/") + " " + [ - _2d(d.getHours()), - _2d(d.getMinutes()), - _2d(d.getSeconds()), - ].join(":"); + (function() { + const d_ = document; + Array.prototype.forEach.call(d_.body.querySelectorAll("script,style,noscript"), function(e) { + e.parentNode.removeChild(e); + }); - // init - (() => { - // inactivate auto loader - let readmore = d_.querySelector(".js-read-more-button"); - if (readmore) { - /* - https://cdn-ak.b.st-hatena.com/js/v4/bookmark.js - BookmarkAutoLoaderView#getLabelHeight + const text = d_.body.textContent.replace(/\s+/g, ""); + const count = text.length; + const title = d_.title; + const hx_list = d_.querySelectorAll("h1,h2,h3,h4,h5,h6"); - 要素を見えなくしちゃうと、getBoundingClientRect は、top = 0 を返すので、 - メソッドを乗っ取る - */ - readmore.getBoundingClientRect = () => { - return {top: 1000000}; - }; - } - - d_.head.appendChild(Object.assign(d_.createElement("style"), { - innerHTML: ' \ - .hatena-star-comment-button { \ - display: initial !important; \ - margin-right: 8px !important; \ - } \ - .js-bookmarks-sort-tab[data-sort="recent"] > img { \ - width: 12px; \ - margin: 0 0.5ex; \ - } \ - .entry-comment-readmore { \ - display: none; \ - } \ - .entry-info-meta { \ - display: initial; /* flex */ \ - } \ - .twitter-clicks { \ - color: gray; \ - margin-left: 1em; \ - } \ - ', - })); - - // add tab - let comment_tabs = d_.querySelector("ul.entry-comment-tab"); - let tab = comment_tabs.appendChild(Object.assign(d_.createElement("li"), { - className: "js-bookmarks-sort-tab", - innerHTML: "全てのブックマーク", - })); - tab.dataset["sort"] = "all"; - - // add panel - let sort_panel = d_.querySelector("div.js-bookmarks-sort-panels"); - bookmark_container = sort_panel.appendChild(Object.assign(d_.createElement("div"), { - className: "bookmarks-sort-panel js-bookmarks-sort-panel", - innerHTML: '<div class="js-bookmarks js-bookmarks-all"></div>', - })); - bookmark_container.dataset["sort"] = "all"; - bookmark_container = bookmark_container.firstChild; - - tab.click(); - - // entry url star - d_.querySelector(".js-entry-info").appendChild(Object.assign(d_.createElement("span"), { - id: "entry_star_count", - })); - })(); - - function append_bookmark(b, bookmark_container) { - /* - #enable_button ~ /enable_button -- not implement - #is_public ~ /is_public -- not implement - #should_nofollow ~ /should_nofollow -- not implement - anchor_path - comment_expanded - comment_page_path - created - profile_image_url - tags - user_name - user_page_path - */ - let created = new Date(b.created); - let date = datetime_string(created); - let date2 = date_string(created); - let legacyTagLinks = b.tags.map(tag => { - return '<li><a href="/' + b.user.name + '/' + encodeURIComponent(tag) + '/">' + tag + '</a></li>'; - }).join(""); - let keyword_map = { - anchor_path : '/' + b.user.name + '/' + date2 + '#bookmark-' + b.location_id, - comment_expanded : b.comment_expanded, - comment_page_path : "/entry/" + b.location_id + "/comment/" + b.user.name, - created : date, - profile_image_url : b.user.image.image_url, - tags : legacyTagLinks, - user_name : b.user.name, - user_page_path : "/" + b.user.name, - }; - let x = d_.createElement("div"); - x.innerHTML = bookmark_template.replace(/[{]{2,3}\s*([^}\s]+)\s*[}]{2,3}/g, (m, p) => { - return keyword_map[p] || ""; - }); - // remove comment permalink with no comment - if (b.comment == "") { - let comment_permalink = x.querySelector(".entry-comment-permalink"); - comment_permalink.parentNode.removeChild(comment_permalink); - } - - return bookmark_container.appendChild(x.firstChild); - } - - const xhr = new XMLHttpRequest(); - let bookmarks = []; - xhr.onload = (ev) => { - if (ev.target.status < 400) { - const resp = ev.target.response; - /* - https://cdn-ak.b.st-hatena.com/js/v4/bookmark.star.js - EntryStarView.prototype.observeBookmarkListChange - - はてなスターは MutationObserver が作ってくれるのだけれど、 - Hatena.Star.EntryLoader は、static な領域を使って処理をするので、 - load するたびにブックマークを追加すると、最後のブロックしか - スターが展開されない。 - */ - bookmarks = bookmarks.concat(resp.bookmarks); - if (resp.cursor) { - load_bookmark(resp.cursor); - } else { - let comment_tags_map = {}; - bookmarks.forEach(b => { - let e = append_bookmark(b, bookmark_container); - comment_tags_map[ b.user.name ] = e.querySelector(".entry-comment-tags"); - }); - - // hatena star - Hatena.Star.SiteConfig = { - entryNodes: { - "div.entry-info": { - uri: "h1.entry-info-title a", - title: "h1.entry-info-title a", - container: "#entry_star_count", - }, - "div.js-bookmarks-all div.js-bookmark-item": { - uri: "a.js-bookmark-anchor-path", - title: "span.js-bookmark-comment", - container: "span.js-add-star-container" - } - } - }; - new Hatena.Star.EntryLoader(); - - // Tweet clicks - function insert_clicks(n, e) { - let x = e.parentNode.insertBefore(Object.assign(d_.createElement("span"), { - innerHTML: n + " clicks", - className: "twitter-clicks", - }), e.nextSibling); - x.dataset["clicks"] = n; - return x; - } - const xhr2 = new XMLHttpRequest(); - const url = "http://b.hatena.ne.jp/api/shorturl.clicks"; - let clicks_list = []; - xhr2.onload = (ev) => { - if (ev.target.status < 400) { - let data = ev.target.response; - data.entries[0].clicks.forEach(e => { - if (e.count > 0) { - clicks_list.push(insert_clicks(e.count, comment_tags_map[ e.user ])); - } - }); - insert_clicks(clicks_list.reduce((sum, item) => { - return sum + parseInt(item.dataset["clicks"], 10); - }, 0 - ), d_.getElementById("entry_star_count")); - console.log(clicks_list.length + " clicks !!!"); - } - }; - xhr2.responseType = "json"; - xhr2.open("POST", url, true); - xhr2.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); - xhr2.send( - "entry=" + d_.documentElement.dataset['entryEid'] + "," + - bookmarks.map(b => b.user.name).join("|") - ); - - } - } - }; - xhr.responseType = "json"; - function load_bookmark(cursor) { - let url = [ - "http://b.hatena.ne.jp/api/entry/", - entry_url, - "/bookmarks?cursor=" + cursor, - "&limit=500&commented_only=0" - ].join(""); - xhr.open("GET", url, true); - xhr.send(null); - } - - load_bookmark(""); - + const panel = d_.body.appendChild(d_.createElement("textarea")); + panel.style.position = "fixed"; + panel.style.backgroundColor = "white"; + panel.style.border = "1px solid black"; + panel.style.padding = "1ex"; + panel.style.top = "0"; + panel.style.width = "80ex"; + panel.style.height = "20em"; + function indent(tag) { + let n = parseInt(tag.replace(/^H/, "")) - 1; + let pad = ""; + for (let i = 0 ; i < n ; ++i) { + pad += "\t"; + } + return pad; + } + panel.value = [ + "【文字数】", + count, + "\n【title】", + title, + "\n【hタグ】", + Array.prototype.map.call(hx_list, function(h) {return indent(h.tagName) + h.tagName + ":" + h.textContent;}).join("\n"), + ].join("\n"); })();
  • /*
     * @question:1521455576
     * @description question:1521455576
     * @license MIT http://opensource.org/licenses/MIT
     * @javascript_url
     */
    (function() {
    	const d_ = document;
    
    	Array.prototype.forEach.call(d_.body.querySelectorAll("script,style,noscript"), function(e) {
    		e.parentNode.removeChild(e);
    	});
    
    	const text = d_.body.textContent.replace(/\s+/g, "");
    	const count = text.length;
    	const title = d_.title;
    	const hx_list = d_.querySelectorAll("h1,h2,h3,h4,h5,h6");
    
    	const panel = d_.body.appendChild(d_.createElement("textarea"));
    	panel.style.position = "fixed";
    	panel.style.backgroundColor = "white";
    	panel.style.border = "1px solid black";
    	panel.style.padding = "1ex";
    	panel.style.top = "0";
    	panel.style.width = "80ex";
    	panel.style.height = "20em";
    	function indent(tag) {
    		let n = parseInt(tag.replace(/^H/, "")) - 1;
    		let pad = "";
    		for (let i = 0 ; i < n ; ++i) {
    			pad += "\t";
    		}
    		return pad;
    	}
    	panel.value = [
    		"【文字数】",
    		count,
    		"\n【title】",
    		title,
    		"\n【hタグ】",
    		Array.prototype.map.call(hx_list, function(h) {return indent(h.tagName) + h.tagName + ":" + h.textContent;}).join("\n"),
    	].join("\n");
    })();
    
    
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。