I[★]
@@ -1,6 +1,6 @@
/*
- * @title greed quote star feat. Proxy
- * @description 引用になってなくても引用スターできるようにします
+ * @title I[★]
+ * @description greedy quoted Hatena Star
* @include http://*
* @include https://*
* @contributor Hatena inc. https://s.hatena.ne.jp/images/add.gif
@@ -10,10 +10,11 @@
* @javascript_url
*/
+// TBD .com handling
+// TBC spec and behavior
(() => {
'use strict';
- // make star add button's color gold
function change_button_color(img) {
// change color with canvas
// https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Canvas_tutorial/Pixel_manipulation_with_canvas
@@ -21,7 +22,7 @@
document.body.querySelectorAll([
'img.hatena-star-add-button[src*="s.hatena.ne.jp"]',
]).forEach(button => {
- if (! canvas) {
+ if (!canvas) {
canvas = Object.assign(document.createElement('canvas'), {
width: img.width,
height: img.height,
@@ -46,8 +47,12 @@
});
}
- document.body.appendChild(Object.assign(document.createElement('img'), {
- // https://s.hatena.ne.jp/images/add.gif
+ // IDK necessary needs star icon at bottom is?
+ //document.body.appendChild(Object.assign(document.createElement('img'), {
+ Object.assign(document.createElement('img'), {
+ // TODO over CORS, canvas too
+ //src: 'https://s.hatena.com/images/add.gif',
+ //src: 'https://s.hatena.ne.jp/images/add.gif',
// XXX check term of use
src: 'data:image/gif;base64,R0lGODlhEAAQAIABALrJ9f///yH5BAEAAAEALAAAAAAQABAAAAIojI+pm+APYQCIMlfZtLOvSEkexhmchXkjaHYlGpLpqrZNqbngnvd+AQA7',
// https://stackoverflow.com/questions/17035106/context-getimagedata-operation-is-insecure
@@ -55,7 +60,8 @@
onload() {
change_button_color(this);
},
- }));
+ //}));
+ });
// http://q.hatena.ne.jp/1487227736#a1262105
function convert_numeric_reference_quote(url_string) {
@@ -84,17 +90,14 @@
return url_string;
}
- const Ten = window.Ten;
- if (!Ten) return;
-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
- Ten.JSONP = new Proxy(Ten.JSONP, {
+ window.Ten.JSONP = new Proxy(window.Ten.JSONP, {
construct: (target, args) => {
- const re_addstar = /^https?:\/\/s\.hatena\.ne\.jp\/star\.add\.json/;
- let url = args[0];
- if (re_addstar.test(url)) {
- url = convert_numeric_reference_quote(url);
- args[0] = url;
+ let url_string = args[0];
+
+ if (url_string.endsWith('//s.hatena.ne.jp/star.add.json')) {
+ url_string = convert_numeric_reference_quote(url_string);
+ args[0] = url_string;
}
return Reflect.construct(target, args);
/*
* @title I[★]
* @description greedy quoted Hatena Star
* @include http://*
* @include https://*
* @contributor Hatena inc. https://s.hatena.ne.jp/images/add.gif
* @contributor a-kuma3 http://let.hatelabo.jp/a-kuma3/let/hJmc_YyG8sE-
* @nitpicker noromanba
* @license MIT License https://opensource.org/licenses/MIT
* @javascript_url
*/
// TBD .com handling
// TBC spec and behavior
(() => {
'use strict';
function change_button_color(img) {
// change color with canvas
// https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Canvas_tutorial/Pixel_manipulation_with_canvas
let canvas;
document.body.querySelectorAll([
'img.hatena-star-add-button[src*="s.hatena.ne.jp"]',
]).forEach(button => {
if (!canvas) {
canvas = Object.assign(document.createElement('canvas'), {
width: img.width,
height: img.height,
});
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, img.width, img.height);
let data = imageData.data;
for (let i = 0 ; i < data.length ; i += 4) {
if (data[i] < 200) {
// gold : rgb(255,215,0)
data[i] = 255; // red
data[i + 1] = 215; // green
data[i + 2] = 0; // blue
// data[i + 3] = 255; // opacity
}
}
ctx.putImageData(imageData, 0, 0);
}
button.src = canvas.toDataURL();
button.title = button.title + ' (force quote)';
});
}
// IDK necessary needs star icon at bottom is?
//document.body.appendChild(Object.assign(document.createElement('img'), {
Object.assign(document.createElement('img'), {
// TODO over CORS, canvas too
//src: 'https://s.hatena.com/images/add.gif',
//src: 'https://s.hatena.ne.jp/images/add.gif',
// XXX check term of use
src: 'data:image/gif;base64,R0lGODlhEAAQAIABALrJ9f///yH5BAEAAAEALAAAAAAQABAAAAIojI+pm+APYQCIMlfZtLOvSEkexhmchXkjaHYlGpLpqrZNqbngnvd+AQA7',
// https://stackoverflow.com/questions/17035106/context-getimagedata-operation-is-insecure
crossOrigin: 'anonymous',
onload() {
change_button_color(this);
},
//}));
});
// http://q.hatena.ne.jp/1487227736#a1262105
function convert_numeric_reference_quote(url_string) {
// https://developer.mozilla.org/en-US/docs/Web/API/URL
// https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
const url = new URL(url_string);
const param = url.searchParams;
let quote = param.get('quote');
if (quote) {
// to numeric reference
quote = (s => {
let o = '', i = 0;
while (i < s.length) {
const code = s.codePointAt(i);
o += code < 128 ? String.fromCharCode(code) : `&#${code};`;
i += 1;
if (code > 0xffff) { // for surrogate pair
i += 1;
}
}
return o;
})(quote);
param.set('quote', quote);
url_string = url.href;
}
return url_string;
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
window.Ten.JSONP = new Proxy(window.Ten.JSONP, {
construct: (target, args) => {
let url_string = args[0];
if (url_string.endsWith('//s.hatena.ne.jp/star.add.json')) {
url_string = convert_numeric_reference_quote(url_string);
args[0] = url_string;
}
return Reflect.construct(target, args);
},
});
})();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。