display all bookmarks including no-comment @ Hatena::Bookmark
by
a-kuma3
2018-03-23 [2018/03/23 08:30:53]
コメントがないブックマークも全て表示する
@@ -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(":");
-
-
- // 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
-
- 要素を見えなくしちゃうと、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("");
+(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");
})();
/*
* @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 です。