Diff
checker
文本
文本
图像
文档
Excel
文件夹
Legal
Enterprise
桌面版
定价
登录
下载 Diffchecker 桌面版
比较文本
查找两个文本文件之间的差异
工具
历史
显示
视图
拆分
统一
实时编辑器
隐藏空白更改
折叠未更改行
关闭换行
比对精度
智能
语法
无
更改外观
处理
忽略
文本转换
转到第一个差异
编辑输入
Diffchecker Desktop
运行Diffchecker最安全的方式。获取Diffchecker桌面应用:您的差异永远不会离开您的电脑!
获取桌面版
Untitled diff
创建于
10年前
差异永不过期
清除
导出
分享
解释
297 删除
行
总计
删除
字符
总计
删除
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
700 行
全部复制
319 添加
行
总计
添加
字符
总计
添加
要继续使用此功能,请升级到
Diff
checker
Pro
查看价格
741 行
全部复制
// ==UserScript==
// ==UserScript==
// @name EH Gallery Quick Favourite
// @name EH Gallery Quick Favourite
// @author FabulousCupcake
// @author FabulousCupcake
// @namespace http://fabulous.cupcake.jp.net/
// @namespace http://fabulous.cupcake.jp.net/
复制
已复制
复制
已复制
// @version v2.
1
.0
// @version v2.
2
.0
// @description Upgrades the gallery favourite button to allow quick favouriting of a gallery.
// @description Upgrades the gallery favourite button to allow quick favouriting of a gallery.
// @include /^https?://(ex|(?:g\.)?e-)hentai\.org/g/\d+?/\w{10}/?/
// @include /^https?://(ex|(?:g\.)?e-)hentai\.org/g/\d+?/\w{10}/?/
// @include /^https?://(ex|(?:g\.)?e-)hentai\.org\/gallerypopups\.php\?.+&act=addfav/
// @include /^https?://(ex|(?:g\.)?e-)hentai\.org\/gallerypopups\.php\?.+&act=addfav/
// @grant none
// @grant none
// ==/UserScript==
// ==/UserScript==
/* ====================================== *\
/* ====================================== *\
Hotkey Map
Hotkey Map
----
----
Shift+F : Initiate Favouriting Mode
Shift+F : Initiate Favouriting Mode
[0-9] : Favourite 0-9
[0-9] : Favourite 0-9
- : Remove Favourite
- : Remove Favourite
----
----
Pressing any other key during act-
Pressing any other key during act-
ive favouriting mode will exit the
ive favouriting mode will exit the
active favving mode.
active favving mode.
\* ====================================== */
\* ====================================== */
// Config
// Config
const config = {
const config = {
复制
已复制
复制
已复制
'
debug
'
: false,
"
debug
"
: false,
'timeout': 5000, // XHR Timelimit in milliseconds
"
editor_size
"
: 60, // Width of the favnotes input element in not-px unit
'
editor_size
'
: 60, // Width of the favnotes input element in not-px unit
"
hotkeys
"
: true, // Enable hotkeys
'
hotkeys
'
: true, // Enable hotkeys
"
cheatsheet
"
: true // Show cheatsheet after pressing Shift+F?
'
cheatsheet
'
: true // Show cheatsheet after pressing Shift+F?
};
};
// Colors
// Colors
var geh = {
var geh = {
复制
已复制
复制
已复制
'
border
'
:
'
#5C0D12
'
,
"
border
"
:
"
#5C0D12
"
,
'bg'
:
'
#E3E0D1
'
,
"bg"
:
"
#E3E0D1
"
,
'
bg_light
'
:
'
#F8F6EE
'
,
"
bg_light
"
:
"
#F8F6EE
"
,
};
};
var exh = {
var exh = {
复制
已复制
复制
已复制
'
border
'
:
'
#000000
'
,
"
border
"
:
"
#000000
"
,
'bg'
:
'
#4F535B
'
,
"bg"
:
"
#4F535B
"
,
'
bg_light
'
:
'
#5F636B
'
,
"
bg_light
"
:
"
#5F636B
"
,
};
};
var color;
var color;
var hotkeyInit = false;
var hotkeyInit = false;
// Are we on fjords?
// Are we on fjords?
color = (location.host.substr(0,2) == "ex" ) ?
color = (location.host.substr(0,2) == "ex" ) ?
color = exh :
color = exh :
color = geh;
color = geh;
// Stylesheet
// Stylesheet
var stylesheet =`
var stylesheet =`
#gdf {
#gdf {
margin: 6px 0 !important;
margin: 6px 0 !important;
padding: 10px 5px !important;
padding: 10px 5px !important;
width: 160px !important;
width: 160px !important;
height: 18px;
height: 18px;
position: relative;
position: relative;
border: 1px dashed ${color.border};
border: 1px dashed ${color.border};
left: -2px !important;
left: -2px !important;
}
}
#gdf > div:nth-child(1),
#gdf > div:nth-child(1),
#gdf > div:nth-child(2),
#gdf > div:nth-child(2),
#gdf > div:nth-child(3) {
#gdf > div:nth-child(3) {
display: inline !important;
display: inline !important;
float: none !important;
float: none !important;
}
}
#gdf > div:nth-child(2) > a {
#gdf > div:nth-child(2) > a {
position: relative;
position: relative;
top: -1px;
top: -1px;
line-height: 21px;
line-height: 21px;
}
}
#gdf > #fav {
#gdf > #fav {
padding-left: 5px;
padding-left: 5px;
}
}
#gdf > #fav > * {
#gdf > #fav > * {
float: none !important;
float: none !important;
display: inline-block !important;
display: inline-block !important;
margin: 0 !important;
margin: 0 !important;
position: relative;
position: relative;
top: 2px;
top: 2px;
}
}
#gdf div.i {
#gdf div.i {
display: inline-block;
display: inline-block;
margin: 0 !important;
margin: 0 !important;
}
}
#gdf a:hover {
#gdf a:hover {
color: inherit !important;
color: inherit !important;
}
}
.qf-top, .qf-bot {
.qf-top, .qf-bot {
background: ${color.bg_light} !important;
background: ${color.bg_light} !important;
width: inherit;
width: inherit;
padding: 0 5px;
padding: 0 5px;
position: absolute;
position: absolute;
left: -1px;
left: -1px;
visibility: hidden;
visibility: hidden;
border: 1px solid ${color.border};
border: 1px solid ${color.border};
}
}
已保存差异
原始文本
打开文件
// ==UserScript== // @name EH Gallery Quick Favourite // @author FabulousCupcake // @namespace http://fabulous.cupcake.jp.net/ // @version v2.1.0 // @description Upgrades the gallery favourite button to allow quick favouriting of a gallery. // @include /^https?://(ex|(?:g\.)?e-)hentai\.org/g/\d+?/\w{10}/?/ // @include /^https?://(ex|(?:g\.)?e-)hentai\.org\/gallerypopups\.php\?.+&act=addfav/ // @grant none // ==/UserScript== /* ====================================== *\ Hotkey Map ---- Shift+F : Initiate Favouriting Mode [0-9] : Favourite 0-9 - : Remove Favourite ---- Pressing any other key during act- ive favouriting mode will exit the active favving mode. \* ====================================== */ // Config const config = { 'debug': false, 'timeout': 5000, // XHR Timelimit in milliseconds 'editor_size': 60, // Width of the favnotes input element in not-px unit 'hotkeys': true, // Enable hotkeys 'cheatsheet': true // Show cheatsheet after pressing Shift+F? }; // Colors var geh = { 'border' : '#5C0D12', 'bg' : '#E3E0D1', 'bg_light' : '#F8F6EE', }; var exh = { 'border' : '#000000', 'bg' : '#4F535B', 'bg_light' : '#5F636B', }; var color; var hotkeyInit = false; // Are we on fjords? color = (location.host.substr(0,2) == "ex" ) ? color = exh : color = geh; // Stylesheet var stylesheet =` #gdf { margin: 6px 0 !important; padding: 10px 5px !important; width: 160px !important; height: 18px; position: relative; border: 1px dashed ${color.border}; left: -2px !important; } #gdf > div:nth-child(1), #gdf > div:nth-child(2), #gdf > div:nth-child(3) { display: inline !important; float: none !important; } #gdf > div:nth-child(2) > a { position: relative; top: -1px; line-height: 21px; } #gdf > #fav { padding-left: 5px; } #gdf > #fav > * { float: none !important; display: inline-block !important; margin: 0 !important; position: relative; top: 2px; } #gdf div.i { display: inline-block; margin: 0 !important; } #gdf a:hover { color: inherit !important; } .qf-top, .qf-bot { background: ${color.bg_light} !important; width: inherit; padding: 0 5px; position: absolute; left: -1px; visibility: hidden; border: 1px solid ${color.border}; } .qf-top { border-bottom: none; padding-top: 5px; bottom: 33px; } .qf-bot { border-top: none; padding-bottom: 5px; top: 33px; } #gdf .fav { box-sizing: border-box; cursor: pointer; padding: 5px; text-align: left; width: 100%; } #gdf .fav:hover { background: ${color.bg}; } #gdf:hover, #gdf.hover { border: 1px solid ${color.border}; } #gdf:hover > .qf-top, #gdf:hover > .qf-bot, #gdf.hover > .qf-top, #gdf.hover > .qf-bot { visibility: visible; } #gdf > .favnote { float: right !important; cursor: pointer; width: 16px; height: 16px; margin-right: 5px; position: relative; top: 1px; z-index: 20; opacity: 0.5; } #gdf > .favnote:hover { opacity: 1; } #gdf > .favnote:after { opacity: 0; } #gdf > .favnote:hover:after { display: block; padding: 0 5px; height: 20px; box-shadow: 0 1px 4px rgba(0,0,0,0.4); background: #f4f4f4; color: #333; font-weight: 400; font-size: 11px; line-height: 20px; position: absolute; top: -20px; left: 0px; transition: opacity 300ms cubic-bezier(1, -1, 1, -1); opacity: 1 } /* ========================================= *\ * Fugue Icons v3.5.6 by Yusuke Kamiyamane * * http://p.yusukekamiyamane.com/ * \* ========================================= */ #gdf > .favnote { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABQ0lEQVR4AcWONZoVURBGTxXusgrcIcMhw3dCjC/hxewB9wR3SXAYJGKS5zLW91bBK9wd/u6+2ud8P/89AnDjsOwBZvBjKS1a7xd4k+EAZsyav2zvFkst3A08Y1aQUz85D2C5AKC39ymdyhG9dlBkyUY/D6BvBIINYkUtvlw0sNTG8iCpSAwNFQwMDMS3eO2pLWZsvbJfln3YQEARkTdOi3nYsOG8TUpDNJtNzpzYDizZXHlxbQqwMv7IGRVRVBUz+6pk+vSFmGVGjx7N3XStCfCRQES+J4kmb5l3gpRRQhDQdyX6ah3Mxw0Euh/fkYRg1OcNBMWRcHxPosPHfNIgoUgXFtz5rkR1RDDvBH39PhKdiIwAcccxcCPWMVvA7hk3Q3RkMG8FU2/d4Vm7tHk0P5FHz3nWZQUYA0wI2c8lAS1+Ny8BF2m6Eor51N8AAAAASUVORK5CYII='); } #gdf > .favnote.plus { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABl0lEQVR4AcWOA4xeQRRGz0xtM6gd1DbCmjFquw3qWGVUx6lt27Ztt+vdN3OnndWPddTv4frk479LAVzfp5YATcmfVrbu585HAK7uUTtadF03WEwszgk4i0iANYlYm4TYAIBPn14S/2P/TmBF2wHuHIAGEEEhyUjwy3/Y4A9i4hCbjAkMKSkBSUlJ+K9Nn6ODRZhxeZfqClA4E4BGKYWPIPhYqFBhMmRMCjExMZw+PB9oO+jHx6sVgB6FAaxFK6XRWiMiOUKaNGmFiKV48eI8MFdjACIASqk8Id5Jxk0mwPgiFaAByROi/+X+BkCT6UDhvzAnEbWPM15fpveTw8x6cx0bDvA0hQZyh9z6/Y3WHftx8/fXKAcGTbqD7CBT7p+m06VtYBx/7B+UgbGubHvWV1yjADav5MyIUbu6IjHgHA7BOfG5j7Q7soqy3RsRrVM7T95QQMW5Y1jWsDZNyEEbi5So81oVKglQcUSLUj+33IpPcSR9f+n2A5QAqgI18/wWl7pT81Uz52P6TQkKpClF1zChyHUfSddf7UXJLEn3VbsAAAAASUVORK5CYII='); } #gdf > .favnote.arrow { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABnUlEQVR4Ac2QA6weURCFt7bduHZc27YV1bZt+9m2bdu2bRvn7Tz8ZthJvsXdPd+ducz/UeF2/V6zmMnIaiFBqE0/i7YqdbSU/URz6Xc0l3xBY9F71OU9Q3X2PVRm3ASR4L8H9C/LGj5BsFU/y7YKBTQVvkBjwTM05D9Ffd5j1GTfR3naLRQnXUFhwkVEuG8BGt1A/7Os5QgCLfpZtVUoobnopUSJl+UyDub/+nlxBH6m/WzaK1XQWvKaJFI7oXEowxF4G/Wz66hSQ1vpG5kkJKAMR+Cu38+ho1oD7WXvZJLQwVKGI3DR6efUWaOJjvL3UiUfnF1hF2YAynAEDpr9XFCjzQo+SJWc0Q/DWYMIvFE9HccR2Kr2c0OtDjorPgpJXlrY4JiqD4GjhIo3lAqAjV9saxa/jz7NUBn/ZnxQbwWSUCfd41Srgw527y83/MkDriQAZ2K43E0GZj72C6f8+AfnGW3190yIKHbcu1O65IZSPS/LA4B51zTKx+14dpEEw1gms0yXhVEn9WKIkQf+nO/NyleDD6irsJzue+8CGCvzmWahQigAAAAASUVORK5CYII='); } #gdf > .favnote.pencil { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABwElEQVR4Ac2QA4yYMQCF23nRfEMwe4sz27Zt297Ztm3btm3btt/+XnJmvJfU/b6C/B+JdKB8XLGYYNlFhibcjlp11GiirUIGreVSaC0TR3OJEBoKfqE29xOqs96ClaTA02B7ubJ7kCDUhlp3VCmhpfgPmot+oanwJxoLvqMu9zMqM96hNOUFipOeIsrzMNDsAbafK3v6BMFW1KajSgWtJX/HlPhYb+0rlorUp08QYE7tOqvV0F7GxyTj3oQ9hzF9Al8T6tBVo4GOcv4JSUqtriJlAy0NpnQfYfE0pE5dtVrorBAcV5IS+gqu4hcBXl7YUepHWNz0qEt3nTa6KoXGlBTF34KF3kO0tLTg64nZOTqEHCEsTtrUDXW6nEB4VElJ4h0EWq/m+t8hLXwZCrzTgvv+wF6deqBeD91VIiNKypLvI8hmDYNhpboM6eEvwZg+gakc8UOjDZiE3aTnObWaYB9bkf4OwbabGQwb9TXIinyD9kplMKaXn/vlMdHVFCJhQ4u2IImzUKC1DFb+S+tVeElq7xpjGMsVMpMrPFxZMrQIPKRSaEyD7Hca9PAiuTBknaeHHSd4dpZafL1Ld4+24R9mFfDtXW/67AAAAABJRU5ErkJggg=='); } #gdf > .favnote.exclamation { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB5ElEQVR4AcWQA4yfMQBHXzvbtm3b4RzNXow5mIPZWzTbtm3btre/1a/dXXN2uF9St6+v5b9HANw8IKYDNclYFjfuZi4mAlzfJ3Y1aLuit1YejNFgHLSO4KgAjhNEOxEAvnx5je/Xwd3AoqY9zAUACaA1Ah1CR/7Y4kRcaOVFOyFURBEORwgGg7Y06XK8t9aMvrpHtAXIHAdAIoSIYWrbZspkl22UCuN2uzl7dBLQtNevz9cLAB3sDsdBCiGRUqK1ThVSo0YjtHbInj07j9R1N9idcQBrIKVto0pcayEB33P+fD9J0PuC2DNxT1DRA3vA3pzUxPaDvs+UrT2eD48W233RZ5IYCGxJwcTneUuOfLXIlj0/uQrUIhT4FmcgYw2E7aYEAdfvF+QtXJ++Q7aTt2AtXH9eRgMyEWegkMQYJIV4XO/IlLUIRrnYsWMHfs9nNNkRgkJxf+APmKzIvIgsIIzBoMFoRFT5EfVxeYpW4fOf6xw6OJ4fwRtkypEVbSgxsJe9koITRrKganlqkCTZsoncJUsXKFupQf3cjnJRqdYtXj1qBAhe3Xv6bdUm32AB5ADyWJskWTlTLGzVrmKngkWyFsIYchfqhffXHgB+//T+vH/r0yFBGlk/l2Va05BUIiW3/wHmcuCUyEztWwAAAABJRU5ErkJggg=='); } #gdf > .favnote:after { width: 70px; content: "See your note"; } #gdf > .favnote.plus:after { width: 55px; content: "Add a note"; } #gdf > .favnote.arrow:after { width: 70px; content: "Save the note"; } #gdf > .favnote.pencil:after { width: 70px; content: "Edit your note"; } #gdf > .favnote.exclamation:after { width: 300px; height: 60px !important; white-space: normal; content: "Note failed to load. Click to retry. WARNING: Changing favourite category while the note is not loaded will remove existing notes!"; } #gdf > .favnote + .editor { position: absolute; height: 18px; background: ${color.bg_light} !important; padding: 10px; top: -1px; left: 132px; z-index: 10; border: 1px solid ${color.border}; visibility: hidden; } #gdf > .favnote + .editor > input { margin: 0 0 0 30px; height: 12px; } #gdf > .favnote + .editor > input.notinput { border-color: transparent; background: none !important; color: inherit !important; cursor: default !important; outline: none !important; color: transparent !important; text-shadow: 0 0 0 ${color.border}; } #gdf > .favnote + .editor.show { visibility: visible; } #gdf.hover .fav { position: relative; } #gdf .hotkey-hint { position: absolute; top: 4px; right: 0; box-sizing: border-box; padding: 0 1px 0 2px; border: 1px solid #888; border-radius: 2px; background: #eee; color: #666 !important; font-family: monospace; font-size: 13px; box-shadow: -3px 0 2px 2px ${color.bg_light}; visibility: hidden; } #gdf.hover .fav:hover .hotkey-hint { box-shadow: -3px 0 2px 2px ${color.bg}; } #gdf.hover .hotkey-hint { visibility: visible; } `; // Debug msg function dlog(msg) { if ( config.debug ) { console.log(`"EHGQF: ${msg}`); } } // Detect if page is favourite adding popup function isFavouritePopupPage() { var x = location.search.match("addfav"); var y = location.pathname.match("gallerypopups.php"); if ( x && y ) return true; return false; } // Get the actual/current favourite category of the current gallery function getCurrentFavID() { var curFavEl = document.querySelector("div[style*='g/fav.png);']"); var curFavID; if ( curFavEl ) { curFavID = (curFavEl.attributes.style.value.match(/background-position:0px -(\d+)px/)[1] - 2 ) / 19; } else { curFavID = 10; // curFavEl does not exist if gallery is not yet marked as favourite of any favs } dlog(curFavID); return curFavID; } // Get Favourite Notes remotely from the popup function fetchFavouriteNotes(cb) { dlog("Beginning to check favnotes"); // Send XHR to Favourite Page var galID = location.pathname.match(/^\/\w\/(\d+)\//)[1]; var token = location.pathname.match(/\/(\w+)\/$/)[1]; var prot = location.protocol; var host = location.host; var url = `${prot}//${host}/gallerypopups.php?gid=${galID}&t=${token}&act=addfav`; var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.timeout = config.timeout; xhr.responseType = "document"; xhr.send(); // And grab the favnotes xhr.onload = function() { if ( xhr.status == 200 ) { // grab it! var data = xhr.response; var favnoteEl = data.querySelector('textarea[name="favnote"]'); var favnote; if (favnoteEl) { favnote = favnoteEl.value; } else { favnote = false; } dlog("Favnotes successfully found"); cb(favnoteEl.value); // Fire callback function } else { dlog("XHR failed; notes not found"); return false; } }; xhr.timeout = function() { dlog("XHR timed out; notes not found"); return false; }; } // Update the locally stored favourite labels function updateFavouriteLabels() { dlog("Updating favourite labels"); var favs = document.querySelectorAll('div[style="height:25px; cursor:pointer"]'); for (var i=0; i<favs.length; i++) { var label = favs[i].children[2].textContent; localStorage.setItem(`EHGQF-fav${i}`, label); dlog(`Successfully set 'EHGQF-fav${i} to ${label}`); } } // Update the current/actual Favourite Category of the current Gallery function updateCurrentFav(favID) { dlog('Updating current fav'); var el; if (favID == 'favdel') { el = ` <div style="float:left"> <a onclick="return false" href="#" id="favoritelink"><img src="http://ehgt.org/g/mr.gif"> Add to Favorites</a> <div class="hotkey-hint">-</div> </div> `; } else { // Fetch the Labels of the 10 Fav items var favLabels = []; for (i=0; i<10; i++) { var label = localStorage.getItem(`EHGQF-fav${i}`); if ( !label ) label = `Favorites ${i}`; favLabels.push(label); } // Calculate bg offset var offset = 2 + (favID*19); // Build el = ` <div id="fav" style="float:left; cursor:pointer"> <div title="Read Later" style="background-image:url(http://ehgt.org/g/fav.png); background-position:0px -${offset}px;" class="i"></div> </div> <div style="float:left"> <a onclick="return false" href="#" id="favoritelink">${favLabels[favID]}</a> </div> `; } document.getElementById('gdf').innerHTML = el; } // Update favnote icon status function updateFavnoteIcon(status) { dlog(`Updating favnote icon to ${status}`); var favnoteEl = document.querySelector('#gdf > .favnote'); // Clear all classes but .favnote favnoteEl.className = 'favnote'; // Add status favnoteEl.classList.add(status); } // Inject Stylesheet function injectStylesheet() { dlog("Injecting stylesheet"); var stylesheetEl = document.createElement('style'); stylesheetEl.innerHTML = stylesheet; document.body.appendChild(stylesheetEl); } // Build and inject favnote UI; this needs to be separated because it's asynchronous function injectFavnoteElements() { dlog("Injecting Favnote UI elements"); // Fetch the FavID of the current gallery var curFavID = getCurrentFavID(); // Fetch favnotes if current gallery was already in a fav category if ( curFavID != 10 ) { fetchFavouriteNotes(function(favnote){ // Determine icon type var favnoteStatus = ''; if ( favnote === false ) favnoteStatus = 'exclamation'; if ( favnote === "" ) favnoteStatus = 'plus'; // Build elements for Favnotes var favnoteEl = ` <div class='favnote ${favnoteStatus}'></div> <div class="editor"> <input type="text" size="${config.editor_size}" class="stdinput" value="${favnote}"> </div> `; // Inject var gdf = document.getElementById("gdf"); gdf.insertAdjacentHTML('beforeend', favnoteEl); // Add event listeners document.querySelector("#gdf > .favnote").addEventListener("click", favnoteClick); dlog("Successfully injected Favnote UI "); }); } } // Build and inject UI; also hook event listeners function injectQFElements() { var i; dlog("Injecting Quick Fav UI elements"); // Fetch the FavID of the current gallery var curFavID = getCurrentFavID(); // Fetch the Labels of the 10 Fav items var favLabels = []; for (i=0; i<10; i++) { var label = localStorage.getItem(`EHGQF-fav${i}`); if ( !label ) label = `Favorites ${i+1}`; favLabels.push(label); } // Build fav item elements var favEl = []; for (i=0; i<10; i++) { var offset = 2 + (i*19); var el = ` <div qfid='${i}' class='fav'> <div class="i" style="background-image:url(http://ehgt.org/g/fav.png); background-position:0px -${offset}px;"></div> <a id="favoritelink" href="#">${favLabels[i]}</a> <div class="hotkey-hint">${i}</div> </div> `; favEl.push(el); } // Add the `remove favorites` fav item favEl.push(` <div qfid='favdel' class='fav'> <a id="favoritelink" href="#">Remove from Favorites</a> </div> `); // Build top list var qfTopElContent = ""; for (i=0; i<curFavID; i++) { qfTopElContent += favEl[i]; } var qfTopEl = `<div class='qf-top'>${qfTopElContent}</div>`; // Build bottom list var qfBotElContent = ""; for (i=curFavID+1; i<favEl.length; i++) { qfBotElContent += favEl[i]; } var qfBotEl = `<div class='qf-bot'>${qfBotElContent}</div>`; // Inject Elements! Finally var gdf = document.getElementById("gdf"); gdf.insertAdjacentHTML('beforeend', qfTopEl); gdf.insertAdjacentHTML('beforeend', qfBotEl); // Add Event Listeners var favDOMEl = document.querySelectorAll("#gdf .fav"); for(i=0; i<favDOMEl.length; i++) { favDOMEl[i].addEventListener("click", quickFavourite); } // Disable `#gdf` click event; move it to its child element; gdf.children[0].onclick = gdf.onclick; gdf.children[1].onclick = gdf.onclick; gdf.onclick = ""; dlog("UI Injection successful!"); } // Mark gallery as favourite function quickFavourite(id) { dlog("quickFavourite() triggered!"); // Gather and build things var favnote = document.querySelector('.favnote + .editor > input').value; var favID; try { favID = this.attributes.qfid.value; } catch(e) { favID = id; } var galID = location.pathname.match(/^\/\w\/(\d+)\//)[1]; var token = location.pathname.match(/\/(\w+)\/$/)[1]; var prot = location.protocol; var host = location.host; var url = `${prot}//${host}/gallerypopups.php?gid=${galID}&t=${token}&act=addfav`; var dat = `apply=Add to Favorites&favcat=${favID}&favnote=${favnote}&update=1`; // Prepare to send XHR var xhr = new XMLHttpRequest(); xhr.open("POST", url, true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); xhr.timeout = config.timeout; // Remove Quick Favourite Elements to prevent sending multiple XHR document.querySelector('.qf-top').remove(); document.querySelector('.qf-bot').remove(); document.querySelector('.favnote').remove(); document.querySelector('.editor').remove(); // Send XHR xhr.send(dat); // Update UI if request was successful xhr.onload = function() { if (xhr.status == 200) { updateCurrentFav(favID); // Update #gdf } else { dlog("Error occurred! Favorite was not updated!"); alert("Error occurred! Favorite was not updated!"); } injectQFElements(); // Reinject Quick Favourite UI injectFavnoteElements(); // and Favnote UI disableHotkeys(); dlog("quickFavourite() done!"); // Done! }; // Throw error if timeout occurred xhr.ontimeout = function(e) { dlog("Timeout occurred! Favorite was not updated!"); alert("Timeout occurred! Favorite was not updated!"); injectQFElements(); dlog("quickFavourite() timed out!"); }; } // What happens when favnote icon is clicked function favnoteClick() { var favnoteEl = this; var editorEl = document.querySelector('#gdf > .favnote + .editor'); var inputEl = document.querySelector('#gdf > .favnote + .editor > input'); // Determine mode var mode; if ( favnoteEl.classList.length === 1 ) mode = 'show'; else if ( favnoteEl.classList.contains('arrow') ) mode = 'save'; else if ( favnoteEl.classList.contains('exclamation') ) mode = 'reload'; else mode = 'edit'; // Behave accordingly switch(mode) { case 'show': updateFavnoteIcon('pencil'); // marks the next action to edit editorEl.classList.add('show'); inputEl.classList.add('notinput'); break; case 'edit': updateFavnoteIcon('arrow'); // marks the next action to save editorEl.classList.add('show'); inputEl.classList.remove('notinput'); break; case 'save': var favID = getCurrentFavID(); quickFavourite(favID); break; case 'reload': // an error occurred, attempt to reload favnotes document.querySelector('.favnote').remove(); document.querySelector('.editor').remove(); injectFavnoteElements(); break; default: dlog("What is happening?"); alert("A really strange error occurred. This part of code should be reached."); return; } } // Adds keypress event listener function injectHotkeyListener() { document.addEventListener('keypress', hotkeyHandler); dlog("Listening to keypress events now"); } // Processes keypresses function hotkeyHandler(e) { let key = e.which; let char = String.fromCharCode(key); if (hotkeyInit) { if (e.keyCode == 27) { return; } // 0-9 and "-" let favID; switch(char) { case("0"): favID = 0; break; case("1"): favID = 1; break; case("2"): favID = 2; break; case("3"): favID = 3; break; case("4"): favID = 4; break; case("5"): favID = 5; break; case("6"): favID = 6; break; case("7"): favID = 7; break; case("8"): favID = 8; break; case("9"): favID = 9; break; case("-"): favID = 'favdel'; break; default: disableHotkeys(); break; } if (favID) quickFavourite(favID); } else { if (char == "F") enableHotkeys(); } } function enableHotkeys() { hotkeyInit = true; if(config.cheatsheet) showCheatSheet(); dlog("Entering active hotkey favouriting mode"); } function disableHotkeys() { if(config.cheatsheet) hideCheatSheet(); hotkeyInit = false; dlog("Quitting active hotkey favouriting mode"); } function showCheatSheet() { dlog("Showing Cheat Sheet"); document.getElementById("gdf").classList.add("hover"); } function hideCheatSheet() { dlog("Hiding Cheat Sheet"); document.getElementById("gdf").classList.remove("hover"); } // Main/init function init() { if ( isFavouritePopupPage() ) { // We are in favourite popup page; update labels dlog("We are in favourite popup page"); updateFavouriteLabels(); } else { // We are in gallery page; inject quick favourite ui dlog("We are in Gallery page"); injectStylesheet(); injectQFElements(); injectFavnoteElements(); if (config.hotkeys) injectHotkeyListener(); } dlog("Initialization finished!"); } init();
更改后文本
打开文件
// ==UserScript== // @name EH Gallery Quick Favourite // @author FabulousCupcake // @namespace http://fabulous.cupcake.jp.net/ // @version v2.2.0 // @description Upgrades the gallery favourite button to allow quick favouriting of a gallery. // @include /^https?://(ex|(?:g\.)?e-)hentai\.org/g/\d+?/\w{10}/?/ // @include /^https?://(ex|(?:g\.)?e-)hentai\.org\/gallerypopups\.php\?.+&act=addfav/ // @grant none // ==/UserScript== /* ====================================== *\ Hotkey Map ---- Shift+F : Initiate Favouriting Mode [0-9] : Favourite 0-9 - : Remove Favourite ---- Pressing any other key during act- ive favouriting mode will exit the active favving mode. \* ====================================== */ // Config const config = { "debug": false, "editor_size": 60, // Width of the favnotes input element in not-px unit "hotkeys": true, // Enable hotkeys "cheatsheet": true // Show cheatsheet after pressing Shift+F? }; // Colors var geh = { "border" : "#5C0D12", "bg" : "#E3E0D1", "bg_light" : "#F8F6EE", }; var exh = { "border" : "#000000", "bg" : "#4F535B", "bg_light" : "#5F636B", }; var color; var hotkeyInit = false; // Are we on fjords? color = (location.host.substr(0,2) == "ex" ) ? color = exh : color = geh; // Stylesheet var stylesheet =` #gdf { margin: 6px 0 !important; padding: 10px 5px !important; width: 160px !important; height: 18px; position: relative; border: 1px dashed ${color.border}; left: -2px !important; } #gdf > div:nth-child(1), #gdf > div:nth-child(2), #gdf > div:nth-child(3) { display: inline !important; float: none !important; } #gdf > div:nth-child(2) > a { position: relative; top: -1px; line-height: 21px; } #gdf > #fav { padding-left: 5px; } #gdf > #fav > * { float: none !important; display: inline-block !important; margin: 0 !important; position: relative; top: 2px; } #gdf div.i { display: inline-block; margin: 0 !important; } #gdf a:hover { color: inherit !important; } .qf-top, .qf-bot { background: ${color.bg_light} !important; width: inherit; padding: 0 5px; position: absolute; left: -1px; visibility: hidden; border: 1px solid ${color.border}; } .qf-top { border-bottom: none; padding-top: 5px; bottom: 33px; } .qf-bot { border-top: none; padding-bottom: 5px; top: 33px; } #gdf .fav { box-sizing: border-box; cursor: pointer; padding: 5px; text-align: left; width: 100%; } #gdf .fav:hover { background: ${color.bg}; } #gdf:hover, #gdf.hover { border: 1px solid ${color.border}; } #gdf:hover > .qf-top, #gdf:hover > .qf-bot, #gdf.hover > .qf-top, #gdf.hover > .qf-bot { visibility: visible; } #gdf > .favnote { float: right !important; cursor: pointer; width: 16px; height: 16px; margin-right: 5px; position: relative; top: 1px; z-index: 20; opacity: 0.5; } #gdf > .favnote:hover { opacity: 1; } #gdf > .favnote:after { opacity: 0; } #gdf > .favnote:hover:after { display: block; padding: 0 5px; height: 20px; box-shadow: 0 1px 4px rgba(0,0,0,0.4); background: #f4f4f4; color: #333; font-weight: 400; font-size: 11px; line-height: 20px; position: absolute; top: -20px; left: 0px; transition: opacity 300ms cubic-bezier(1, -1, 1, -1); opacity: 1 } /* ========================================= *\ * Fugue Icons v3.5.6 by Yusuke Kamiyamane * * http://p.yusukekamiyamane.com/ * \* ========================================= */ #gdf > .favnote { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABQ0lEQVR4AcWONZoVURBGTxXusgrcIcMhw3dCjC/hxewB9wR3SXAYJGKS5zLW91bBK9wd/u6+2ud8P/89AnDjsOwBZvBjKS1a7xd4k+EAZsyav2zvFkst3A08Y1aQUz85D2C5AKC39ymdyhG9dlBkyUY/D6BvBIINYkUtvlw0sNTG8iCpSAwNFQwMDMS3eO2pLWZsvbJfln3YQEARkTdOi3nYsOG8TUpDNJtNzpzYDizZXHlxbQqwMv7IGRVRVBUz+6pk+vSFmGVGjx7N3XStCfCRQES+J4kmb5l3gpRRQhDQdyX6ah3Mxw0Euh/fkYRg1OcNBMWRcHxPosPHfNIgoUgXFtz5rkR1RDDvBH39PhKdiIwAcccxcCPWMVvA7hk3Q3RkMG8FU2/d4Vm7tHk0P5FHz3nWZQUYA0wI2c8lAS1+Ny8BF2m6Eor51N8AAAAASUVORK5CYII='); } #gdf > .favnote.plus { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABl0lEQVR4AcWOA4xeQRRGz0xtM6gd1DbCmjFquw3qWGVUx6lt27Ztt+vdN3OnndWPddTv4frk479LAVzfp5YATcmfVrbu585HAK7uUTtadF03WEwszgk4i0iANYlYm4TYAIBPn14S/2P/TmBF2wHuHIAGEEEhyUjwy3/Y4A9i4hCbjAkMKSkBSUlJ+K9Nn6ODRZhxeZfqClA4E4BGKYWPIPhYqFBhMmRMCjExMZw+PB9oO+jHx6sVgB6FAaxFK6XRWiMiOUKaNGmFiKV48eI8MFdjACIASqk8Id5Jxk0mwPgiFaAByROi/+X+BkCT6UDhvzAnEbWPM15fpveTw8x6cx0bDvA0hQZyh9z6/Y3WHftx8/fXKAcGTbqD7CBT7p+m06VtYBx/7B+UgbGubHvWV1yjADav5MyIUbu6IjHgHA7BOfG5j7Q7soqy3RsRrVM7T95QQMW5Y1jWsDZNyEEbi5So81oVKglQcUSLUj+33IpPcSR9f+n2A5QAqgI18/wWl7pT81Uz52P6TQkKpClF1zChyHUfSddf7UXJLEn3VbsAAAAASUVORK5CYII='); } #gdf > .favnote.arrow { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABnUlEQVR4Ac2QA6weURCFt7bduHZc27YV1bZt+9m2bdu2bRvn7Tz8ZthJvsXdPd+ducz/UeF2/V6zmMnIaiFBqE0/i7YqdbSU/URz6Xc0l3xBY9F71OU9Q3X2PVRm3ASR4L8H9C/LGj5BsFU/y7YKBTQVvkBjwTM05D9Ffd5j1GTfR3naLRQnXUFhwkVEuG8BGt1A/7Os5QgCLfpZtVUoobnopUSJl+UyDub/+nlxBH6m/WzaK1XQWvKaJFI7oXEowxF4G/Wz66hSQ1vpG5kkJKAMR+Cu38+ho1oD7WXvZJLQwVKGI3DR6efUWaOJjvL3UiUfnF1hF2YAynAEDpr9XFCjzQo+SJWc0Q/DWYMIvFE9HccR2Kr2c0OtDjorPgpJXlrY4JiqD4GjhIo3lAqAjV9saxa/jz7NUBn/ZnxQbwWSUCfd41Srgw527y83/MkDriQAZ2K43E0GZj72C6f8+AfnGW3190yIKHbcu1O65IZSPS/LA4B51zTKx+14dpEEw1gms0yXhVEn9WKIkQf+nO/NyleDD6irsJzue+8CGCvzmWahQigAAAAASUVORK5CYII='); } #gdf > .favnote.pencil { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABwElEQVR4Ac2QA4yYMQCF23nRfEMwe4sz27Zt297Ztm3btm3btt/+XnJmvJfU/b6C/B+JdKB8XLGYYNlFhibcjlp11GiirUIGreVSaC0TR3OJEBoKfqE29xOqs96ClaTA02B7ubJ7kCDUhlp3VCmhpfgPmot+oanwJxoLvqMu9zMqM96hNOUFipOeIsrzMNDsAbafK3v6BMFW1KajSgWtJX/HlPhYb+0rlorUp08QYE7tOqvV0F7GxyTj3oQ9hzF9Al8T6tBVo4GOcv4JSUqtriJlAy0NpnQfYfE0pE5dtVrorBAcV5IS+gqu4hcBXl7YUepHWNz0qEt3nTa6KoXGlBTF34KF3kO0tLTg64nZOTqEHCEsTtrUDXW6nEB4VElJ4h0EWq/m+t8hLXwZCrzTgvv+wF6deqBeD91VIiNKypLvI8hmDYNhpboM6eEvwZg+gakc8UOjDZiE3aTnObWaYB9bkf4OwbabGQwb9TXIinyD9kplMKaXn/vlMdHVFCJhQ4u2IImzUKC1DFb+S+tVeElq7xpjGMsVMpMrPFxZMrQIPKRSaEyD7Hca9PAiuTBknaeHHSd4dpZafL1Ld4+24R9mFfDtXW/67AAAAABJRU5ErkJggg=='); } #gdf > .favnote.exclamation { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAB5ElEQVR4AcWQA4yfMQBHXzvbtm3b4RzNXow5mIPZWzTbtm3btre/1a/dXXN2uF9St6+v5b9HANw8IKYDNclYFjfuZi4mAlzfJ3Y1aLuit1YejNFgHLSO4KgAjhNEOxEAvnx5je/Xwd3AoqY9zAUACaA1Ah1CR/7Y4kRcaOVFOyFURBEORwgGg7Y06XK8t9aMvrpHtAXIHAdAIoSIYWrbZspkl22UCuN2uzl7dBLQtNevz9cLAB3sDsdBCiGRUqK1ThVSo0YjtHbInj07j9R1N9idcQBrIKVto0pcayEB33P+fD9J0PuC2DNxT1DRA3vA3pzUxPaDvs+UrT2eD48W233RZ5IYCGxJwcTneUuOfLXIlj0/uQrUIhT4FmcgYw2E7aYEAdfvF+QtXJ++Q7aTt2AtXH9eRgMyEWegkMQYJIV4XO/IlLUIRrnYsWMHfs9nNNkRgkJxf+APmKzIvIgsIIzBoMFoRFT5EfVxeYpW4fOf6xw6OJ4fwRtkypEVbSgxsJe9koITRrKganlqkCTZsoncJUsXKFupQf3cjnJRqdYtXj1qBAhe3Xv6bdUm32AB5ADyWJskWTlTLGzVrmKngkWyFsIYchfqhffXHgB+//T+vH/r0yFBGlk/l2Va05BUIiW3/wHmcuCUyEztWwAAAABJRU5ErkJggg=='); } #gdf > .favnote:after { width: 70px; content: "See your note"; } #gdf > .favnote.plus:after { width: 55px; content: "Add a note"; } #gdf > .favnote.arrow:after { width: 70px; content: "Save the note"; } #gdf > .favnote.pencil:after { width: 70px; content: "Edit your note"; } #gdf > .favnote.exclamation:after { width: 300px; height: 60px !important; white-space: normal; content: "Note failed to load. Click to retry. WARNING: Changing favourite category while the note is not loaded will remove existing notes!"; } #gdf > .favnote + .editor { position: absolute; height: 18px; background: ${color.bg_light} !important; padding: 10px; top: -1px; left: 132px; z-index: 10; border: 1px solid ${color.border}; visibility: hidden; } #gdf > .favnote + .editor > input { margin: 0 0 0 30px; height: 12px; } #gdf > .favnote + .editor > input.notinput { border-color: transparent; background: none !important; color: inherit !important; cursor: default !important; outline: none !important; color: transparent !important; text-shadow: 0 0 0 ${color.border}; } #gdf > .favnote + .editor.show { visibility: visible; } #gdf.hover .fav { position: relative; } #gdf .hotkey-hint { position: absolute; top: 4px; right: 0; box-sizing: border-box; padding: 0 1px 0 2px; border: 1px solid #888; border-radius: 2px; background: #eee; color: #666 !important; font-family: monospace; font-size: 13px; box-shadow: -3px 0 2px 2px ${color.bg_light}; visibility: hidden; } #gdf.hover .fav:hover .hotkey-hint { box-shadow: -3px 0 2px 2px ${color.bg}; } #gdf.hover .hotkey-hint { visibility: visible; } `; /* ========================================================================= *\ * * UTILITY FUNCTIONS \* ========================================================================= */ // Debug msg function dlog(msg) { if ( config.debug ) { console.log(`"EHGQF: ${msg}`); } } // Get the actual/current favourite category of the current gallery function getPageFavId() { let idElement = document.querySelector("#fav .i"); if ( !idElement ) return 10; return (idElement.style.backgroundPositionY.match(/\d+/)[0] - 2)/19; } /* ========================================================================= *\ * * UI INJECTIONS \* ========================================================================= */ // Inject CSS function injectStylesheet() { dlog("Injecting stylesheet"); var stylesheetEl = document.createElement("style"); stylesheetEl.innerHTML = stylesheet; document.body.appendChild(stylesheetEl); } // Build and inject FavNote UI function injectFavnoteElements() { dlog("Injecting Favnote UI elements"); // Fetch the FavID of the current gallery var curFavID = getPageFavId(); // Fetch favnotes if current gallery was already in a fav category if ( curFavID != 10 ) { fetchFavouriteNotes( favnote => { // Determine icon type var favnoteStatus = ""; if ( favnote === false ) favnoteStatus = "exclamation"; if ( favnote === "" ) favnoteStatus = "plus"; // Build elements for Favnotes var favnoteEl = ` <div class='favnote ${favnoteStatus}'></div> <div class="editor"> <input type="text" size="${config.editor_size}" class="stdinput" value="${favnote}"> </div> `; // Inject var gdf = document.getElementById("gdf"); gdf.insertAdjacentHTML("beforeend", favnoteEl); // Add event listeners document.querySelector("#gdf > .favnote").addEventListener("click", favnoteClick); dlog("Successfully injected Favnote UI"); return; }); } dlog("FavID = 10: No notes to inject!"); } // Build & Inject QF UI function injectQFElements() { var i; dlog("Injecting Quick Fav UI elements"); // Fetch the FavID of the current gallery var curFavID = getPageFavId(); // Fetch the Labels of the 10 Fav items var favLabels = []; for (i=0; i<10; i++) { var label = localStorage.getItem(`EHGQF-fav${i}`); if ( !label ) label = `Favorites ${i+1}`; favLabels.push(label); } // Build fav item elements var favEl = []; for (i=0; i<10; i++) { var offset = 2 + (i*19); var el = ` <div qfid='${i}' class='fav'> <div class="i" style="background-image:url(https://ehgt.org/g/fav.png); background-position:0px -${offset}px;"></div> <a id="favoritelink" href="#">${favLabels[i]}</a> <div class="hotkey-hint">${i}</div> </div> `; favEl.push(el); } // Add the `remove favorites` fav item favEl.push(` <div qfid='favdel' class='fav'> <a id="favoritelink" href="#">Remove from Favorites</a> <div class="hotkey-hint">-</div> </div> `); // Build top list var qfTopElContent = ""; for (i=0; i<curFavID; i++) { qfTopElContent += favEl[i]; } var qfTopEl = `<div class='qf-top'>${qfTopElContent}</div>`; // Build bottom list var qfBotElContent = ""; for (i=curFavID+1; i<favEl.length; i++) { qfBotElContent += favEl[i]; } var qfBotEl = `<div class='qf-bot'>${qfBotElContent}</div>`; // Inject Elements! Finally var gdf = document.getElementById("gdf"); gdf.insertAdjacentHTML("beforeend", qfTopEl); gdf.insertAdjacentHTML("beforeend", qfBotEl); // Add Event Listeners var favDOMEl = document.querySelectorAll("#gdf .fav"); for(i=0; i<favDOMEl.length; i++) { favDOMEl[i].addEventListener("click", quickFavourite); } // Disable `#gdf` click event; move it to its child element; gdf.children[0].onclick = gdf.onclick; gdf.children[1].onclick = gdf.onclick; gdf.onclick = ""; dlog("UI Injection successful!"); } /* ========================================================================= *\ * * QUICK FAVOURITE \* ========================================================================= */ // Send Favouriting XHR request to EH server function quickFavourite(id) { dlog("quickFavourite() triggered!"); // Gather and build things let favnoteEl = document.querySelector(".favnote + .editor > input"); let favnote = (favnoteEl) ? favnoteEl.value : ""; let favID; try { favID = this.attributes.qfid.value; } catch(e) { favID = id; } let galID = location.pathname.match(/^\/\w\/(\d+)\//)[1]; let token = location.pathname.match(/\/(\w+)\/$/)[1]; let prot = location.protocol; let host = location.host; let url = `${prot}//${host}/gallerypopups.php?gid=${galID}&t=${token}&act=addfav`; let dat = `apply=Add to Favorites&favcat=${favID}&favnote=${favnote}&update=1`; // Prepare to send XHR let xhr = new XMLHttpRequest(); xhr.open("POST", url, true); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); // Remove Quick Favourite Elements to prevent sending multiple XHR document.querySelector(".qf-top").remove(); document.querySelector(".qf-bot").remove(); if ( favnoteEl ) document.querySelector(".favnote").remove(); if ( favnoteEl ) document.querySelector(".editor").remove(); // Send XHR xhr.send(dat); // Update UI if request was successful xhr.onload = function() { if (xhr.status == 200) { updateCurrentFav(favID); // Update #gdf } else { dlog("Error occurred! Favorite was not updated!"); alert("Error occurred! Favorite was not updated!"); } injectQFElements(); // Reinject Quick Favourite UI injectFavnoteElements(); // and Favnote UI disableHotkeys(); dlog("quickFavourite() done!"); // Done! }; } // Update the current/actual Favourite Category of the current Gallery function updateCurrentFav(favID) { dlog("Updating current fav with favID "+favID); // If id is not specified, refresh if ( typeof favID == "undefined" ) { favID = getPageFavId(); dlog("FavID set to " + favID); } var el; if (favID == "favdel" || favID === 10) { el = ` <div style="float:left"> <a onclick="return false" href="#" id="favoritelink"><img src="https://ehgt.org/g/mr.gif"> Add to Favorites</a> <div class="hotkey-hint"></div> </div> `; } else { // Fetch the Labels of the 10 Fav items var favLabels = []; for (let i=0; i<10; i++) { var label = localStorage.getItem(`EHGQF-fav${i}`); if ( !label ) label = `Favorites ${i}`; favLabels.push(label); } // Calculate bg offset var offset = 2 + (favID*19); // Build el = ` <div id="fav" style="float:left; cursor:pointer"> <div title="Read Later" style="background-image:url(https://ehgt.org/g/fav.png); background-position:0px -${offset}px;" class="i"></div> </div> <div style="float:left"> <a onclick="return false" href="#" id="favoritelink">${favLabels[favID]}</a> </div> `; } document.getElementById("gdf").innerHTML = el; } /* ========================================================================= *\ * * FAVOURITE NOTES \* ========================================================================= */ // Get Favourite Notes remotely from the popup function fetchFavouriteNotes(cb) { dlog("Beginning to check favnotes"); // Send XHR to Favourite Page var galID = location.pathname.match(/^\/\w\/(\d+)\//)[1]; var token = location.pathname.match(/\/(\w+)\/$/)[1]; var prot = location.protocol; var host = location.host; var url = `${prot}//${host}/gallerypopups.php?gid=${galID}&t=${token}&act=addfav`; var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.timeout = config.timeout; xhr.responseType = "document"; xhr.send(); // And grab the favnotes xhr.onload = function() { if ( xhr.status == 200 ) { // grab it! var data = xhr.response; var favnoteEl = data.querySelector("textarea[name='favnote']"); dlog("Favnotes successfully found"); cb(favnoteEl.value); // Fire callback function } else { dlog("XHR failed; notes not found"); return false; } }; xhr.timeout = function() { dlog("XHR timed out; notes not found"); return false; }; } // Update favnote icon status function updateFavnoteIcon(status) { dlog(`Updating favnote icon to ${status}`); var favnoteEl = document.querySelector("#gdf > .favnote"); // Clear all classes but .favnote favnoteEl.className = "favnote"; // Add status favnoteEl.classList.add(status); } // FavNote click event handler function favnoteClick() { var favnoteEl = this; var editorEl = document.querySelector("#gdf > .favnote + .editor"); var inputEl = document.querySelector("#gdf > .favnote + .editor > input"); // Determine mode var mode; if ( favnoteEl.classList.length === 1 ) mode = "show"; else if ( favnoteEl.classList.contains("arrow") ) mode = "save"; else if ( favnoteEl.classList.contains("exclamation") ) mode = "reload"; else mode = "edit"; // Behave accordingly switch(mode) { case "show": updateFavnoteIcon("pencil"); // marks the next action to edit editorEl.classList.add("show"); inputEl.classList.add("notinput"); break; case "edit": updateFavnoteIcon("arrow"); // marks the next action to save editorEl.classList.add("show"); inputEl.classList.remove("notinput"); break; case "save": var favID = getPageFavId(); quickFavourite(favID); break; case "reload": // an error occurred, attempt to reload favnotes document.querySelector(".favnote").remove(); document.querySelector(".editor").remove(); injectFavnoteElements(); break; default: dlog("What is happening?"); alert("A really strange error occurred. This part of code should be reached."); return; } } /* ========================================================================= *\ * * FAVOURITE HOTKEYS \* ========================================================================= */ // Adds keypress event listener function injectHotkeyListener() { document.addEventListener("keypress", hotkeyHandler); dlog("Listening to keypress events now"); } // Handles keypresses function hotkeyHandler(e) { let key = e.which; let char = String.fromCharCode(key); if (hotkeyInit) { if (e.keyCode == 27) { return; } // 0-9 and "-" let favID; switch(char) { case("0"): favID = 0; break; case("1"): favID = 1; break; case("2"): favID = 2; break; case("3"): favID = 3; break; case("4"): favID = 4; break; case("5"): favID = 5; break; case("6"): favID = 6; break; case("7"): favID = 7; break; case("8"): favID = 8; break; case("9"): favID = 9; break; case("-"): favID = "favdel"; break; default: disableHotkeys(); break; } if (typeof favID != "undefined") quickFavourite(favID); } else { if (char == "F") enableHotkeys(); } } function enableHotkeys() { hotkeyInit = true; if(config.cheatsheet) showCheatSheet(); dlog("Entering active hotkey favouriting mode"); } function disableHotkeys() { if(config.cheatsheet) hideCheatSheet(); hotkeyInit = false; dlog("Quitting active hotkey favouriting mode"); } function showCheatSheet() { dlog("Showing Cheat Sheet"); document.getElementById("gdf").classList.add("hover"); } function hideCheatSheet() { dlog("Hiding Cheat Sheet"); document.getElementById("gdf").classList.remove("hover"); } /* ========================================================================= *\ * * CORE LOGICS \* ========================================================================= */ function checkSyncNecessity() { // >1w = stale let currentTime = new Date().getTime(); let lastSyncTime = localStorage.getItem("EHGQF-lastSyncTime"); let timeDelta = currentTime - lastSyncTime; if ( timeDelta > 1000*60*60*24*7 ) return true; // setup let x = localStorage.getItem("EHGQF-setup"); if (typeof x == "undefined") return true; // constant page check let labelId = getPageFavId(); if ( labelId == 10 ) return false; // can't check if page isn't favourited yet let pageLabel = document.querySelector("#favoritelink").textContent; let storedLabel = localStorage.getItem(`EHGQF-fav${labelId}`); if ( pageLabel != storedLabel ) return true; dlog("No reason found to sync favourite labels"); return false; } function syncFavouriteLabels() { dlog("Fetching fresh Favourite Labels!"); // Send XHR to Favourite Page var galID = location.pathname.match(/^\/\w\/(\d+)\//)[1]; var token = location.pathname.match(/\/(\w+)\/$/)[1]; var prot = location.protocol; var host = location.host; var url = `${prot}//${host}/gallerypopups.php?gid=${galID}&t=${token}&act=addfav`; var xhr = new XMLHttpRequest(); xhr.open("GET", url, true); xhr.responseType = "document"; xhr.send(); // And grab the favnotes xhr.onreadystatechange = function() { if ( xhr.readyState == 4 && xhr.status == 200 ) { let data = xhr.response; for(let i=0; i<=9; i++) { let label = data.querySelector(`div + div + div[onclick*='fav${i}']`).textContent; localStorage.setItem(`EHGQF-fav${i}`, label); } dlog("Favourite Labels Updated!"); let time = new Date().getTime(); localStorage.setItem("EHGQF-setup", 1); localStorage.setItem("EHGQF-lastSyncTime", time); updateCurrentFav(); injectQFElements(); } }; } function init() { dlog("Initialization start!"); if ( checkSyncNecessity() ) syncFavouriteLabels(); injectStylesheet(); injectQFElements(); injectFavnoteElements(); if (config.hotkeys) injectHotkeyListener(); dlog("Initialization finished!"); } init();
查找差异